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

简介: springboot版本 2.4.9

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


相关文章
|
1月前
|
JSON API 数据处理
Swagger动态参数注解:使用@DynamicParameters实现JSON参数的灵活定义
总结起来,通过使用SpringFox提供给我们工具箱里面非常有力量但又不太显眼工具———即使面对复杂多变、非标准化数据格式也能轻松驾驭它们———从而大大增强我们系统与外界沟通交流能力同时也保证系统内部数据处理逻辑清晰明确易于维护升级.
145 10
|
4月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
9月前
|
Java Spring
SpringBoot 实战 不同参数调用不同实现
本文介绍了如何在实际工作中根据不同的入参调用不同的实现,采用`map+enum`的方式实现优雅且严谨的解决方案。通过Spring Boot框架中的工厂模式或策略模式,避免了使用冗长的`if...else...`语句。文中详细展示了定义接口、实现类、枚举类以及控制器调用的代码示例,确保用户输入的合法性并简化了代码逻辑。
270 1
SpringBoot 实战 不同参数调用不同实现
|
9月前
|
Java Maven 开发者
编写SpringBoot的自定义starter包
通过本文的介绍,我们详细讲解了如何创建一个Spring Boot自定义Starter包,包括自动配置类、配置属性类、`spring.factories`文件的创建和配置。通过自定义Starter,可以有效地复用公共配置和组件,提高开发效率。希望本文能帮助您更好地理解和应用Spring Boot自定义Starter,在实际项目中灵活使用这一强大的功能。
718 17
|
8月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——拦截自定义异常
本文介绍了在实际项目中如何拦截自定义异常。首先,通过定义异常信息枚举类 `BusinessMsgEnum`,统一管理业务异常的代码和消息。接着,创建自定义业务异常类 `BusinessErrorException`,并在其构造方法中传入枚举类以实现异常信息的封装。最后,利用 `GlobalExceptionHandler` 拦截并处理自定义异常,返回标准的 JSON 响应格式。文章还提供了示例代码和测试方法,展示了全局异常处理在 Spring Boot 项目中的应用价值。
380 0
|
11月前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
1767 15
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
244 8
|
12月前
|
安全 Java 应用服务中间件
如何将Spring Boot应用程序运行到自定义端口
如何将Spring Boot应用程序运行到自定义端口
952 0
|
SQL Java
springboot自定义注解收集操作日志
springboot自定义注解收集操作日志
415 0
springboot自定义注解收集操作日志
|
SQL Java
springboot高级功能(四)业务实战,自定义注解收集操作日志
springboot高级功能(四)业务实战,自定义注解收集操作日志
542 0