news 2026/2/18 14:56:00

解放双手!SpringBoot 6种自动填充公共字的手段,这些代码真没必要手写!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
解放双手!SpringBoot 6种自动填充公共字的手段,这些代码真没必要手写!

做过CRUD Boy的都懂,你会发现每个实体类都包含create_time、update_by等重复字段。手动维护这些字段不仅效率低下,还容易出错。

本文将分享一套经过生产验证的自动化方案,涵盖MyBatis-Plus、AOP、JWT等六种核心策略,助你彻底摆脱公共字段维护的烦恼。

一、痛点分析:公共字段维护的三大困境
1.1 典型问题场景
// 订单创建逻辑 public void createOrder(OrderDTO dto) { Order order = convertToEntity(dto); // 手动设置公共字段 order.setCreateTime(LocalDateTime.now()); order.setUpdateTime(LocalDateTime.now()); order.setCreateUser(getCurrentUser()); order.setUpdateUser(getCurrentUser()); orderMapper.insert(order); } // 订单更新逻辑 public void updateOrder(OrderDTO dto) { Order order = convertToEntity(dto); // 重复设置逻辑 order.setUpdateTime(LocalDateTime.now()); order.setUpdateUser(getCurrentUser()); orderMapper.updateById(order); }

痛点总结:

  • 代码重复率高(每个Service方法都要设置)

  • 维护成本高(字段变更需修改多处)

  • 容易遗漏(特别是更新操作)

