Spring boot理财系统4 Jsonrpc

销售端作用:

用于与第三方交互的门户网关,这里进行安全控制,流量统计等,整合内部资源,对外提供相应的接口,完成产品的销售管理

功能:

  • 产品查询
  • 申购、赎回
  • 对账

接口文档:

  • swagger
  • swagger编写
  • 已有代码生成接口文档

主要步骤

  • 在api模块中定义产品相关的rpc请求服务和请求对象
  • 在manager中的rpc包下实现api模块中的服务类
  • 在manager中的configuration包下实现RpcConfiguration将rpc相关配置交给spring管理

常见错误:
在配置类中对应的配置内容未添加@Bean

application.yml中url的配置末尾要加/,Json

@JsonRpcService("rpc/products") //这里不能以/开始 例如 /products这是错误的(这里可以通过自己封装来配置)

序列化和反序列化问题

Cannot determine embedded database driver class for database type NONE

产品查询功能

使用jsonrpc实现系统内部之间的交互

使用jsonrpc4j框架来实现jsonrpc

引入依赖

产品相关rpc封装成一个类

package com.qwl.api.domain;

import org.springframework.data.domain.Pageable;
import java.math.BigDecimal;
import java.util.List;

/**
 * 产品相关rpc请求对象
 */
public class ProductRpcReq {
    private List<String> idList;
    private BigDecimal minRewardRate;
    private BigDecimal maxRewardRate;
    private List<String> statusList;
    private Pageable pageable;

    //get set toString
}

产品相关rpc服务

import com.googlecode.jsonrpc4j.JsonRpcService;
import com.qwl.api.domain.ProductRpcReq;
import com.qwl.entity.Product;
import org.springframework.data.domain.Page;

@JsonRpcService("rpc/products")
public interface ProductRpc {
    //查询多个产品
    Page<Product> query(ProductRpcReq req);

    //查询单个产品
    Product findOne(String id);

}

rpc管理端

在管理端添加依赖

    compile project(":api")

rpc服务实现类

package com.qwl.manager.rpc;

import com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImpl;
import com.qwl.api.ProductRpc;
import com.qwl.api.domain.ProductRpcReq;
import com.qwl.entity.Product;
import com.qwl.manager.service.ProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

@AutoJsonRpcServiceImpl
@Service
public class ProductRpcImpl implements ProductRpc {
    private static Logger LOG = LoggerFactory.getLogger(ProductRpcReq.class);

    @Autowired
    private ProductService productService;
    @Override
    public Page<Product> query(ProductRpcReq req) {
        LOG.info("查询多个产品,请求{}",req);
        Page<Product> result = productService.query(req.getIdList(),req.getMinRewardRate(),
                req.getMaxRewardRate(),req.getStatusList(),req.getPageable());
        LOG.info("查询多个产品,结果{}",result);
        return result;
    }

    @Override
    public Product findOne(String id) {
        LOG.info("查询产品详情,请求{}",id);
        Product result = productService.findOne(id);
        LOG.info("查询产品详情,结果{}",result);
        return result;
    }
}

rpc相关配置

 

rpc客户端

添加依赖并新建启动类

package com.qwl.seller.Service;

import com.qwl.api.ProductRpc;
import com.qwl.api.domain.ProductRpcReq;
import com.qwl.entity.Product;
import com.qwl.entity.enums.ProductStatus;
import com.qwl.seller.configuration.RpcConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Service
public class ProductRpcService {

    @Autowired
    private ProductRpc productRpc;

    private static Logger LOG = LoggerFactory.getLogger(RpcConfiguration.class);
    //查询全部产品
    public List<Product> findAll(){
        ProductRpcReq req = new ProductRpcReq();
        List<String> status = new ArrayList<>();
        status.add(ProductStatus.IN_SELL.name());
        Pageable pageable = new PageRequest(0,1000,Sort.Direction.DESC,"rewardRate");
        req.setStatusList(status);

        LOG.info("rpc查询全部产品,请求{}",req);

        LOG.info("rpc查询全部产品,请求:{}",req);
        Page<Product> result = productRpc.query(req);
        LOG.info("rpc查询全部产品,结果:{}",result);
        return result.getContent();
    }
    
    @PostConstruct
    public void test(){
        findAll();
    }

    //查询单个产品
    public Product findOne(String id){
        LOG.info("rpc查询单个产品,请求:{}",id);
        Product result = productRpc.findOne(id);
        LOG.info("rpc查询单个产品,结果:{}",result);
        return result;
    }
    @PostConstruct
    public void init(){
        findOne("001");
    }
}

