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


相关文章
|
5月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
778 3
|
4月前
|
JSON API 数据安全/隐私保护
Python采集淘宝拍立淘按图搜索API接口及JSON数据返回全流程指南
通过以上流程,可实现淘宝拍立淘按图搜索的完整调用链路,并获取结构化的JSON商品数据,支撑电商比价、智能推荐等业务场景。
|
5月前
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
858 128
|
5月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
604 0
|
5月前
|
Java 测试技术 API
将 Spring 的 @Embedded 和 @Embeddable 注解与 JPA 结合使用的指南
Spring的@Embedded和@Embeddable注解简化了JPA中复杂对象的管理,允许将对象直接嵌入实体,减少冗余表与连接操作,提升数据库设计效率。本文详解其用法、优势及适用场景。
366 126
|
4月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
544 2
|
5月前
|
Java 测试技术 数据库
使用Spring的@Retryable注解进行自动重试
在现代软件开发中,容错性和弹性至关重要。Spring框架提供的`@Retryable`注解为处理瞬时故障提供了一种声明式、可配置的重试机制,使开发者能够以简洁的方式增强应用的自我恢复能力。本文深入解析了`@Retryable`的使用方法及其参数配置,并结合`@Recover`实现失败回退策略,帮助构建更健壮、可靠的应用程序。
666 1
使用Spring的@Retryable注解进行自动重试
|
5月前
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
420 12
|
5月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
291 0
探索Spring Boot的@Conditional注解的上下文配置

热门文章

最新文章