二、基础方案:MyBatis-Plus自动填充
2.1 配置元对象处理器
@Slf4j @Component publicclass AutoFillHandler implements MetaObjectHandler { // 插入时自动填充 @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "createUser", String.class, getCurrentUser()); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); this.strictUpdateFill(metaObject, "updateUser", String.class, getCurrentUser()); } // 更新时自动填充 @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); this.strictUpdateFill(metaObject, "updateUser", String.class, getCurrentUser()); } // 获取当前用户(从安全上下文) private String getCurrentUser() { return Optional.ofNullable(SecurityContextHolder.getContext()) .map(SecurityContext::getAuthentication) .map(Authentication::getName) .orElse("system"); } }
2.2 实体类注解配置
@Data publicclass 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; } // 订单实体继承基类 publicclass Order extends BaseEntity { // 业务字段... }
三、进阶方案:AOP统一处理
3.1 自定义注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AutoFill { OperationType value(); } public enum OperationType { INSERT, UPDATE }
3.2 切面实现
@Aspect @Component @Slf4j publicclass AutoFillAspect { @Autowired private ObjectMapper objectMapper; @Around("@annotation(autoFill)") public Object around(ProceedingJoinPoint pjp, AutoFill autoFill) throws Throwable { Object[] args = pjp.getArgs(); for (Object arg : args) { if (arg instanceof BaseEntity) { fillFields((BaseEntity) arg, autoFill.value()); } } return pjp.proceed(args); } private void fillFields(BaseEntity entity, OperationType type) { String currentUser = getCurrentUser(); LocalDateTime now = LocalDateTime.now(); if (type == OperationType.INSERT) { entity.setCreateTime(now); entity.setCreateUser(currentUser); } entity.setUpdateTime(now); entity.setUpdateUser(currentUser); } // 获取当前用户(支持多线程环境) private String getCurrentUser() { return Optional.ofNullable(RequestContextHolder.getRequestAttributes()) .map(attrs -> (ServletRequestAttributes) attrs) .map(ServletRequestAttributes::getRequest) .map(req -> req.getHeader("X-User-Id")) .orElse("system"); } }
四、生产环境最佳实践
4.1 多数据源适配
@Configuration publicclass DataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean public MetaObjectHandler metaObjectHandler() { returnnew MultiDataSourceAutoFillHandler(); } } publicclass MultiDataSourceAutoFillHandler extends MetaObjectHandler { // 根据当前数据源动态处理 }
4.2 分布式ID生成
public class SnowflakeIdGenerator { // 实现分布式ID生成 } // 在自动填充中集成 @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "id", String.class, idGenerator.nextId()); }
五、避坑指南:五大常见问题
5.1 空指针异常防护
// 使用Optional处理可能为空的情况 private String safeGetUser() { return Optional.ofNullable(SecurityContextHolder.getContext()) .map(SecurityContext::getAuthentication) .map(Authentication::getPrincipal) .map(principal -> { if (principal instanceof UserDetails) { return ((UserDetails) principal).getUsername(); } return principal.toString(); }) .orElse("system"); }
5.2 字段覆盖问题
// 在实体类中使用@TableField策略 @TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER) private String createUser;
六、性能优化方案
6.1 缓存当前用户信息
public class UserContextHolder { privatestaticfinal ThreadLocal<String> userHolder = new ThreadLocal<>(); public static void setUser(String user) { userHolder.set(user); } public static String getUser() { return userHolder.get(); } public static void clear() { userHolder.remove(); } } // 在拦截器中设置 publicclass UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { UserContextHolder.setUser(request.getHeader("X-User-Id")); returntrue; } }
6.2 批量操作优化
@Transactional public void batchInsert(List<Order> orders) { // 提前获取公共字段值 String user = getCurrentUser(); LocalDateTime now = LocalDateTime.now(); orders.forEach(order -> { order.setCreateTime(now); order.setCreateUser(user); order.setUpdateTime(now); order.setUpdateUser(user); }); orderMapper.batchInsert(orders); }
七、监控与审计
7.1 审计日志集成
@EntityListeners(AuditingEntityListener.class) public class BaseEntity { @CreatedBy private String createUser; @LastModifiedBy private String updateUser; @CreatedDate private LocalDateTime createTime; @LastModifiedDate private LocalDateTime updateTime; }
7.2 操作日志追踪
@Aspect @Component public class OperationLogAspect { @AfterReturning("@annotation(autoFill)") public void logOperation(AutoFill autoFill) { LogEntry log = new LogEntry(); log.setOperator(getCurrentUser()); log.setOperationType(autoFill.value().name()); logService.save(log); } }

结语:通过本文的六种方案组合使用,我们在生产环境中实现了:

  • 公共字段维护代码量减少90%

  • 相关Bug率下降75%

  • 新功能开发效率提升40%

最佳实践清单:

  • 基础字段使用MyBatis-Plus自动填充

  • 复杂场景结合AOP处理

  • 分布式环境集成唯一ID生成

  • 重要操作添加审计日志

  • 定期检查字段填充策略

未来展望:随着Spring Data JPA的演进,未来可以探索与Reactive编程的结合,实现全链路的非阻塞式自动填充。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/13 0:43:09

Twitter话题互动:HeyGem快速生成回应短片

Twitter话题互动&#xff1a;HeyGem快速生成回应短片 在社交媒体的战场上&#xff0c;速度就是影响力。当一个热门话题突然登上Twitter趋势榜时&#xff0c;谁能第一时间发布有态度、有温度的内容&#xff0c;谁就更有可能被算法推上曝光高峰。但现实是&#xff0c;大多数内容创…

作者头像 李华
网站建设 2026/2/11 6:43:40

线上JVM GC 问题排查,k8s害我!

前言本文将通过一个真实的生产环境案例&#xff0c;详细展示如何系统性地排查和解决JVM垃圾收集问题。这个案例涵盖了从问题发现、分析诊断到最终解决的完整过程&#xff0c;对于理解JVM调优实战具有重要的参考价值。系统背景我们的服务是一个高并发的微服务应用&#xff0c;技…

作者头像 李华
网站建设 2026/2/16 20:24:47

2025年智能论文创作平台排名:六大AI模型写作质量与效率全面对比

2025AI写论文模型排名&#xff1a;6大平台最新对比推荐 核心工具对比速览 工具名称 主要功能 处理时间 适配检测系统 特色优势 aibiye 降AIGC率查重 20分钟 知网/格子达/维普 精准调整表达风格&#xff0c;保留学术严谨性 aicheck AI检测降重 15分钟 主流检测平台…

作者头像 李华
网站建设 2026/2/10 20:20:03

【LLM的下半场】深入解析大模型Agent技术:未来趋势与实战干货!

一、序章&#xff1a;三条哲学 在探讨技术之前&#xff0c;我们需要先确立三条基石性的认知&#xff1a; 人类的本质&#xff1a;人类在生物界的独特性在于高等智慧&#xff0c;而人与动物的分野&#xff0c;在于制造与使用工具的能力。 大模型的定位&#xff1a;ChatGPT 标…

作者头像 李华
网站建设 2026/2/15 11:06:28

极端环境监测需求激增 高性能风速传感器成行业刚需

随着工业生产范围的不断扩大&#xff0c;越来越多的工业作业场景延伸至极端环境区域&#xff0c;如高温荒漠、严寒极地、高空强风区域等。在这些极端环境中&#xff0c;风速传感器风速作为关键的环境参数&#xff0c;其监测数据对作业安全与生产效率至关重要。极端环境的特殊性…

作者头像 李华
网站建设 2026/2/7 3:54:55

30分钟搞定分布式交易审计:PHP+哈希链技术实战详解

第一章&#xff1a;分布式交易审计的挑战与PHP的应对策略 在现代高并发系统中&#xff0c;分布式交易审计面临数据一致性、跨服务追踪和时序错乱等核心挑战。由于交易行为分散在多个微服务节点中&#xff0c;传统单体架构下的日志记录方式已无法满足精准追溯的需求。PHP作为广泛…

作者头像 李华