springboot版本 2.4.9
话不多说,直接上代码
代码中的json工具和加密工具均是使用的hutool包中的
依赖
cn.hutool
hutool-all
5.7.11
先来自定义一个注解
@Target({ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamsAESAnno {
}
使用@Target注解标明此注解能用在方法和参数上面
使用@Retention注解标明此注解作用在运行阶段
然后我们要处理接口参数的话,需要自定义参数解析器,实现springMvc的
HandlerMethodArgumentResolver
@Log4j2
public class AESDecodeResolver implements HandlerMethodArgumentResolver {
/*
秘钥
*/
public static final String KEY = "vhukzevhukze1234";
/*
json参数的key
*/
private static final String NAME = "str";
/**
* 如果接口或者接口参数有解密注解,就解析
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasMethodAnnotation((ParamsAESAnno.class)) || parameter.hasParameterAnnotation(ParamsAESAnno.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest webRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
//AES
AES aes = SecureUtil.aes(KEY.getBytes(StandardCharsets.UTF_8));
//如果是实体类参数,把请求参数封装
if (BaseReq.class.isAssignableFrom(parameter.getParameterType())) {
//获取加密的请求数据并解密
String beforeParam = webRequest.getParameter(NAME);
String afterParam = aes.decryptStr(beforeParam, CharsetUtil.CHARSET_UTF_8);
//json转对象 // 这里的return就会把转化过的参数赋给控制器的方法参数
return JSONUtil.toBean(afterParam, parameter.getParameterType());
// 如果是非集合类,就直接解码返回
} else if (!Iterable.class.isAssignableFrom(parameter.getParameterType())) {
String decryptStr = aes.decryptStr(webRequest.getParameter(parameter.getParameterName()), CharsetUtil.CHARSET_UTF_8);
return Integer.class.isAssignableFrom(parameter.getParameterType()) ? Integer.parseInt(decryptStr) : decryptStr;
//如果是集合类
} else {
//获取加密的请求数据并解密
String beforeParam = webRequest.getParameter(NAME);
String afterParam = aes.decryptStr(beforeParam, CharsetUtil.CHARSET_UTF_8);
//转成对象数组
JSONArray jsonArray = JSONUtil.parseArray(afterParam);
return jsonArray.stream()
.map(json -> JSONUtil.toBean(json.toString(), parameter.getParameterType()))
.collect(Collectors.toList());
}
}
}
但是现在post请求都是用json提交,不用表单提交了,如果是json提交的话,改成下面这样
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.gt.SPYZT.annotation.ParamsAESAnno;
import com.gt.SPYZT.entity.dto.BaseReq;
import com.gt.SPYZT.utils.AESUtil;
import lombok.extern.log4j.Log4j2;
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.IOException;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* 解析加密注解
*
* @author vhukze
* @date 2021/9/8 11:14
*/
@Log4j2
public class AESDecodeResolver implements HandlerMethodArgumentResolver {
/*
json参数的key
*/
private static final String NAME = "str";
/**
* 如果接口或者接口参数有解密注解,就解析
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasMethodAnnotation((ParamsAESAnno.class)) || parameter.hasParameterAnnotation(ParamsAESAnno.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest webRequest, WebDataBinderFactory webDataBinderFactory) throws IOException {
//aes
AES aes = AESUtil.aes;
//获取post请求的json数据
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
int contentLength = request.getContentLength();
if (contentLength < 0) {
return null;
}
byte[] buffer = new byte[contentLength];
for (int i = 0; i < contentLength; ) {
int readlen = request.getInputStream().read(buffer, i,
contentLength - i);
if (readlen == -1) {
break;
}
i += readlen;
}
String str = new String(buffer,CharsetUtil.CHARSET_UTF_8);
StringBuilder sb = new StringBuilder();
for (char c : str.toCharArray()) {
//去掉json中的空格 换行符 制表符
if(c != 32 && c != 13 && c != 10){
sb.append(c);
}
}
//如果是实体类参数,把请求参数封装
if (BaseReq.class.isAssignableFrom(parameter.getParameterType())) {
//获取加密的请求数据并解密
// String beforeParam = webRequest.getParameter(NAME);
String afterParam = aes.decryptStr(JSONUtil.parseObj(sb.toString()).get(NAME).toString(), CharsetUtil.CHARSET_UTF_8);
//json转对象 // 这里的return就会把转化过的参数赋给控制器的方法参数
return JSONUtil.toBean(afterParam, parameter.getParameterType());
// 如果是非集合类,就直接解码返回
} else if (!Iterable.class.isAssignableFrom(parameter.getParameterType())) {
String decryptStr = aes.decryptStr(webRequest.getParameter(parameter.getParameterName()), CharsetUtil.CHARSET_UTF_8);
return Integer.class.isAssignableFrom(parameter.getParameterType()) ? Integer.parseInt(decryptStr) : decryptStr;
//如果是集合类
} else if(Iterable.class.isAssignableFrom(parameter.getParameterType())){
//获取加密的请求数据并解密
// String beforeParam = webRequest.getParameter(NAME);
String afterParam = aes.decryptStr(sb.toString(), CharsetUtil.CHARSET_UTF_8);
//转成对象数组
JSONArray jsonArray = JSONUtil.parseArray(afterParam);
return jsonArray.stream()
.map(json -> JSONUtil.toBean(JSONUtil.parseObj(sb.toString()).get(NAME).toString(), parameter.getParameterType()))
.collect(Collectors.toList());
}
return null;
}
}
注册自定义解析器
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
//region 注册自定义HandlerMethodArgumentResolver
@Override
public void addArgumentResolvers(List resolvers) {
resolvers.add(aesDecodeResolver());
}
@Bean
public AESDecodeResolver aesDecodeResolver() {
return new AESDecodeResolver();
}
//endregion
}
接下来就可以直接使用注解了
@RestController
@RequestMapping("test")
public class TestController {
@ParamsAESAnno
@GetMapping
public RestfulResp> test(String str,Integer type) {
return new RestfulResp<>().success();
}
@ParamsAESAnno
@PostMapping("json")
public RestfulResp> jsonTest(BaseReq baseReq){
return new RestfulResp<>().success();
}
@ParamsAESAnno
@PostMapping("jsonList")
public RestfulResp> jsonTest(List list){
return new RestfulResp<>().success();
}
}
效果图就不贴了,测试没有问题
如果想使用Validation包里面注解校验参数,请看我的另一篇博文:
使用反射实现@RequestBody的参数校验功能
本文参考博文:SpringBoot使用自定义注解实现简单参数加密解密(注解+HandlerMethodArgumentResolver) - yellowgg - 博客园