一、需求
被@EncryptMethod标注的方法为切入点,对被@EncryptField注解标注的参数进行加密解密。
二、问题列表
(基本等于初次使用切面,遇到的问题有些许智障,不许嘲笑,嘲笑我就打你👊)
问题一:
能进入增强方法,但无法进入目标业务方法
解决:
没有调用 point.proceed(),该方法旨在调用目标方法,并获取其返回值。(没有调用该方法又怎么会进入业务呢😓,我是白痴)
问题二:
获取参数上的注解(刚开始一直着眼于单个参数上的注解,比如其中一个参数@EncryptField String name,一直不知道该怎么获取,后来看到可以一次获取方法所有参数的注解,获取方法如下)
解决:
//方法签名。方法签名是方法的形式定义,它提供了对该功能的高级描述。
MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();
//获取方法中参数上的注解
Annotation[][] annotations = methodSig.getMethod().getParameterAnnotations();
annotations 是一个二维数组,第一维是参数序号,第二维是其对应的注解。
问题三:
切面加密成功,但进入目标方法的参数依然是未加密的
解决:
没有将加密后的参数传入point.proceed()🤦
Object result = joinPoint.proceed(joinPoint.getArgs());
综上,所有的问题都很基础,就是因为我对基础知识不熟造成的,以后我一定先了解好基础知识再上手做(ง •_•)ง。最后,附上代码。第一次可能做的不好,有什么建议都可以说哦,成长靠你了🤝。
@Documented
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
String[] value() default "";
}
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptMethod {
String type() default "encrypt";
}
@Slf4j
@Aspect
@Component
public class EncryptHandler {
@Resource
private StringEncryptor stringEncryptor;
@Pointcut("@annotation(com.example.demo.utils.EncryptMethod)")
public void pointCut(){
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
/**
* 加密
*/
encrypt(joinPoint);
Object result = joinPoint.proceed(joinPoint.getArgs());
/**
* 解密
*/
Object decrypt = decrypt(joinPoint);
return decrypt;
}
public void encrypt(ProceedingJoinPoint joinPoint){
try {
//方法签名。方法签名是方法的形式定义,它提供了对该功能的高级描述。
MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();
//获取方法中参数上的注解
Annotation[][] annotations = methodSig.getMethod().getParameterAnnotations();
Object[] args = joinPoint.getArgs();
for(int i = 0; i < args.length; i++){
for(Annotation annotation:annotations[i]){
if (EncryptField.class.isInstance(annotation)) {
args[i] = encryptValue(args[i]);
break;
}else if(RequestBody.class.isInstance(annotation)){
handler(args[i],"encrypt");
break;
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public Object decrypt(ProceedingJoinPoint joinPoint){
Object result=null;
try {
MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();
Annotation[][] annotations = methodSig.getMethod().getParameterAnnotations();
Object[] args = joinPoint.getArgs();
for(int i = 0; i < args.length; i++){
for(Annotation annotation:annotations[i]){
if (EncryptField.class.isInstance(annotation)) {
args[i] = decryptValue(args[i]);
break;
}else if(RequestBody.class.isInstance(annotation)){
result=handler(args[i],"decrypt");
break;
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return result;
}
public Object encryptValue(Object realValue){
String value=null;
try {
value=stringEncryptor.encrypt(String.valueOf(realValue));
}catch (Exception e){
return value;
}
return value;
}
public String decryptValue(Object realValue) {
String value = String.valueOf(realValue);
try {
value = stringEncryptor.decrypt(value);
} catch (Exception ex) {
return value;
}
return value;
}
public Object handler(Object obj,String type) throws IllegalAccessException {
if(obj==null){
return null;
}
Field[] declaredFields = obj.getClass().getDeclaredFields();
for(Field field:declaredFields){
boolean hasSecureField = field.isAnnotationPresent(EncryptField.class);
if(hasSecureField ){
field.setAccessible(true);
String realValue = (String)field.get(obj);
String value;
if("encrypt".equals(type)){
value=stringEncryptor.encrypt(realValue);
}else{
value=stringEncryptor.decrypt(realValue);
}
field.set(obj,value);
}
}
return obj;
}
}
@RestController
@RequestMapping("/encrypt")
public class EncryptController {
@Resource
private StringEncryptor stringEncryptor;
@EncryptMethod
@RequestMapping("/test")
//这里之所以没把name放进user里,是想试一下这种方式传入的参数如何处理
public Object test(@RequestBody User user, @EncryptField @RequestParam String name){
return insertUser(user,name);
}
private UserVo insertUser(User user,String name){
UserVo userVo = new UserVo();
BeanUtils.copyProperties(user,userVo);
userVo.setName(name);
System.out.println("加密后的数据:user"+ JSON.toJSONString(userVo));
return userVo;
}
}