springboot项目通过自定义注解+aop实现对入参加解密

1.创建自定义注解:

java 复制代码
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptDecrypt {
}

2.创建加解密工具类:

java 复制代码
public class EncryptionUtils {
    // 加密方法
    public static String encrypt(String data) {
        // 实现加密逻辑
        // ...
        return encryptedData;
    }

    // 解密方法
    public static String decrypt(String encryptedData) {
        // 实现解密逻辑
        // ...
        return decryptedData;
    }
}

3.创建切面类:

java 复制代码
@Aspect
@Component
public class EncryptionAspect {

    @Around("execution(* com.example.*.*(..)) && (@annotation(com.example.EncryptDecrypt) || @args(com.example.EncryptDecrypt))")
    public Object encryptDecryptMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法参数
        Object[] args = joinPoint.getArgs();

        // 遍历参数,对带有 EncryptDecrypt 注解的参数进行加解密操作
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            if (arg != null) {
                if (arg instanceof String) {
                    if (arg.getClass().isAnnotationPresent(EncryptDecrypt.class)) {
                        String encryptedData = (String) arg;
                        String decryptedData = EncryptionUtils.decrypt(encryptedData);
                        args[i] = decryptedData;
                    }
                } else {
                    Field[] fields = arg.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        if (field.isAnnotationPresent(EncryptDecrypt.class)) {
                            field.setAccessible(true);
                            Object fieldValue = field.get(arg);
                            if (fieldValue instanceof String) {
                                String encryptedData = (String) fieldValue;
                                String decryptedData = EncryptionUtils.decrypt(encryptedData);
                                field.set(arg, decryptedData);
                            }
                        }
                    }
                }
            }
        }

        // 执行原方法
        Object result = joinPoint.proceed(args);

        // 对返回值进行加密操作(可根据需求进行操作)

        return result;
    }
}

4.参数解释

java 复制代码
@Target({ElementType.FIELD, ElementType.PARAMETER}) 是一个注解的元注解,用于指定注解可以应用的目标元素类型。在这个例子中,@Target 注解表明注解 EncryptDecrypt 可以应用于字段(Field)和参数(Parameter)上。

ElementType.FIELD 表示注解可以应用于字段上,即类的成员变量。
ElementType.PARAMETER 表示注解可以应用于方法的参数上。
通过指定这些目标元素类型,你可以限制注解的使用范围,确保它只能应用在指定的地方。在这个场景中,EncryptDecrypt 注解旨在用于标记需要进行加解密操作的字段和方法参数。
java 复制代码
1.execution(* com.example.*.*(..)):表示匹配 com.example 包及其子包下的所有类的所有方法。

		execution() 是切点函数,用于匹配方法执行的连接点。
		* 表示匹配任意返回类型的方法。
		com.example.* 表示匹配 com.example 包下的任意类。
		*.*(..) 表示匹配任意方法名和参数的方法。
		
2.(@annotation(com.example.EncryptDecrypt) || @args(com.example.EncryptDecrypt)):表示匹配带有 EncryptDecrypt 注解的方法或参数。

		@annotation(com.example.EncryptDecrypt) 匹配带有 EncryptDecrypt 注解的方法。
		@args(com.example.EncryptDecrypt) 匹配带有 EncryptDecrypt 注解的参数。

-----------------------------------------分割线-------------------------------------------------------------------------------------------

对出参进行解密

注解类

java 复制代码
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Decrypt {
    String value() default "";
}
java 复制代码
mport org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Collection;

@Aspect
@Component
public class DecryptionAspect {

    @Around("execution(* com.example.*.*(..))")
    public Object decryptMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // 执行原方法并获取返回值
        Object result = joinPoint.proceed();

        // 对带有 @Decrypt 注解的字段进行解密操作
        if (result != null) {
            if(result instanceof GatewayResp){
            //GatewayResp 为统一定义的出参 包括code,msg,data
                GatewayResp r = (GatewayResp) result;
                Object data = r.getData();
                if(data instanceof Collection<?>) {
                    //集合
                    data = decryptCollectionFields((Collection<?>)data);
                }else{
                    //单对象
                    data = decryptObjectFields(data);
                }
                r.setData(data);
            }

        }

        return result;
    }

    private Collection<?> decryptCollectionFields(Collection<?> collection) throws IllegalAccessException {
        for (Object object : collection) {
            decryptObjectFields(object);
        }
        return collection;
    }
    private Object decryptObjectFields(Object object) throws IllegalAccessException {
        Field[] fields = object.getClass().getDeclaredFields();

        for (Field field : fields) {
            // 如果字段带有 @Decrypt 注解,则对其进行解密操作
            if (field.isAnnotationPresent(Decrypt.class)) {
                field.setAccessible(true);
                Object fieldValue = field.get(object);

                if (fieldValue instanceof String) {
                    String decryptedValue = EncryptionUtils.decrypt((String) fieldValue);
                    field.set(object, decryptedValue);
                }
            } else {
                // 如果字段不带有 @Decrypt 注解,则递归调用 decryptObjectFields() 方法
                field.setAccessible(true);
                Object fieldValue = field.get(object);

                if (fieldValue != null) {
                    if (fieldValue instanceof Collection<?>) {
                        decryptCollectionFields((Collection<?>) fieldValue);
                    } else if(isCustomObject(fieldValue)){
                        decryptObjectFields(fieldValue);
                    }
                }
            }
        }
        return object;
    }

    /**
     * 判断一个对象不是八大基本数据类型和String类型
     */
    private boolean isCustomObject(Object object) {
        Class<?> objectType = object.getClass();

        // 判断是否为八大基本数据类型
        if (objectType.isPrimitive()) {
            return false;
        }

        // 判断是否为String类型
        if (objectType.equals(String.class)) {
            return false;
        }

        return true;
    }
}
相关推荐
雾月552 分钟前
LeetCode 1292 元素和小于等于阈值的正方形的最大边长
java·数据结构·算法·leetcode·职场和发展
CopyLower37 分钟前
在 Spring Boot 中实现 WebSockets
spring boot·后端·iphone
24k小善1 小时前
Flink TaskManager详解
java·大数据·flink·云计算
想不明白的过度思考者1 小时前
Java从入门到“放弃”(精通)之旅——JavaSE终篇(异常)
java·开发语言
.生产的驴1 小时前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
猿周LV2 小时前
JMeter 安装及使用 [软件测试工具]
java·测试工具·jmeter·单元测试·压力测试
晨集2 小时前
Uni-App 多端电子合同开源项目介绍
java·spring boot·uni-app·电子合同
时间之城2 小时前
笔记:记一次使用EasyExcel重写convertToExcelData方法无法读取@ExcelDictFormat注解的问题(已解决)
java·spring boot·笔记·spring·excel
椰羊~王小美2 小时前
LeetCode -- Flora -- edit 2025-04-25
java·开发语言
凯酱2 小时前
MyBatis-Plus分页插件的使用
java·tomcat·mybatis