开发者

MyBatis Plus实现时间字段自动填充的完整方案

目录
  • 前言
  • 解决目标
  • 技术栈
  • 实现步骤
    • 1. 实体类注解配置
    • 2. 创建元数据处理器
    • 3. 服务层代码优化
  • 填充机制详解
    • 创建记录时的填充过程http://www.devze.com
    • 更新记录时的填充过程
    • 数据库建议配置
  • 前后对比
    • 进阶扩展
      • 1. 支持更多字段类型
      • 2. 添加创建者和更新者自动填充
    • 常见问题与解决方案
      • 1. 字段没有自动填充
      • 2. 更新操作时创建时间被意外修改
      • 3. jsON 序列化时间格式问题
    • 总结
      • 优势
      • 核心实现

    前言

    在日常开发中,我们经常需要记录数据的创建时间和更新时间。传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏。本文将介绍如何使用 MyBATis Plus 的自动填充功能来优雅地解决这个问题。

    解决目标

    • 创建记录时自动设置 createTimeupdateTime
    • 更新记录时自动更新 updateTime,保持 createTime 不变
    • 无需手动编写时间设置代码
    • 统一的时间管理机制

    技术栈

    • 框架: Spring Boot + MyBatis Plus
    • 数据库: mysql
    • 实体管理: JPA 注解 + MyBatis Plus 注解

    实现步骤

    1. 实体类注解配置

    首先在实体类的时间字段上添加 MyBatis Plus 的自动填充注解:

    /**
     * 邮箱服务器实体类
     */
    @Entity
    @Table(name = "tbl_email_server")
    public class EmailServer extends BaseEntity {
        
        // 其他字段...
        
        /** 创建时间 */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        @TableField(fill = FieldFill.INSERT)
        private Date createTime;
    
        /** 更新时间 */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        @TableField(fill = FieldFill.INSERT_UPDATE)  
        private Date updateTime;
        
        // getter 和 setter 方法...
    }
    

    注解说明:

    • @TableField(fill = FieldFill.INSERT): 仅在插入操作时自动填充
    • @TableField(fill = FieldFill.INSERT_UPDATE): 在插入和更新操作时都自动填充
    • @JsonFormat: 指定 JSON 序列化时的日期格式

    2. 创建元数据处理器

    创建自定义的元数据处理器来实现具体的填充逻辑:

    package com.ruoyi.framework.config;
    
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    
    import Java.util.Date;
    
    /**
     * MyBatis Plus 字段自动填充处理器
     * 
     * @author ruoyi
     */
    @Component
    public class MyBatisMetaObjectHandler implements MetaObjectHandler {
    
        /**
         * 插入时的填充策略
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            Date now = new Date();
            
            // 插入时同时填充创建时间和更新时间
            this.strictInsertFill(metaObject, "createTime", Date.class, now);
            this.strictInsertFill(metaObject, "updateTime", Date.class, now);
        }
    
        /**
         * 更新时的填充策略  
         */
        @Override
        public void updateFill(MetaObject metaObject) {
            // 更新时仅填充更新时间
            this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
        }
    }
    

    核心方法说明:

    • insertFill(): 处理插入操作的字段填充
    • updateFill(): 处理更新操作的字段填充
    • strictInsertFill(): 严格插入填充,只有当字段值为 null 时才填充
    • strictUpdateFill(): 严格更新填充,只有当字段值为 null 时才填充

    3. 服务层代码优化

    移除原本手动设置时间的代码:

    修改前:

    @Override
    public int insertEmailServer(EmailServer emailServer) {
        // 手动设置时间字段
        emailServer.setCreateBy(SecurityUtils.getUsername());
        emailServer.setCreateTime(new Date());  // ❌ 需要移除
        emailServer.setUpdateTime(new Date());  // ❌ 需要移除
        return emailServerMapper.insertEmailServer(emailServer);
    }
    
    @Override
    public int updateEmailServer(EmailServer emailServer) {
        emailServer.setUpdateBy(SecurityUtils.getUsername());
        emailServer.setUpdateTime(new Date());  // ❌ 需要移除  
        return emailServerMapper.updateEmailS编程客栈erver(emailServer);
    }
    

    修改后:

    @Override
    public int insertEmailServer(EmailServer emailServer) {
        // 只设置创建者,时间字段由 MyBatis Plus 自动填充
        emailServer.setCreateBy(SecurityUtils.getUsername());
        return emailServerMapper.insertEmailServer(emailServer);
    }
    
    @Override
    public int updateEmailServer(EmailServer emailServer) {
        // 只设置更新者,更新时间由 MyBatis Plus 自动填充
        emailServer.setUpdateBy(SecurityUtils.getUsername());
        return emailServerMapper.updateEmailServer(emailServer);
    }
    

    填充机制详解

    创建记录时的填充过程

    // 执行插入操作
    EmailServer emailServer = new EmailServer();
    emailServer.setServerName("SMTP服务器");
    /js/ ... 设置其他业务字段
    
    // 调用 insertEmailServer 时,MyBatis Plus 会:
    // 1. 触发 insertFill 方法
    // 2. createTime = 2024-01-15 10:30:25  
    // 3. updateTime = 2024-01-15 10:30:25 (与创建时间相同)
    

    更新记录时的填充过程

    // 执行更新操作
    EmailServer emailServer = new EmailServer();
    emailServer.setServerId(1L);
    emailServer.setServerName("新的服务器名称");
    // ... 修改其他业务字段
    
    // 调用 updateEmailServer 时,MyBatis Plus 会:
    // 1. 触发 updateFill 方法
    // 2. createTime = 保持原值不变
    // 3. updateTime = 2024-01-15 14:25:30 (更新为当前时间)
    

    数据库建议配置

    虽然使用了注解自动填充,但建议在数据库层面也设置默认值作为双重保障:

    -- 为时间字段添加默认值
    ALTER TABLE tbl_email_server 
    MODIFY COLUMN create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间';
    
    ALTER TABLE tbl_email_server 
    MODIFY COLUMN update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间';
    

    前后对比

    对比项手动设置方式自动填充方式
    代码量每个方法都需要设置一次配置,全局生效
    维护性容易遗漏,难以统一统一管理,不易出错
    一致性依赖开发者自觉性自动保证一致性
    性能无额外性能消耗微小的反射开销

    进阶扩展

    1. 支持更多字段类型

    @Override
    public void insertFill(MetaObject metaObject) {
        Date now = new Date();
        
        // 支持 Date 类型
        this.strictInsertFill(metaObject, "createTime", Date.class, now);
        this.strictInsertFill(metaObject, "updateTime", Date.class, now);
        
        // 支持 LocalDateTime 类型
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        
        // 支持时间戳
        this.strictInsertFill(metaObject, "createTime", Long.class, System.currentTimeMillis());
    }
    

    2. 添加创建者和更新者自动填充

    @Override
    public void insertFill(MetaObject metaObject) {
        Date now = new Date();
        String currentUser = getCurrentUser(); // 获取当前用户
        
        // 时间字段填充
        this.strictInsertFill(metaObject, "createTime", Date.class, now);
        this.strictInsertFill(metaObject, "updateTime", Date.class, now);
        
        // 用户字段填充
        this.strictInsertFill(metaObject, "createBy", String.class, currentUser);
        this.strijsctInsertFill(metaObject, "updateBy", String.class, currentUser);
    }
    
    @OverrXcgvqtcehide  
    public void updateFill(MetaObject metaObject) {
        String currentUser = getCurrentUser();
        
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
        this.strictUpdateFill(metaObject, "updateBy", String.class, currentUser);
    }
    
    private String getCurrentUser() {
        try {
            return SecurityUtils.getUsername();
        } catch (Exception e) {
            return "system"; // 默认用户
        }
    }
    

    常见问题与解决方案

    1. 字段没有自动填充

    可能原因:

    • 实体类字段名与数据库列名不匹配
    • 忘记添加 @TableField 注解
    • MetaObjectHandler 没有被 Spring 管理

    解决方案:

    // 确保字段名正确映射
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Date createTime;
    
    // 确保处理器被 Spring 管理
    @Component  // 必须添加此注解
    public class MyBatisMetaObjectHandler implements MetaObjectHandler {
        // ...
    }
    

    2. 更新操作时创建时间被意外修改

    解决方案:

    // 使用 FieldFill.INSERT 而不是 INSERT_UPDATE
    @TableField(fill = FieldFill.INSERT)  // ✅ 正确
    private Date createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)  // ✅ 正确
    private Date updateTime;
    

    3. JSON 序列化时间格式问题

    解决方案:

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    

    总结

    MyBatis Plus 的自动填充功能为我们提供了一个优雅的解决方案来管理时间字段:

    优势

    1. 自动化: 无需手动编写重复的时间设置代码
    2. 统一性: 全局统一的时间填充策略
    3. 可靠性: 避免了人为遗漏设置时间的问题
    4. 扩展性: 可以轻松扩展到其他字段的自动填充

    核心实现

    1. 在实体类时间字段添加 @TableField 注解
    2. 创建实现 MetaObjectHandler 接口的处理器
    3. 在处理器中实现 insertFillupdateFill 方法
    4. 移除服务层中的手动时间设置代码

    这种方案不仅提升了开发效率,还增强了代码的可维护性和一致性。在实际项目中,建议结合数据库默认值设置,形成双重保障机制。

    以上就是MyBatis Plus实现时间字段自动填充的完整方案的详细内容,更多关于MyBatis Plus时间字段自动填充的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