基于Spring-AOP写的切面和注解,解决一些跟业务逻辑无关的公共问题处理方法

技术点: Spring  Aop  反射

背景:目前在做一个项目,做数据库设计的时候对一些表进行了埋点,比如跟我业务相关的每个表,都有create_time,create_user_id,create_user_name,update_time,update_user_id,update_user_name等字段

如果放在Dao处理,则我每一个表对应的每一个实体都需要setCreateUserId,setCreateUserName,setUpdateUserId,

setUpdateUserName 等等,代码咸的很臃肿,基于这样的背景,写了一个切面,处理这些公共的逻辑。

代码:

      aspect 包:

 

注解             

import java.lang.annotation.*;

/**
 * @author qiwenshuai
 * @note
 * @since 18-11-8 14:00 by jdk 1.8
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OTADaoRecord {
    OTARecordEnum type()  default OTARecordEnum.NONE;
}

枚举
/**
 * @author qiwenshuai
 * @note
 * @since 18-11-9 09:17 by jdk 1.8
 */
public enum OTARecordEnum {

    NONE("NONE",0),

    CREATE("CREATE",1),

    UPDATE("UPDATE",2),

    MAPCREATE("MAPCREATE",3),

    MAPUPDATE("MAPUPDATE",4),

    ;


    private String type;
    private Integer value;

    OTARecordEnum(String type,Integer value){
        this.type=type;
        this.value=value;
    }


    public String getType() {
        return type;
    }

    public Integer getValue() {
        return value;
    }

}

切面

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author qiwenshuai
 * @note 每次修改和新增都要增加 userId和userName 为了简便,写个注解只关注业务层。
 * @since 18-11-8 17:45 by jdk 1.8
 */
@Aspect
@Component
public class RecordAspect {

    private static final Logger logger = LoggerFactory.getLogger(RecordAspect.class);

    private static final String CREATE_USER_ID_METHOD = "setCreateUserId";
    private static final String CREATE_USER_NAME_METHOD = "setCreateUserName";
    private static final String CREATE_DATA_SOURCE_METHOD = "setDataSource";
    private static final String CREATE_MAP_USER_ID_METHOD = "createUserId";
    private static final String CREATE_MAP_USER_NAME_METHOD = "createUserName";
    private static final String CREATE_MAP_DATA_SOURCE_METHOD = "dataSource";
    private static final String UPDATE_MAP_USER_ID = "updateUserId";
    private static final String UPDATE_MAP_USER_NAME = "updateUserName";
    private static final String UPDATE_USER_ID_METHOD = "setUpdateUserId";
    private static final String UPDATE_USER_NAME_METHOD = "setUpdateUserName";

    protected final HttpServletRequest request;

    @Autowired
    public RecordAspect(HttpServletRequest request) {
        this.request = request;
    }

    //Controller层切点
    @Pointcut("@annotation(cn.futuremove.tsp.vehicle.aspect.OTADaoRecord)")
    public void OTADaoRecord() {
    }

    /**
     * 环绕AOP
     */
    @Around("OTADaoRecord()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        try {
            if (OTARecordEnum.UPDATE.equals(getControllerMethodDescription(pjp))) {
                setUpdateProperty(pjp);
            } else if (OTARecordEnum.CREATE.equals(getControllerMethodDescription(pjp))) {
                setCreateProperty(pjp);
            } else if (OTARecordEnum.MAPCREATE.equals(getControllerMethodDescription(pjp))) {
                setMapCreateProperty(pjp);
            } else if (OTARecordEnum.MAPUPDATE.equals(getControllerMethodDescription(pjp))) {
                setMapUpdateProperty(pjp);
            }
            return pjp.proceed();
        } catch (Exception e) {
            logger.error("切面设置值发生错误:{}", e);
            return null;
        }

    }


    /**
     * 反射获取type值的逻辑
     */
    private OTARecordEnum getControllerMethodDescription(ProceedingJoinPoint pjp) throws ClassNotFoundException {
        String targetName = pjp.getTarget().getClass().getName();
        String methodName = pjp.getSignature().getName();
        Object[] arguments = pjp.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        OTARecordEnum recordEnum = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    recordEnum = method.getAnnotation(OTADaoRecord.class).type();
                    break;
                }
            }
        }
        return recordEnum;
    }


    private void setCreateProperty(ProceedingJoinPoint pjp) throws InvocationTargetException, IllegalAccessException {
        //create的逻辑
        Object[] arguments = pjp.getArgs();
        for (Object object : arguments) {
            Method[] methods = object.getClass().getMethods();
            createInvoke(methods, object);
        }
    }


    private void setUpdateProperty(ProceedingJoinPoint pjp) throws InvocationTargetException, IllegalAccessException {
        //create的逻辑
        Object[] arguments = pjp.getArgs();
        for (Object object : arguments) {
            Method[] methods = object.getClass().getMethods();
            updateInvoke(methods, object);
        }
    }


    private void setMapCreateProperty(ProceedingJoinPoint pjp) {
        Object[] arguments = pjp.getArgs();
        for (Object o : arguments) {
            if (o instanceof Map) {
                for (Object key : ((Map) o).keySet()) {
                    Map map = (Map)((Map<String,Object>) o).get(key);
                    map.put(CREATE_MAP_USER_ID_METHOD,"999");
                    map.put(CREATE_MAP_USER_NAME_METHOD,"create");
                    map.put(CREATE_MAP_DATA_SOURCE_METHOD,"1");
                }
            }
        }
    }

    private void setMapUpdateProperty(ProceedingJoinPoint pjp) {
        Object[] arguments = pjp.getArgs();
        for (Object o : arguments) {
            if (o instanceof Map) {
                for (Object key : ((Map) o).keySet()) {
                    Map map = (Map)((Map<String,Object>) o).get(key);
                    map.put(UPDATE_MAP_USER_ID,"999");
                    map.put(UPDATE_MAP_USER_NAME,"update");
                }
            }
        }

    }


    private void createInvoke(Method[] methods, Object object) throws InvocationTargetException, IllegalAccessException {
        for (Method method : methods) {
            if (method.getName().equals(CREATE_USER_ID_METHOD)) {
                //后期取值
                method.invoke(object, "99999");
            }
            if (method.getName().equals(CREATE_USER_NAME_METHOD)) {
                //后期取值
                method.invoke(object, "create");
            }
            if (method.getName().equals(CREATE_DATA_SOURCE_METHOD)) {
                //创建数据的时候,记录数据源
                method.invoke(object, "1");
            }
        }
    }

    private void updateInvoke(Method[] methods, Object object) throws InvocationTargetException, IllegalAccessException {
        for (Method method : methods) {
            if (method.getName().equals(UPDATE_USER_ID_METHOD)) {
                //后期取值
                method.invoke(object, "99999");
            }
            if (method.getName().equals(UPDATE_USER_NAME_METHOD)) {
                //后期取值
                method.invoke(object, "update");
            }
        }

    }
}

具体的Controller调用只需要在Controller层加上注解就可以了

例如:

@OTADaoRecord(type = OTARecordEnum.MAPUPDATE)
@OTADaoRecord(type = OTARecordEnum.CREATE)

等等。。。。。。。

 

要注意的是,使用声明式事务注解的时候,Controller层不要写 

@Transactional

基于Spring事务在Service层的传播性,要在Service处理所有的Dao逻辑,并且在Service层加上注解,并且不要加try-catch,否则Controller拦截不到Exception,无法回滚事务。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值