AOP 依赖
我创建的项目项目为 SpringBoot 项目
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.3</version></parent>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
String 类型参数
这里以对前端传递过来的加密数据进行解密为例
注解
importjava.lang.annotation.*;/**
* 标注需要进行 RSA 加密算法解密的通用注解。
* 该注解可以使用在类上、方法上、方法参数上、字段/属性上、局部变量上
*/@Target({ElementType.TYPE,ElementType.METHOD,ElementType.PARAMETER,ElementType.FIELD,ElementType.LOCAL_VARIABLE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceDecodeRsaCommonAnnotation{}
importjava.lang.annotation.*;/**
* 标注需要进行 RSA 加密算法解密的方法参数的注解。
* 该注解可以使用在方法参数上
*/@Target({ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceDecodeRsaParameterAnnotation{}
控制器方法
@GetMapping("/test")@DecodeRsaCommonAnnotationpublicvoidtest(@DecodeRsaParameterAnnotationString text
){System.out.println(text);}
方式一:通过环绕通知实现 [个人比较推荐]
importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Pointcut;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;@Aspect@Order(1)@ComponentpublicclassDecodeRsaAspect{/**
* DecodeRsaAspect 的切点为被 @DecodeRsaCommonAnnotation 标记的位置
*/@Pointcut("@annotation(cn.org.xiaoweiba.graduationdesign.bookmall.annotation.rsa.DecodeRsaCommonAnnotation)")publicvoidpointCut(){}/**
* 采用 Rsa 加密算法进行解密
*
* @param proceedingJoinPoint 切点
*/@Around("pointCut()")publicObjectdecodeRsaAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){Object returnVal =null;try{// 获取切点方法的参数Object[] args = proceedingJoinPoint.getArgs();// 中间处理 ...// 对切点方法的参数进行重新赋值for(int i =0; i < args.length; i++){
args[i]="RSA 加密算法解密后的数据";}// 执行切点方法,并传递重新赋值后的参数列表
returnVal = proceedingJoinPoint.proceed(args);}catch(Throwable e){// 异常处理 ...}// 返回切点方法执行后的返回值return returnVal;}}
方式二:通过前置通知 + 反射实现
Java ReflectUtil 反射相关的工具类
由于 JDK 8 中有关反射相关的功能自从 JDK 9 开始就已经被限制了,如:通过反射修改 String 类型变量的 value 字段(final byte[]),所以要能够使用运行此方法,需要在运行项目时,添加虚拟机(VM)选项:
--add-opens java.base/java.lang=ALL-UNNAMED
,开启默认不被允许的行为
通过反射修改 String 类型对象 value 取值的工具方法
获取指定对象中的指定字段(不包含父类中的字段)
/**
* 获取指定对象中的指定字段(不包含父类中的字段)。
* 此方法在获取指定对象中的指定字段时,会包证获取的指定字段能够被访问。
*
* @param object 要获取字段的指定对象
* @param fieldName 要获取的指定字段的名称
* @return 指定对象中的指定字段
*/publicstaticFieldgetField(Object object,String fieldName)throwsNoSuchFieldException{// 获取指定对象的 ClassClass<?> objectClass = object.getClass();// 获取指定对象中的指定字段Field declaredField = objectClass.getDeclaredField(fieldName);// 保证获取的指定字段能够被访问
declaredField.setAccessible(true);return declaredField;}
通过反射为字符串对象的 value 字段重新赋值为 strValue
/**
* 通过反射为字符串对象的 value 字段重新赋值为 strValue,
* 从而保证不修改字符串对象的引用,并且能够修改字符串的取值
* 由于 JDK 8 中有关反射相关的功能自从 JDK 9 开始就已经被限制了,所以要能够使用运行此方法,
* 需要在运行项目时,添加虚拟机(VM)选项:--add-opens java.base/java.lang=ALL-UNNAMED
* 开启默认不被允许的行为
*
* @param str 需要进行重新赋值的字符串对象
* @param strValue 要赋值给字符串对象的值
*/publicstaticvoidsetValueString(String str,String strValue)throwsNoSuchFieldException,IllegalAccessException{// 获取字符串的 value 字段Field strValueField =getField(str,"value");// 为字符串对象的 value 字段重新赋值// strValueField.set(str, strValue.getBytes(StandardCharsets.UTF_8)); 不要使用该种方法,会出现乱码// 采用如下方式,获取 strValue 的 value 字段值,将其赋值给 str 的 value 字段
strValueField.set(str, strValueField.get(strValue));}
切面类
importcn.org.xiaoweiba.graduationdesign.bookmall.utils.ReflectUtil;importorg.aspectj.lang.JoinPoint;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.aspectj.lang.annotation.Pointcut;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;@Aspect@Order(1)@ComponentpublicclassDecodeRsaAspect{/**
* DecodeRsaAspect 的切点为被 @DecodeRsaCommonAnnotation 标记的位置
*/@Pointcut("@annotation(cn.org.xiaoweiba.graduationdesign.bookmall.annotation.rsa.DecodeRsaCommonAnnotation)")publicvoidpointCut(){}/**
* 采用 Rsa 加密算法进行解密
*
* @param joinPoint 切点
*/@Before("pointCut()")publicvoiddecodeRsaBeforeAdvice(JoinPoint joinPoint){try{// 获取切点方法的参数Object[] args = joinPoint.getArgs();// 中间处理 ...// 对切点方法的参数进行重新赋值for(int i =0; i < args.length; i++){// 对字符串对象的 value 字段重新赋值,不修改字符串对象的指向,保证修改的为切点方法的字符串对象参数ReflectUtil.setValueString((String) args[i],"解密后的数据");}}catch(Throwable e){// 异常处理 ...}}}
版权归原作者 萤火虫的小尾巴 所有, 如有侵权,请联系我们删除。