我创建的项目项目为 SpringBoot 项目
org.springframework.boot spring-boot-starter-parent 3.1.3
org.springframework.boot spring-boot-starter-aop
这里以对前端传递过来的加密数据进行解密为例
import java.lang.annotation.*; /** * 标注需要进行 RSA 加密算法解密的通用注解。 * 该注解可以使用在类上、方法上、方法参数上、字段/属性上、局部变量上 */ @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DecodeRsaCommonAnnotation { }
import java.lang.annotation.*; /** * 标注需要进行 RSA 加密算法解密的方法参数的注解。 * 该注解可以使用在方法参数上 */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DecodeRsaParameterAnnotation { }
@GetMapping("/test") @DecodeRsaCommonAnnotation public void test( @DecodeRsaParameterAnnotation String text ) { System.out.println(text); }
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect @Order(1) @Component public class DecodeRsaAspect { /** * DecodeRsaAspect 的切点为被 @DecodeRsaCommonAnnotation 标记的位置 */ @Pointcut("@annotation(cn.org.xiaoweiba.graduationdesign.bookmall.annotation.rsa.DecodeRsaCommonAnnotation)") public void pointCut() { } /** * 采用 Rsa 加密算法进行解密 * * @param proceedingJoinPoint 切点 */ @Around("pointCut()") public Object decodeRsaAroundAdvice(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,开启默认不被允许的行为
获取指定对象中的指定字段(不包含父类中的字段)
/** * 获取指定对象中的指定字段(不包含父类中的字段)。 * 此方法在获取指定对象中的指定字段时,会包证获取的指定字段能够被访问。 * * @param object 要获取字段的指定对象 * @param fieldName 要获取的指定字段的名称 * @return 指定对象中的指定字段 */ public static Field getField(Object object, String fieldName) throws NoSuchFieldException { // 获取指定对象的 Class Class> 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 要赋值给字符串对象的值 */ public static void setValueString(String str, String strValue) throws NoSuchFieldException, 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)); }
import cn.org.xiaoweiba.graduationdesign.bookmall.utils.ReflectUtil; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect @Order(1) @Component public class DecodeRsaAspect { /** * DecodeRsaAspect 的切点为被 @DecodeRsaCommonAnnotation 标记的位置 */ @Pointcut("@annotation(cn.org.xiaoweiba.graduationdesign.bookmall.annotation.rsa.DecodeRsaCommonAnnotation)") public void pointCut() { } /** * 采用 Rsa 加密算法进行解密 * * @param joinPoint 切点 */ @Before("pointCut()") public void decodeRsaBeforeAdvice(JoinPoint joinPoint) { try { // 获取切点方法的参数 Object[] args = joinPoint.getArgs(); // 中间处理 ... // 对切点方法的参数进行重新赋值 for (int i = 0; i < args.length; i++) { // 对字符串对象的 value 字段重新赋值,不修改字符串对象的指向,保证修改的为切点方法的字符串对象参数 ReflectUtil.setValueString((String) args[i], "解密后的数据"); } } catch (Throwable e) { // 异常处理 ... } } }