公共字段自动填充

公共字段自动填充

什么是公共字段自动填充?就是在插入和更新数据时,自动填充一些公共字段,比如创建时间、修改时间、创建人、修改人等。

实现方法

  1. 自定义注解 @AutoFill 用于标记需要自动填充公共字段的方法
  2. 自定义切面类 AutoFillAspect 用于拦截标记了 @AutoFill 注解的方法 通过反射为公共字段赋值
  3. Mapper 的方法上添加 @AutoFill 注解

技术点:枚举,反射,AOP,注解

示例代码

定义枚举 OperationType 用于标识操作类型(插入或更新)

1
2
3
4
5
// enumeration/OperationType.java
public enum OperationType {
UPDATE,
INSERT
}

定义注解 @AutoFill 用于标记需要自动填充公共字段的方法

1
2
3
4
5
6
7
8
// annotation/AutoFill.java

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
// 数据库操作类型 UPDATE/INSERT
OperationType value();
}

定义切面类 AutoFillAspect 用于拦截标记了 @AutoFill 注解的方法

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
// aspect/AutoFillAspect.java
@Aspect
@Component
public class AutoFillAspect {

// 拦截区域内被 @AutoFill 注解的方法
@Pointcut("execution(* com.example.mapper.*.*(..)) && @annotation(com.example.annotation.AutoFill)")
public void autoFillPointcut() {}

// 在方法执行前执行
@Before("autoFillPointcut()")
public void autoFill(JoinPoint joinPoint) {
log.info("开始自动填充公共字段...");

// 获取操作类型 INSERT/UPDATE
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 方法签名对象
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); // 获取方法上的 @AutoFill 注解对象
OperationType operationType = autoFill.value(); // 获取操作类型

// 获取方法参数
Object[] args = joinPoint.getArgs(); // 获取方法参数
if (args == null | args.length == 0) {
return;
}

Object entity = args[0]; // 获取实体对象

// 准备赋值数据
LocalDateTime now = LocalDateTime.now(); // 当前时间
Long currentId = BaseContext.getCurrentId(); // 当前用户ID(从ThreadLocal中获取)

// 反射赋值
if (operationType == OperationType.INSERT) {
Method setCreateTime = entity.getClass().getMethod("setCreateTime", LocalDateTime.class);
Method setCreateUser = entity.getClass().getMethod("setCreateUser", Long.class);
Method setUpdateTime = entity.getClass().getMethod("setUpdateTime", LocalDateTime.class);
Method setUpdateUser = entity.getClass().getMethod("setUpdateUser", Long.class);

setCreateTime.invoke(entity, now);
setCreateUser.invoke(entity, currentId);
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} else if (operationType == OperationType.UPDATE) {
Method setUpdateTime = entity.getClass().getMethod("setUpdateTime", LocalDateTime.class);
Method setUpdateUser = entity.getClass().getMethod("setUpdateUser", Long.class);

setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
}
}
}

(可选) 定义 AutoFillConstant 用于存放公共字段的常量

1
2
3
4
5
6
7
// constant/AutoFillConstant.java
public class AutoFillConstant {
public static final String SET_CREATE_TIME = "setCreateTime";
public static final String SET_CREATE_USER = "setCreateUser";
public static final String SET_UPDATE_TIME = "setUpdateTime";
public static final String SET_UPDATE_USER = "setUpdateUser";
}

Mapper 的方法上添加 @AutoFill 注解

1
2
3
4
5
6
7
// mapper/UserMapper.java
public interface UserMapper extends BaseMapper<User> {
// 插入用户
@Insert(...)
@AutoFill(OperationType.INSERT)
void insert(User user);
}

测试后发现成功实现了公共字段的自动填充…