springboot版本 2.4.9
话不多说,直接上代码
代码中的json工具和加密工具均是使用的hutool包中的
依赖
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.11</version> </dependency>
先来自定义一个注解
@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<HandlerMethodArgumentResolver> 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<BaseReq> list){ return new RestfulResp<>().success(); } }
效果图就不贴了,测试没有问题
如果想使用Validation包里面注解校验参数,请看我的另一篇博文:
使用反射实现@RequestBody的参数校验功能
本文参考博文:SpringBoot使用自定义注解实现简单参数加密解密(注解+HandlerMethodArgumentResolver) - yellowgg - 博客园