公共字段自动填充aop

在项目开发中,我们的数据库设计往往会包括创建人、创建时间、修改人、修改时间等公共字段,这些公共字段有助于帮助我们知道是谁对数据库记录进行了更改,但这带来的一个问题就是在进行数据库插入或修改的时候,这些字段需要手动设置,这会给我们带来很大不便,这里我简单讲一下采用aop方式进行公共字段填充,因为项目集成了tk.mybatis,很多单表的操作并没有显示指定接口,所以采用在service层方法进行切入来设置。以下列出用到的类,做一个思路的梳理,具体应用可自行更改。

 

公共字段自动填充aop_第1张图片

 

其中SetCommonField是一个注解,该注解打在方法上即可启用aop,该注解包含一个methodType属性,这个属性定义数据库的四种操作(增删改查),在CommonFieldAspect类中定义了对应的常量。

功能实现思路是解析前端请求得出用户id(这里我的代码有点问题,各位可自行考虑怎么获取用户id),然后根据用户id查询redis缓存得到用户信息保存到UserInfo,然后再根据不同的methodType将userInfo转换为CommonField,最后我们读取切点方法的第一个参数,并将其与CommonField类同名的字段进行设置。

 



import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * aop设置公共字段增强处理注解
 *
 * @author TenSunLee
 * @createdTime  2019/8/15 11点18分
 * @version 1.0.0
 * @updateBy TenSunLee
 * @updatedTime  2019/8/15 11点18分
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SetCommonField {
    /**
     * 标注方法类型
     * @return 方法类型字符串
     */
    String methodType();
}


import java.sql.Timestamp;
import java.util.List;

/**
 * 封装所有需要设置的公共字段类
 *
 * @author TenSunLee
 * @createdTime 2019/8/15 13点38分
 * @version 1.0.0
 * @updateBy TenSunLee
 * @updatedTime 2019/8/15 13点41分
 *
 */
public class CommonField {
    /**
     * 组织机构id
     */
    private Long orgId;
    /**
     * 公司id
     */
    private Long companyId;

    private Boolean manager;

    private Byte managerLevel;

    private List roles;
    /**
     * 创建人id
     */
    private Long createdBy;
    /**
     * 创建时间
     */
    private Timestamp createdTime;
    /**
     * 最后修改人id
     */
    private Long updatedBy;
    /**
     * 最后修改时间
     */
    private Timestamp updatedTime;

    @Override
    public String toString() {
        return "CommonField{" +
                "orgId=" + orgId +
                ", companyId=" + companyId +
                ", manager=" + manager +
                ", managerLevel=" + managerLevel +
                ", roles=" + roles +
                ", createdBy=" + createdBy +
                ", createdTime=" + createdTime +
                ", updatedBy=" + updatedBy +
                ", updatedTime=" + updatedTime +
                '}';
    }

    public Long getOrgId() {
        return orgId;
    }

    public void setOrgId(Long orgId) {
        this.orgId = orgId;
    }

    public Long getCompanyId() {
        return companyId;
    }

    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }

    public Boolean getManager() {
        return manager;
    }

    public void setManager(Boolean manager) {
        this.manager = manager;
    }

    public Byte getManagerLevel() {
        return managerLevel;
    }

    public void setManagerLevel(Byte managerLevel) {
        this.managerLevel = managerLevel;
    }

    public List getRoles() {
        return roles;
    }

    public void setRoles(List roles) {
        this.roles = roles;
    }

    public Long getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(Long createdBy) {
        this.createdBy = createdBy;
    }

    public Timestamp getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(Timestamp createdTime) {
        this.createdTime = createdTime;
    }

    public Long getUpdatedBy() {
        return updatedBy;
    }

    public void setUpdatedBy(Long updatedBy) {
        this.updatedBy = updatedBy;
    }

    public Timestamp getUpdatedTime() {
        return updatedTime;
    }

    public void setUpdatedTime(Timestamp updatedTime) {
        this.updatedTime = updatedTime;
    }
}


import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.reflect.FieldUtils;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

/**
 * 公共字段设置aspect
 *
 * @author TenSunLee
 * @version 1.0.0
 * @createdTime 2019/8/15 11:08
 * @updateBy TenSunLee
 * @updatedTime 2019/8/22 14:45
 */
