-
Notifications
You must be signed in to change notification settings - Fork 35
Echo
Yizzuide edited this page Nov 3, 2020
·
3 revisions
Echo is a powerful tool for invoking third-party services and base on Spring RestTemplate, which unified parameter signature and response field processing.
Echo是一个调用第三方服务利器,基于Spring RestTemplate,实现了统一的参数签名与响应字段处理。
<dependency>
<groupId>com.github.yizzuide</groupId>
<artifactId>milkomeda-spring-boot-starter</artifactId>
<version>${milkomeda-last-version}</version>
</dependency>
@EnableEcho
@SpringBootApplication
public class MilkomedaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MilkomedaDemoApplication.class, args);
}
}
milkomeda:
# Only show log with dev environment, the `condition` is condition match object addition from framework.
# 仅在dev环境开启info日志, `condition`是框架附加的条件判别对象
show-log: ${condition.equals(${spring.application.name}, dev)}
echo:
read-timeout: 20s
The interface EchoResponseData
specifies the specification of 'code', 'msg' and 'data', if the fields are different, you need to adapt them.
EchoResponseData
接口定了规范的code
、msg
、data
,如果字段相同就需要适配一下。
@Data
public class SimpleEchoResponseData<T> implements EchoResponseData<T> {
private String code;
private String errorMsg;
private T data;
// If the getter for the parameter is inconsistent with the interface definition, you can do so.
// 如果参数的getter跟接口定义不一致,可以这样适配
@Override
public String getMsg() {
return errorMsg;
}
}
@Slf4j
@Component
public class SimpleEchoRequest extends EchoRequest {
// Must be override to return reponse data type
// 必须返回一个响应映射类型
@Override
protected <T> EchoResponseData<T> responseData() {
return new SimpleEchoResponseData<>();
}
// If request content type is application/x-www-form-urlencoded, add and override below.
// 如果使用application/x-www-form-urlencoded表单通讯方式,覆盖下面方法。
/*@Override
protected void appendHeaders(HttpHeaders headers) {
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
}*/
// Signature
@Override
protected void signParam(Map<String, Object> inParams, Map<String, Object> outParams) {
// If request content type is application/x-www-form-urlencoded, `outParams` type is LinkedMultiValueMap
// 如果使用application/x-www-form-urlencoded表单通讯方式,则outParams为LinkedMultiValueMap
/*if (outParams instanceof LinkedMultiValueMap) {
LinkedMultiValueMap multiValueMap = (LinkedMultiValueMap) outParams;
multiValueMap.add("appId", "1000");
multiValueMap.add("timestamp", "2019-09-21 17:12:00");
multiValueMap.add("version", "1.0");
// ...
}*/
// If request content type is application/json
// 使用json通信方式的添加方式
outParams.put("appId", "1000");
outParams.put("version", "1.0");
// Remove empty value
DataTypeConvertUtil.clearEmptyValue(inParams);
String bizContent = JSONUtil.serialize(inParams);
outParams.put("biz_data", bizContent);
// Convert map to form data, such as name=val&name2=val2...
String signStr = DataTypeConvertUtil.map2FormData(outParams, false);
log.info("sign str:{}", signStr);
String sign = EncryptUtil.sign(signStr, getPriKey(), EncryptUtil.SIGN_TYPE_RSA2);
outParams.put("sign", sign);
}
// Signature verification
// 验签
@Override
public Map<String, Object> verifyParam(Map<String, Object> inParams) {
String sign = (String) inParams.remove("sign");
String signStr = DataTypeConvertUtil.map2FormData(inParams, false);
log.info("sign str:{}", signStr);
boolean isVerified = EncryptUtil.verify(signStr, sign, getParPubKey(), EncryptUtil.SIGN_TYPE_RSA2);
if (!isVerified) {
log.error("verify fail,params:{}", inParams);
return null;
}
return inParams;
}
// This method for check reponse is ok
// 这个方法用于检测响应是否成功
@Override
protected void checkResponse(EchoResponseData responseData) throws EchoException {
if (!("200".equals(responseData.getCode()))) {
log.error("Response error with msg: {}, code:{}", responseData.getMsg(), responseData.getCode());
}
}
private String getParPubKey() {
return "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCa9bXW/GTqseFLWxBfnECbxaNcMTAGDojSnmwtUcPd9mwnevRguOIDbOxbSsIwDtN9bw3o16V5N+Y7iuluEHsrWhrhC9RQx6LA9h8nuTE6c1HSstgq7y+DSPvZrbou5zZnDbgP45M2LT2MXd3HaApq+Ocvg5gp11WhKRa4AgXerQIDAQAB";
}
private String getPriKey() {
return "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJr1tdb8ZOqx4UtbEF+cQJvFo1wxMAYOiNKebC1Rw932bCd69GC44gNs7FtKwjAO031vDejXpXk35juK6W4QeytaGuEL1FDHosD2Hye5MTpzUdKy2CrvL4NI+9mtui7nNmcNuA/jkzYtPYxd3cdoCmr45y+DmCnXVaEpFrgCBd6tAgMBAAECgYBuFRGZ6XFTnQw8uTN3iIwJXSzBCJxiIR8n6K1WwJhRbYbFwT4sHAtLfaym6gPrmgy6NhN+jvuZkpF3SSatLv4f3vwu3ToZcmi6A0LlVzFT7cMHBzMP/Ev09aa0N/j9+ykPlJH06ehkvwz/504GEDwLt2791MxWqtZJjuDNWloWQQJBAOaQ+jgUmjIkKX09/x0a8P13JezBP14UV5cZLvoRWW8XzTkfZx/rpC7irpijvcwBhi45kIg8JrIngYm5/QSkLDECQQCsDakrLtIJLenTSHmFi2KfI2EHYT0deFrK92+VDY15iE7gBQBvbiZiAKwjV33gcrtS6JTZWtxKeOAUUPTiUgc9AkEA1Gb+e6dPHZ3+sqfoWxG0rGuU/nRQQgUPY90JT8mn0BXnMxZg1CEqkR62pVtCv6svx2m0Yiy3oSuPxCcYlawAIQJAW5lORjJAGij6gsTkBagmkkjYoIAxdF4eIE7JdhZoCpr6OyQOjkSbZLOs8Yfj+Tm75zDyBiHshC2ERuyu40r+lQJBAJ+SImDYm9NLqo6hq1+FTI1apKyq8rsuQYL8IRsYAHmOGCNmHN1b/AFitHaptZXYOtiZyuEP8xP86Np8vrTUKSg=";
}
}
@Slf4j
@RestController
public class EchoController {
@Resource
private EchoRequest simpleEchoRequest;
// Mock a third-party service
// 模拟一个第三方平台开户接口
@RequestMapping("/echo/account/open")
public ResponseEntity<Map<String, Object>> openAccount(@RequestBody Map<String, Object> params) {
log.info("params:{}", params);
Map<String, Object> data = new HashMap<>();
// Signature verification
// 验签
Map<String, Object> map = simpleEchoRequest.verifyParam(params);
if (map == null) {
data.put("code", "403");
data.put("error_msg", "signature verification fail");
data.put("data", null);
} else {
data.put("code", "200");
data.put("error_msg", "");
data.put("data", new HashMap<String, Object>(){
private static final long serialVersionUID = -7494033976315538458L;
{
put("order_id", "12343243434324324");
}});
}
return ResponseEntity.ok(data);
}
// Test to invoke above service
// 请求上面第三方平台开户接口
@RequestMapping("/test/echo/account/open")
public String requestOpenAccount() {
Map<String, Object> reqParams = new HashMap<>();
reqParams.put("uid", "1101");
reqParams.put("name", "yiz");
reqParams.put("id_no", "14324357894594483");
EchoResponseData<Map<String, Object>> responseData = simpleEchoRequest.fetch(HttpMethod.POST, "http://localhost:8080/echo/account/open", reqParams);
log.info("receive response data: {}", responseData);
return "OK";
}
}