銷售端作用:
用於與第三方交互的門戶網關,這裏進行安全控制,流量統計等,整合內部資源,對外提供相應的接口,完成產品的銷售管理
功能:
- 產品查詢
- 申購、贖回
- 對賬
接口文檔:
- 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