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

     

 

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