springboot使用自定义注解实现接口参数解密,普通字段,json,集合

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 - 博客园

你可能感兴趣的:(springboot,json,spring,restful,自定义注解,接口参数解密)