一、为什么需要自动填充几乎每个业务系统里面数据库都有几个“公共字段”。比较典型的就是create_time / createTime创建时间update_time / updateTime更新时间create_user / createUser创建人update_user / updateUser更新人然后每次创建更新都要进行重复操作public void insert(Employee employee) { employee.setCreateTime(LocalDateTime.now()); employee.setUpdateTime(LocalDateTime.now()); employee.setCreateUser(BaseContext.getCurrentId()); employee.setUpdateUser(BaseContext.getCurrentId()); employeeMapper.insert(employee); } public void update(Employee employee) { employee.setUpdateTime(LocalDateTime.now()); employee.setUpdateUser(BaseContext.getCurrentId()); employeeMapper.update(employee); }这样写耦合度高维护成本高。所以才有了自动填充的设计。二、方案设计核心思路自定义注解在 Mapper 层的方法上打标记通过 AOP 拦截利用反射自动给实体对象赋值。为此需要准备4个东西组件作用OperationType 枚举标记是 INSERT 还是 UPDATEAutoFill 自定义注解打在 Mapper 方法上标明操作类型AutoFillConstant 常量类统一管理 setter 方法名AutoFillAspect 切面类拦截带 AutoFill 的方法反射赋值三、核心代码实现1. 操作类型枚举public enum OperationType { UPDATE, // 更新操作 INSERT // 插入操作 }只有两种情况用枚举约束死不会出现奇怪的值。2. 自定义注解Target({ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) public interface AutoFill { OperationType value(); // INSERT 或 UPDATE }Target(ElementType.METHOD) 表示只能用在方法上Retention(RUNTIME) 表示运行时能通过反射读取到。3. 常量类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; }把方法名抽成常量避免反射时写错字符串也方便后续维护。4. AOP 切面核心Aspect Component Slf4j public class AutoFillAspect { // 拦截 com.sky.mapper 包下所有带 AutoFill 注解的方法 Pointcut(execution(* com.sky.mapper.*.*(..)) annotation(com.sky.annotation.AutoFill)) public void autoFillPointCut() {} Before(autoFillPointCut()) public void autoFill(JoinPoint joinPoint) { log.info(开始进行公共字段自动填充); // 1. 获取方法上的注解判断是 INSERT 还是 UPDATE 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; Object entity args[0]; // 3. 准备数据 LocalDateTime now LocalDateTime.now(); Long currentId BaseContext.getCurrentId(); // 从 ThreadLocal 取当前登录用户ID // 4. 通过反射调用 setter 赋值 if (operationType OperationType.INSERT) { Method setCreateTime entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class); Method setUpdateTime entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setCreateUser entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class); Method setUpdateUser entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); setCreateTime.invoke(entity, now); setUpdateTime.invoke(entity, now); setCreateUser.invoke(entity, currentId); setUpdateUser.invoke(entity, currentId); } else if (operationType OperationType.UPDATE) { 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); } } }流程说明首先利用Pointcut定义切入点execution(* com.sky.mapper.*.*(..))表示mapper包中的所有方法annotation(com.sky.annotation.AutoFill)表示有AutoFill注解的方法。然后用Before 前置通知在方法执行前自动填充字段。在autoFill方法中需要先判断方法上的注解的value值用于确定进行什么操作。由于我们是在给一个对象填充属性所以我们需要先获取这个对象。在这里我们约定mapper中的方法参数的第一个就是操作对象通过getArgs方法获取所有参数定义Object类型的变量承载对象。然后我们需要获取对象类中的修改属性的具体方法。最后调用方法进行赋值。四、怎么使用在 Mapper 层的方法上加注解即可AutoFill(OperationType.INSERT) Insert(insert into employee (...) values (...)) void insert(Employee employee); AutoFill(OperationType.UPDATE) Update(update employee set ... where id #{id}) void update(Employee employee);然后 Service 层里直接调用完全不需要手动 setpublic void addEmployee(EmployeeDTO dto) { Employee employee new Employee(); BeanUtils.copyProperties(dto, employee); // 不需要 setCreateTime、setCreateUser 了 employeeMapper.insert(employee); }五、总结对比手动 setAOP 自动填充代码量每个方法复制粘贴一处实现全局生效可维护性改个字段名要全局搜索替换只改常量类遗漏风险容易忘不会耦合度业务代码和公共逻辑混在一起彻底解耦这套方案本质上是用 AOP 把横切关注点公共字段填充从业务逻辑中剥离出来是 Spring AOP 非常典型的应用场景。如果你也在写类似的增删改系统强烈推荐试试这个方案代码会干净很多。