公共字段自动填充

介绍了在Spring项目中利用自定义切面类与注解完成字段自动填充

公共字段自动填充

在不同的业务表中会有一些公共字段,如创建时间、修改时间、创建人、修改人等

如果每次都在service实现类中手动设置,会造成代码冗余,不便于后期维护

image-20251014112846262

可以使用自定义注解和自定义切面类来优化

  • 自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法

  • 自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

  • 在 Mapper 的方法上加入 AutoFill 注解

实现

1.自定义注解AutoFill

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解,用于标记某个方法需要进行功能字段自动填充
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    // 标识操作类型 (INSERT 或 UPDATE)
    OperationType value();
}

其中的OperationType是一个自定义的枚举类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public enum OperationType {
    /**
     * 更新操作
     */
    UPDATE,
    /**
     * 插入操作
     */
    INSERT
}

2.自定义切面AutoFillAspect

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
 * 自定义切面,实现公共字段的自动填充
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {}

    /**
     * 前置通知,在通知中实现公共字段的自动填充
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("公共字段自动填充...");
        // 1.获取当前拦截方法的操作类型
        // 获取拦截方法的签名对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取方法上的注解对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
        // 获取操作类型
        OperationType operationType = autoFill.value();

        // 2.获取当前拦截方法的参数,即实体对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }
        // 获取实体对象(Mapper方法有多个参数时,一般把实体放在第一位)
        Object entity = args[0];

        // 3.准备公共字段的值
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        // 4.根据操作类型,进行不同的自动填充
        if (operationType == OperationType.INSERT) {
            try {
                // 获取实体对象的set方法
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //通过反射为对象属性赋值
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,currentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else if (operationType == OperationType.UPDATE) {
            try {
                // 获取实体对象的set方法
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //通过反射为对象属性赋值
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

其中AutoFillConstant是自定义的常量类,方便统一管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/**
 * 公共字段自动填充相关常量
 */
public class AutoFillConstant {
    /**
     * 实体类中的方法名称
     */
    public static final String SET_CREATE_TIME = "setCreateTime";
    public static final String SET_UPDATE_TIME = "setUpdateTime";
    public static final String SET_CREATE_USER = "setCreateUser";
    public static final String SET_UPDATE_USER = "setUpdateUser";
}

3.在Mapper接口的方法上加上AutoFill注解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Mapper
public interface EmployeeMapper {
    /**
     * 插入员工数据
     * @param employee
     */
    @Insert("insert into ...略")
    @AutoFill(value = OperationType.INSERT)
    void insert(Employee employee);

    /**
     * 修改员工信息
     * @param employee
     */
    @AutoFill(value = OperationType.UPDATE)
    void update(Employee employee);
}

优化后记得把原本写在service实现类中的设置公共字段参数代码删除掉

本站于2025年3月26日建立
使用 Hugo 构建
主题 StackJimmy 设计