@Aspect
@Component
public class CommonFieldAspect {
    /**
     * 注解所需参数值,表示类型为查询方法
     */
    public static final String TYPE_QUERY = "query";
    /**
     * 注解所需参数值,表示类型为删除方法
     */
    public static final String TYPE_DELETE = "delete";
    /**
     * 注解所需参数值,表示类型为插入方法
     */
    public static final String TYPE_INSERT = "insert";
    /**
     * 注解所需参数值,表示类型为更新方法
     */
    public static final String TYPE_UPDATE = "update";
    /**
     * 默认方法类型
     */
    private static final String DEFAULT_METHOD_TYPE = TYPE_UPDATE;

    private final RedisTemplate redisTemplate;

    @Autowired
    public CommonFieldAspect(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
        init();
    }

    /**
     * 设置redisTemplate采用stringSerializer
     */
    private void init(){
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
    }

    /**
     * 定义增强处理切入点为CommonField注解所注方法
     */
    @Pointcut("@annotation(com.bosssoft.bes.base.commonfield.annotation.SetCommonField)")
    public void commonFieldPoint() {
    }

    /**
     * 设置公共字段的方法
     *
     * @param joinPoint 连接点
     */
    @Before("commonFieldPoint()")
    public void setCommonField(JoinPoint joinPoint) throws ServiceException {
        //获取httprequest对象,解析参数获取CommonRequest中携带的请求用户id
        Long userId = getUserIdFromRequest();
        if(null == userId){
            throw new ServiceException(SystemExceptionEnum.SYSTEM_BASE_COMMON_FIELD_USER_NOT_FOUND_ON_REQUEST);
        }

        //通过userId获取相应字段值
        CommonField commonField = getCommonFieldByUserId(userId);

        //获取methodType
        String methodType = getMethodType(joinPoint);

        //根据方法类型从commonField对象中抽取不同字段设置进入切入点方法参数中
        int result = setFields(commonField, joinPoint, methodType);
    }

    /**
     * 根据methodType抽取不同的commonField中字段设置进切入点方法参数
     *
     * @param commonField 取到的公共字段值
     * @param joinPoint   连接点
     * @param methodType  所切方法类型
     * @return int 执行情况 0表示正常完成
     */
    private int setFields(CommonField commonField, JoinPoint joinPoint, String methodType) throws ServiceException {
        if (!TYPE_INSERT.equals(methodType)) {
            commonField.setCreatedBy(null);
            commonField.setCreatedTime(null);
            if (TYPE_QUERY.equals(methodType)) {
                commonField.setUpdatedBy(null);
                commonField.setUpdatedTime(null);
            }
            if (TYPE_UPDATE.equals(methodType)) {
                commonField.setOrgId(null);
                commonField.setCompanyId(null);
            }
        }
        //获取切点第一个参数
        Object[] args = joinPoint.getArgs();
        Object param = null;
        if (null != args) {
            param = args[0];
        }
        if (null == param) {
            return 1;
        }
        Field[] fields = FieldUtils.getAllFields(commonField.getClass());
        Field[] fieldParams = FieldUtils.getAllFields(param.getClass());
        //遍历CommonField所有字段
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                Object fieldValue = field.get(commonField);
                //字段非null时将其设值给切点参数param
                if (null != fieldValue) {
                    //获取param对应的setter方法后执行
                    String fieldName = field.getName();
                    //by lujinshan 循环遍历参数中是否存在需要被填充的字段
                    for (Field fieldParam : fieldParams) {
                        String fieldParamName = fieldParam.getName();
                        if (fieldName.equals(fieldParamName)) {
                            fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                            Method fieldSetter = null;
                            if (fieldParam.getType().getSimpleName().equals("Date")) {
                                fieldSetter = param.getClass().getMethod("set" + fieldName, Date.class);
                                fieldValue = new Date();
                            } else {
                                fieldSetter = param.getClass().getMethod("set" + fieldName, field.getType());
                            }
                            fieldSetter.invoke(param, fieldValue);
                        }
                    }

                }
            }
        } catch (Exception e) {
            throw new ServiceException(SystemExceptionEnum.SYSTEM_BASE_COMMON_FIELD_SET_ERROR);
        }
        return 0;
    }

    /**
     * 获取请求中的用户id
     *
     * @return 用户id, 未找到返回null
     */
    private Long getUserIdFromRequest() throws ServiceException {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder
                .getRequestAttributes())).getRequest();
        Long userId = Long.valueOf(request.getHeader("userId"));
        return userId;
    }

    /**
     * 根据用户id查找信息并封装到CommonField对象中返回
     *
     * @param userId 用户id
     * @return 需要设置的公共字段对象
     */
    private CommonField getCommonFieldByUserId(Long userId) throws ServiceException {
        String redisKey = "user_info_" + userId;

        ValueOperations valueOperations = redisTemplate.opsForValue();

        UserInfo userInfo = JSONObject.parseObject(String.valueOf(valueOperations.get(redisKey)),UserInfo.class);
        if (userInfo == null) {
            throw new ServiceException(SystemExceptionEnum.SYSTEM_BASE_COMMON_FIELD_USER_NOT_FOUND_ON_CACHE);
        }

        CommonField commonField = new CommonField();
        BeanUtils.copyProperties(userInfo,commonField);
        commonField.setOrgId(userInfo.getOrgId());
        commonField.setCompanyId(userInfo.getCompanyId());
        commonField.setCreatedBy(userInfo.getId());
        commonField.setCreatedTime(Timestamp.valueOf(LocalDateTime.now()));
        commonField.setUpdatedBy(userInfo.getId());
        commonField.setUpdatedTime(commonField.getCreatedTime());
        System.out.println(commonField);
        return commonField;
    }

    /**
     * 获取注解中指定的methodType
     *
     * @param joinPoint 连接点
     * @return 方法类型
     */
    private String getMethodType(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        SetCommonField commonFieldAnno = method.getAnnotation(SetCommonField.class);
        String methodType = DEFAULT_METHOD_TYPE;
        if (null != commonFieldAnno) {
            if (TYPE_UPDATE.equals(commonFieldAnno.methodType())) {
                methodType = TYPE_UPDATE;
            } else if (TYPE_QUERY.equals(commonFieldAnno.methodType())) {
                methodType = TYPE_QUERY;
            } else if (TYPE_INSERT.equals(commonFieldAnno.methodType())) {
                methodType = TYPE_INSERT;
            } else if (TYPE_DELETE.equals(commonFieldAnno.methodType())) {
                methodType = TYPE_DELETE;
            }
        }
        return methodType;
    }
}


