spring实现自定义注解切面编程

spring实现自定义注解切面编程

例如要实现在某几个类之后或之前调用一些操作,就可以用到这个

1. 创建自定义注解

import java.lang.annotation.*;

//注解放置的位置,METHOD是放在方法上
@Target(ElementType.METHOD)
//注解在哪个阶段执行
@Retention(RetentionPolicy.RUNTIME)
//生成文档
@Documented
public @interface ElaSearchRefresh {
    String id() default "";

    String className() default "";

}

类中只需要写上自己需要的字段即可,后面可以作为传参使用

2. 引入注解变量解析util

照抄就完了

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 该类的作⽤可以把⽅法上的参数绑定到注解的变量中
 * 注解的语法
 * 变量名
 * #{}
 * 能解析类似
 * "#{sysOperateLogDto.operateType}"
 */
public class AnnotationResolver {
    private static AnnotationResolver resolver;

    public static AnnotationResolver newInstance() {
        if (resolver == null) {
            return resolver = new AnnotationResolver();
        } else {
            return resolver;
        }
    }

    /**
     * 解析注解上的值
     *
     * @param joinPoint 需要解析的字符串
     * @param str
     * @return
     */
    public Object resolver(JoinPoint joinPoint, String str) {
        if (str == null) return null;
        Object value = null;
        //如果匹配上了#则把内容当作变量
        if (str.matches("#\\{\\D*\\}")) {
            String newStr = str.replaceAll("#\\{", "").replaceAll("\\}", "");
            if (newStr.contains(".")) {//复杂类型
                try {
                    value = complexResolver(joinPoint, newStr);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                value = simpleResolver(joinPoint, newStr);
            }
        } else {//⾮变量
            value = str;
        }
        return value;
    }

    private Object complexResolver(JoinPoint joinPoint, String str) throws Exception {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] names = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        boolean jsonParseFlag = false;
        if (str.startsWith("$JSON$")){
            jsonParseFlag = true;
            str = str.replace("$JSON$","");
        }
        String[] strs = str.split("\\.");
        for (int i = 0; i < names.length; i++) {
            if (strs[0].equals(names[i])) {
                Object obj = args[i];
                if (obj instanceof Map){
                    return ((Map<?, ?>) obj).get(strs[1]);
                }
                //支持json解析
                if (obj instanceof String && jsonParseFlag){
                    JSONObject jsonObject = JSON.parseObject(obj.toString());
                    return jsonObject.get(strs[1]);
                }
                Method dmethod = obj.getClass().getDeclaredMethod(getMethodName(strs[1]));
                Object value = dmethod.invoke(args[i]);
                return getValue(value, 1, strs);
            }
        }
        return null;
    }

    private Object getValue(Object obj, int index, String[] strs) {
        try {
            if (obj != null && index < strs.length - 1) {
                Method method = obj.getClass().getDeclaredMethod(getMethodName(strs[index + 1]));
                obj = method.invoke(obj);
                getValue(obj, index + 1, strs);
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private String getMethodName(String name) {
        return "get" + name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
    }

    private Object simpleResolver(JoinPoint joinPoint, String str) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] names = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < names.length; i++) {
            if (str.equals(names[i])) {
                return args[i];
            }
        }
        return null;
    }
}

3. 创建切面类

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.*;

@Aspect
@Component
public class ElaSearchAspect {

    @Autowired
    private IBaseDao baseDao;

    //定义切点
    @Pointcut(value = "@annotation(net.zjsos.business.common.business.filebase.aspect.ElaSearchRefresh)")
    public void elaRefreshPointCut() {

    }

    //定义切面
    @After("elaRefreshPointCut()")
    //around需要使用ProceedingJoinPoint point
    public void after(JoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        ElaSearchRefresh annotation = method.getAnnotation(ElaSearchRefresh.class);
        //利用util来反射解析动态变量属性
        String id = AnnotationResolver.newInstance().resolver(point, annotation.id()).toString();
        //如果是写死的变量,直接使用annotation.id()获取即可
    }
    
    //定义切面
    @Around("elaRefreshPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //去执⾏被访问的切⾯
        Object result = point.proceed();
        //从切⾯织⼊点处通过反射机制获取织⼊点处
        MethodSignature signature = (MethodSignature) point.getSignature();
        //获取切⼊点所在的方法
        Method method = signature.getMethod();
        ElaSearchRefresh annotation = method.getAnnotation(ElaSearchRefresh.class);
        //利用util来反射解析动态变量属性
        String id = AnnotationResolver.newInstance().resolver(point, annotation.id()).toString();
        //如果是写死的变量,直接使用annotation.id()获取即可
    }
}

4. 使用注解

@RequestMapping("/updateAccessByApplyId")
    //获取动态变量需要加"#{}",写死的变量直接"xxx"就行了
    @ElaSearchRefresh(id = "#{dto.id}")
    public ResultDto updateAccessByApplyId(@RequestBody @Valid FileBaseUpdateAccessDto dto){
        xxxxxxxxxxxxxxxxxxxxxx
    }
评论区
头像
文章目录