Mybatis-Plus字段自动填充

500 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

今天在学习的时候,无意间了解到了mybatis-plus能够对数据库表的字段进行自动填充。在此做一个总结。

1.问题引入

我们的数据库表里面有些字段是相对固定的,比如更新时间,插入时间等。

image.png 我们每次修改数据,插入数据的时候都需要设置这些字段,这让我们觉得很烦。接下来,我向大家介绍mybatis-plus的解决方法。

2.解决办法

  1. 创建一个类,让这个类实现MetaObjectHandler
  2. 这个类用@Component标注
  3. 实现insertFill方法,这个方法在你进行插入操作的时候被触发,所以你可以在这个方法里设置公共字段的值。
  4. 实现updateFill方法,这个方法在你进行更新操作的时候被触发,所以你可以在这个方法里设置公共字段的值。
  5. insertFill和updateFill设置值的方式是利用MetaObject对象去调用setValue方法。setValue方法有2个参数,第一个参数是数据库字段的名字,第二个参数是写入数据库表的值。
  6. 找到对应数据库表的实体类,在代表公共字段的属性上,加上注解@TableField(fill = FieldFill.INSERT)插入时填充字段,@TableField(fill = FieldFill.INSERT_UPDATE) 插入和更新时填充字段

实现MetaObjectHandler的类

@Component
@Slf4j
public class MyMetaObjecthandler implements MetaObjectHandler {

    /**
     * 插入操作,自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充[insert]");
        log.info(metaObject.toString());
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("createUser", BaseContext.getCurrentId());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }

    /**
     * 更新操作自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]");
        log.info(metaObject.toString());

        long id = Thread.currentThread().getId();
        log.info("实现MetaObjectHandler,线程id为:{}",id);

        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }
}

实体类

@Data
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    private String username;

    private String name;

    private String password;

    private String phone;

    private String sex;

    private String idNumber;//身份证

    private Integer status;

    @TableField(fill = FieldFill.INSERT) //插入时填充字段
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE) //插入和更新时填充字段
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

}

经过上面的步骤,大家就可以实现公共字段的自动填充,以后只需要做别的数据的crud即可。*这时可能有同学会觉得有点麻烦,比如插入时间可以在mysql数据库里面设置timestamp?

如果只是时间的话,那其实可以不用这么麻烦的,直接设置timestamp,要是公共字段里面除了时间之外,还要求你设置更新人或者创建人呢?是不是用这种方式更加的方便,写一次就够了

3.插入更新人或者创建人信息的思路

可能有同学有疑问,怎么在实现MetaObjectHandler的类里面获取更新人或者创建人的信息,从而进行设置? 我的思路如下:

  1. 用ThreadLocal封装用户id(我们在数据库表里一般用id表明用户)
  2. 在实现MetaObjectHandler的类里获取封装的id
  3. 进行设置

为什么可以这样呢?因为你发起的同一个请求它触发的进程都是同一个。你可以在每个部分打印他们的id,如下图所示:

image.png

上面实现MetaObjectHandler的类里面的BaseContext.getCurrentId(),其实是封装的ThreadLocal的方法。具体代码如下:

public class BaseContext {
    //这个类有泛型,因为id是Long,所以这里设置的泛型是Long
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    //修饰id
    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    //取出修饰的id
    public static Long getCurrentId() {
        return threadLocal.get();
    }
}

接着我在登录的过滤器里面用ThreadLocal修饰用户id(各位同学不一定要在这里设置,看你自己的业务情况)

//4.判断登录状态,如果已登录,则直接放行
if (request.getSession().getAttribute("employee") != null){
    log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee"));

    //用ThreadLocal修饰用户id
    Long empId = (Long)request.getSession().getAttribute("employee");
    BaseContext.setCurrentId(empId);

    long id = Thread.currentThread().getId();
    log.info("过滤器中,线程id为:{}",id);

    filterChain.doFilter(request,response);
    return;
}

最后,在实现MetaObjectHandler的类里面取出这个id即可。