/**
 * 角色表简略信息
 */
public class RoleSimpleInfo {
    protected Long id;

    protected Long orgId;

    protected Long companyId;

    protected String roleName;

    @Override
    public String toString() {
        return "RoleSimpleInfo{" +
                "id=" + id +
                ", orgId=" + orgId +
                ", companyId=" + companyId +
                ", roleName='" + roleName + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getOrgId() {
        return orgId;
    }

    public void setOrgId(Long orgId) {
        this.orgId = orgId;
    }

    public Long getCompanyId() {
        return companyId;
    }

    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
}
package com.bosssoft.bes.base.commonfield.aspect;

import java.io.Serializable;
import java.util.List;

/**
 *
 *
 * @author TenSunLee
 * @createdTime 2019/9/20 14:53
 * @version 1.0.0
 * @updateBy TenSunLee
 * @updatedTime 2019/9/20 14:53
 *
 */
public class UserInfo implements Serializable {
    protected Long id;

    protected Long companyId;

    protected Long orgId;

    protected Boolean manager;

    protected Byte managerLevel;

    protected List roles;

    public UserInfo() {
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "id=" + id +
                ", companyId=" + companyId +
                ", orgId=" + orgId +
                ", manager=" + manager +
                ", managerLevel=" + managerLevel +
                ", roles=" + roles +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getCompanyId() {
        return companyId;
    }

    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }

    public Long getOrgId() {
        return orgId;
    }

    public void setOrgId(Long orgId) {
        this.orgId = orgId;
    }

    public Boolean getManager() {
        return manager;
    }

    public void setManager(Boolean manager) {
        this.manager = manager;
    }

    public Byte getManagerLevel() {
        return managerLevel;
    }

    public void setManagerLevel(Byte managerLevel) {
        this.managerLevel = managerLevel;
    }

    public List getRoles() {
        return roles;
    }

    public void setRoles(List roles) {
        this.roles = roles;
    }
}

 

你可能感兴趣的:(公共字段自动填充aop)