
01痛点速览
            
            
              java
              
              
            
          
          // 每写一个 Service 就要来一遍
order.setCreateTime(LocalDateTime.now());
order.setUpdateTime(LocalDateTime.now());
order.setCreateUser(getCurrentUser());
order.setUpdateUser(getCurrentUser());
        总结:
- Ctrl C + Ctrl V 到手抽筋
 - 一改字段,全局爆炸
 - 一不留神就漏填
 
02方案 1MyBatis-Plus 元对象处理器
最香基础款
2.1 核心代码
            
            
              java
              
              
            
          
          @Slf4j
@Component
public class AutoFillHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // 新增时填充
        strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        strictInsertFill(metaObject, "createUser", String.class, getCurrentUser());
        strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        strictInsertFill(metaObject, "updateUser", String.class, getCurrentUser());
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时只刷新 update*
        strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        strictUpdateFill(metaObject, "updateUser", String.class, getCurrentUser());
    }
    /** 从 Security 上下文里拿登录人 */
    private String getCurrentUser() {
        return Optional.ofNullable(SecurityContextHolder.getContext())
                       .map(SecurityContext::getAuthentication)
                       .map(Authentication::getName)
                       .orElse("system");
    }
}
        注解:
- 实现 MetaObjectHandler,MyBatis-Plus 会自动回调
 - strictInsertFill 只在 insert 语句里生效
 - 使用 Optional 防 NPE,稳!
 
2.2 实体类配上注解
            
            
              java
              
              
            
          
          @Data
public abstract class BaseEntity {
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableField(fill = FieldFill.INSERT)
    private String createUser;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updateUser;
}
@Entity
@Table(name = "t_order")
public class Order extends BaseEntity { }
        03方案 2:AOP 切面
专治各种不服
3.1 自定义注解,声明式零侵入
            
            
              java
              
              
            
          
          @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    OperationType value();   // INSERT / UPDATE
}
public enum OperationType {
    INSERT, UPDATE
}
        3.2 切面逻辑
            
            
              java
              
              
            
          
          @Aspect
@Component
@Slf4j
public class AutoFillAspect {
    @Around("@annotation(autoFill)")
    public Object around(ProceedingJoinPoint pjp, AutoFill autoFill) throws Throwable {
        Object[] args = pjp.getArgs();
        for (Object arg : args) {
            if (arg instanceof BaseEntity) {
                fill((BaseEntity) arg, autoFill.value());
            }
        }
        return pjp.proceed(args);
    }
    private void fill(BaseEntity entity, OperationType type) {
        String user = getCurrentUser();
        LocalDateTime now = LocalDateTime.now();
        if (type == OperationType.INSERT) {
            entity.setCreateTime(now);
            entity.setCreateUser(user);
        }
        entity.setUpdateTime(now);
        entity.setUpdateUser(user);
    }
    private String getCurrentUser() {
        return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                       .map(ServletRequestAttributes.class::cast)
                       .map(ServletRequestAttributes::getRequest)
                       .map(req -> req.getHeader("X-User-Id"))
                       .orElse("system");
    }
}
        注解:
- @Around 拦截所有标注 @AutoFill 的方法
 - 统一在进入方法前就把字段塞满
 - 支持多参数批量处理,一行注解搞定
 
04方案 3:分布式 ID + 多数据源
4.1 Snowflake 发号器
            
            
              java
              
              
            
          
          @Configuration
public class SnowflakeConfig {
    @Bean
    public SnowflakeIdWorker idWorker(@Value("${snowflake.workerId}") long workerId,
                                      @Value("${snowflake.dataCenterId}") long dataCenterId) {
        return new SnowflakeIdWorker(workerId, dataCenterId);
    }
}
        4.2 多数据源下自动填充
            
            
              java
              
              
            
          
          public class MultiDataSourceAutoFillHandler extends MetaObjectHandler {
    @Autowired
    private SnowflakeIdWorker idWorker;
    @Override
    public void insertFill(MetaObject metaObject) {
        super.insertFill(metaObject);
        // 分布式主键
        strictInsertFill(metaObject, "id", Long.class, idWorker.nextId());
    }
}
        05方案 4:性能优化三板斧
5.1 ThreadLocal 缓存当前用户
            
            
              java
              
              
            
          
          public class UserContextHolder {
    private static final ThreadLocal<String> holder = new ThreadLocal<>();
    public static void set(String user) { holder.set(user); }
    public static String get() { return holder.get(); }
    public static void clear() { holder.remove(); }
}
public class UserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) {
        UserContextHolder.set(req.getHeader("X-User-Id"));
        return true;
    }
    @Override
    public void afterCompletion(...) {
        UserContextHolder.clear();   // 防止内存泄漏
    }
}
        5.2 批量操作统一时间
            
            
              java
              
              
            
          
          @Transactional
public void batchInsert(List<Order> orders) {
    String user = UserContextHolder.get();
    LocalDateTime now = LocalDateTime.now();
    orders.forEach(o -> {
        o.setCreateTime(now);
        o.setCreateUser(user);
        o.setUpdateTime(now);
        o.setUpdateUser(user);
    });
    orderMapper.batchInsert(orders);
}
        06方案 5:监控 + 审计
6.1 切面记录操作日志
            
            
              java
              
              
            
          
          @Aspect
@Component
public class OperationLogAspect {
    @AfterReturning("@annotation(autoFill)")
    public void log(AutoFill autoFill) {
        LogEntry log = new LogEntry();
        log.setOperator(UserContextHolder.get());
        log.setOperation(autoFill.value().name());
        log.setTime(LocalDateTime.now());
        logService.save(log);
    }
}
        避坑指南

总结
MyBatis-Plus 打底,AOP 做加持,Snowflake 管 ID,ThreadLocal 提性能,切面搞审计