基于自定义注解的参数解析器
基于自定义注解的参数解析器
背景
在工作中,常会对接一些第三方应用,通常第三方会采用Rsa+Aes加密来通信,但是每个第三方的加密方式可能不一致。此时得好好规划一下实现方案了。因此我们采用注解+Spring自带了参数解析类,实现自己的参数解析器。
原理
通过HandlerMethodArgumentResolver实现自定义参数解析
实现
步骤1:创建注解,例如创建一个解析Aes加密的注解AesJson
import java.lang.annotation.*;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AesJson {
}
步骤2:创建加密参数实体类对象
传入的JSON数据格式为{“data”:“xxxxxxxxxx”}
import lombok.Data;
@Data
public class AesBaseParams {
private String data;
}
步骤3:新建AesArgumentResolver类实现HandlerMethodArgumentResolver
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* aes加密算法加密的入参,通过@AesJson注解自动解析
*/
public class AesArgumentResolver implements HandlerMethodArgumentResolver {
private static final Logger logger = LoggerFactory.getLogger(AesArgumentResolver.class);
/**
* 支持该注解的方法
* @param methodParameter
* @return
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(AesJson.class);
}
/**
* 解析aes加密入参
* @param methodParameter
* @param modelAndViewContainer
* @param nativeWebRequest
* @param webDataBinderFactory
* @return
* @throws Exception
*/
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest httpServletRequest = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
String para = getAllParamJson(httpServletRequest);
AesBaseParams aesBaseParams = JSON.parseObject(para, AesBaseParams.class);
Object obj = null;
if(Objects.nonNull(aesBaseParams)){
//如果是aes加密的请求参数不为空
String data = aesBaseParams.getData();
if(StringUtils.isNotEmpty(data)){
//如果不为空 ,进行解密,data为加密数据,key为aes密钥,此工具类自行获取
String aesDecodeStr = EncryptUtils.decryptByAES(data,key);
//.....
//验签、RSA解密操作、AES解密操作
//将解密后的json字符串,解析成实体对象
obj = JSON.parseObject(aesDecodeStr,methodParameter.getParameterType());
}
}
if(Objects.isNull(obj)){
//抛出异常,解密出错
throw new BaseException(ErrorCodesEnum.DECRYPT_ERROR);
}
return obj;
}
/**
*
* 获取application/json格式提交的请求参数的 json字符串
* @param httpServletRequest
* @return
* @throws IOException
*/
private String getAllParamJson(HttpServletRequest httpServletRequest) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = httpServletRequest.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
return stringBuilder.toString();
}
}
步骤4:注入AesArgumentResolver,实现WebMvcConfigurer并重写addArgumentResolvers方法
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* 创建ArgumentResolverConfig
*/
@Configuration
public class ArgumentResolverConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers){
argumentResolvers.add(aesArgumentResolver());
}
@Bean
public AesArgumentResolver aesArgumentResolver(){
return new AesArgumentResolver();
}
}
步骤5:如何使用
在请求参数对象前添加AesJson注解就可以自动解析参数啦
/**
* 推单接口
* @param reqVo
* @return
*/
@PostMapping("/pushOrder")
public PushOrderRspVo pushOrder(@AesJson PushOrderReqVo reqVo){
String orderNo = reqVo.getOrderNo();
//执行推单逻辑
}