远程调用第三方系统的接口,都需要传sign签字字段,而此字段一般是用密钥和入参根据约定的算法生成的字符串。为了代码简洁快捷,所以通过注解的方式去实现。
首先定义一个注解
package com.yulisao.common;
import java.lang.annotation.*;
@Inherited // 子类也会继承这个注解
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AddSignAnnotation {
}
添加注解的实现类
package com.yulisao.common;
import com.yulisao.utils.SignUtils;
import com.yulisao.dto.TradeInfoDTO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AddSignInterceptor {
@Value("${spring.appid}")
private String appid;
@Value("${spring.secret}")
private String appSecret;
// 表明这个类的功能为谁而执行(已指明了详细的包路径)
@Pointcut("@within(com.yulisao.common.AddSignAnnotation)")
private void execute() {
}
// 功能具体实现逻辑
@Around("execute()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object[] paramValues = pjp.getArgs(); // 获取请求参数, get 和psot 请求都可以获取到
for (int i = 0; i < paramValues.length; i++) { // 遍历请求参数
if (paramValues[i] instanceof TradeInfoDTO) { // 若请求对象中包含TradeInfoDTO这个对象。为了复用性,建议新建一个base对象里面就只有sign这个字段,全部接口的入参对象都继承base对象。这样这里就不用写很多的 if instanceof 了
TradeInfoDTO reqBody = (TradeInfoDTO) paramValues[i]; // 取出请求参数
String sign = SignUtils.sign(reqBody); // 自行实现签名细节
reqBody.setSign(sign); // 给签名字段赋值
paramValues[i] = reqBody; // 处理完成返回
}
// 思考题:get请求,可以尝试在url上统一的拼接某个参数,实现方式略
}
return pjp.proceed(paramValues);
}
}
fegin调用demo
package com.yulisao.client;
import com.alibaba.fastjson.JSONObject;
import com.yulisao.common.AddSignAnnotation;
import com.yulisao.dto.TradeInfoDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "trande-service", url = "${spring.baseurl}") // 设定第三方接口的baseurl
@AddSignAnnotation // 添加此注解 发送请求之前会拦截,给请求参数做处理(添加签名字段到请求参数中)
public interface TradeClient {
/**
* 发起交易
* @param param
* @return
*/
@PostMapping("/trade/pay")
JSONObject pay(@RequestBody TradeInfoDTO param);
/**
* 查询用户交易记录
* @param userId
* @param userName
* @return
*/
@GetMapping("/query/tradeList")
JSONObject tradeList(@RequestParam(name = "userId")String userId, @RequestParam(name = "userName")String userName);
}
请求对象dto
package com.yulisao.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class TradeInfoDTO {
private Long userId;
private BigDecimal amount;
// 这个公共字段 建议放一个专门的base对象,然后 TradeInfoDTO extends base对象
private String sign;
}
题外话,若对方接口要求请求头里面有某个固定的参数,比如token,实现方法可参考如下
先创建一个请求拦截器
package com.yulisao.common;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@Configuration
public class AddToken {
//@Value("${client.tokenid}")
//private String tokenId;
@Bean
public RequestInterceptor headerInterceptor() {
return new RequestInterceptor(){
@Override
public void apply(RequestTemplate template) {
JSONObject params = new JSONObject();
params.put("token", "1234567890"); // token的获取自行实现
List<String> authorizationList = Lists.newArrayList(params.toJSONString());
List<String> contentTypeList = Lists.newArrayList("application/x-www-form-urlencoded;charset=utf-8");
Map<String, Collection<String>> headers = ImmutableMap.of("Authorization", authorizationList,"Content-Type", contentTypeList); // header头里面的参数名称是Authorization
template.headers(headers);
}
};
}
}
fegin接口调用此拦截
@FeignClient(name = "trande-service", url = "${spring.baseurl}", configuration = AddToken.class) // 通过拦截器统一设置请求头
@AddSignAnnotation
public interface TradeClient {
}