package com.qwl.seller.configuration;

import com.googlecode.jsonrpc4j.spring.AutoJsonRpcClientProxyCreator;
import com.qwl.api.ProductRpc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.net.MalformedURLException;
import java.net.URL;

@Configuration
@ComponentScan(basePackageClasses = {ProductRpc.class})
public class RpcConfiguration {
    private static Logger LOG = LoggerFactory.getLogger(RpcConfiguration.class);

    @Bean
    public AutoJsonRpcClientProxyCreator rpcClientProxyCreator(@Value("${rpc.manager.url}") String url){
        AutoJsonRpcClientProxyCreator creator = new AutoJsonRpcClientProxyCreator();
        try {
            creator.setBaseUrl(new URL(url));
        } catch (MalformedURLException e) {
            LOG.error("创建rpc服务地址错误",e);
        }

        creator.setScanPackage(ProductRpc.class.getPackage().getName());
        return creator;
    }
}

修改ProductRpcReq 

修改实现类

 

删除上面的

运行管理端和客户端

原理

先扫描带有@JsonRpcService注解的接口,创建一个代理对象对应的路径就是主地址加上项目配置的地址,实际调用的时候会通过ObjectMapper将参数信息装换为JSON字符串,通过http的形式传递到服务端。

先在application.yml中添加debug级别日志配置

logging:
  level:
    com.googlecode.jsonrpc4j: debug

在ProductRpcService中初始化一个加载即运行方法

@PostConstruct
public void init(){
	findOne("T001");
}

得出结果如下

根据我们配置的信息去扫描RPC的服务接口,然后去创建代理,执行的时候就是把我们的操作信息转化成json字符串的格式传递到服务端,然后服务端使用json字符串的形式返回来

客户端唯一的入口就是RpcConfiguration里面创建的代理类的创建对象AutoJsonRpcClientProxyCreator

客户端的实现

  • 扫描我们的包路径下面添加了JsonRpcService这个注解的接口
  • 创建一个代理对象,对应的路径就是基础地址+注解里面配置的地址
  • 通过objectMapper将参数信息转换成Json字符串
  • 通过http的形式传递到服务端

服务端的实现

服务端的唯一 入口AutoJsonRpcServiceImplExporter,实现了BeanFactoryPostProcessor这个接口,会自动调用postProcessBeanFactory方法,这是spring的实现原理

简化封装

在seller和manager模块中都有JsonRpcConfiguration,在我的代码中这两处都被注释了,因为后面进行简化封装,但是为了让读者能感受到变化我就没删掉

将两个模块中的JsonRpcConfiguration写在util(或者开一个jsonRpc的模块)的configuration/JsonRpcConfiguration中

private static Logger LOG = LoggerFactory.getLogger(JsonRpcConfiguration.class);

    @Bean
    public AutoJsonRpcServiceImplExporter rpcServiceImplExporter(){
        return new AutoJsonRpcServiceImplExporter();
    }

    @Bean
    @ConditionalOnProperty(value = {"rpc.client.url","rpc.client.basePackage"}) //当配置文件中有这两个属性时才需要导出客户端
    public AutoJsonRpcClientProxyCreator rpcClientProxyCreator(@Value("${rpc.client.url}") String url,
                                                               @Value("${rpc.client.basePackage}") String basePackage){
        AutoJsonRpcClientProxyCreator clientProxyCreator = new AutoJsonRpcClientProxyCreator();
        try {
            //配置基础url
            clientProxyCreator.setBaseUrl(new URL(url));
        } catch (MalformedURLException e) {
            LOG.error("创建rpc服务地址错误");
        }
        //让它扫描api下rpc服务的包
        clientProxyCreator.setScanPackage(basePackage);
        return clientProxyCreator;
    }
  • 然后把两个模块中的JsonRpcConfiguration删除

  • util的build.gradle

  • dependencies {
        compile libs.jsonrpc
    }

    api模块中加上对util模块的依赖

  • 在seller的application.yml中加上

  • rpc:
      client:
        url: http://localhost:8081/manager/ #结尾记得加上/,否则会报错
        basePackage: com.qwl.api

    在resources/META-INF/spring.factories下

  • org.springframework.boot.autoconfigure.EnableAutoConfiguration =com.qwl.util.configuration.JsonRpcConfiguration

     

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章