MybatisPlus公共字段自动填充 与 同一线程数据可传输

180 阅读3分钟

一、MybatisPlus公共字段自动填充

1.1、问题分析

在对数据表进行新增或修改时,都需要指定 创建人(createUser)、创建时间(createTime)、修改人(updateUser)、修改时间(updateTime) 等公共字段,那有没有办法让这些字段在一个地方统一管理呢?从而简化我们的开发,答案就是使用MybatisPlus给我们提供的公共字段自动填充功能

1.2、代码实现

1.2.1、在实体类的属性上方加入@TableFiled注解,指定自动填充的策略

// 员工实体类
@Data
public class Employee implements Serializable {

    private String name;

    private String password;

    @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;
}

1.2.2、按照框架要求编写元数据对象处理器

定义 MyMetaObjectHandler 类,在此类中统一对公共字段赋值,此类需要实现MetaObjectHandler接口。实现接口之后,重写两个方法,一个是插入时填充,一个是修改时填充。关于字段填充方式,使用metaObject的setValue来实现。

// 自定义元数据对象处理器--createTime、updateTime、createUser、updateUser
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 插入insert时自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("createUser", BaseContext.getCurrentId());//同一线程取id
        metaObject.setValue("updateUser", BaseContext.getCurrentId());//同一线程取id
    }

    /**
     * 更新updata时自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());//同一线程取id
    }
}

1.2.3、关于id的获取

请看下节:同一线程数据可传输

二、同一线程数据可传输

2.1、问题分析

关于id的获取,之前是存到session里的,但在MyMetaObjectHandler类中不能获得HttpSession对象,所以我们需要用其他方式来获取登录用户Id。由此引出:同一线程数据可传输

2.2、统一线程

  • 在学习ThreadLocal之前,我们需要先确认一个事情,就是客户端发送的每次http请求,对应的在服务端都会分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都属于相同的一个线程:

    1. LocalCheekFilter中的doFilter方法
    2. EmployeeController中的update方法
    3. MyMetaObjectHandler中的updateFill方法

2.3、实现方法

可以在LoginCheckFilterdoFilter方法中获取当前登录用户id,并调用ThreadLocalset方法来设置当前线程的线程局部变量的值(用户id),然后在MyMetaObjectHandlerupdateFill方法中调用ThreadLocalget方法来获得当前线程所对应的线程局部变量的值(用户id)。

2.4、具体实现

2.4.1、在com.blog.common包下新建BaseContext类,作用:基于ThreadLocal的封装工具类,用于保护和获取当前用户id(同一线程传递数据)set、get

public class BaseContext {
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

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

    public static Long getCurrentId() {
        return threadLocal.get();
    }
}

2.4.2、随后在LoginCheckFilter类中添加代码,使用 request.getSession 来 存id(BaseContext.setICurrentId(empId))

//4、判断登录状态,如果已登录,则直接放行
if(request.getSession().getAttribute("employee") != null){
    log.info("用户已登录,id为{}",request.getSession().getAttribute("employee"));
    //同一线程存id
    Long empId = (Long) request.getSession().getAttribute("employee");
    BaseContext.setICurrentId(empId); //同一线程存id

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

2.4.3、在MyMetaObjectHandler类中,取id(BaseContext.getCurrentId())

// 自定义元数据对象处理器--createTime、updateTime、createUser、updateUser
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 插入insert时自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("createUser", BaseContext.getCurrentId());//同一线程取id
        metaObject.setValue("updateUser", BaseContext.getCurrentId());//同一线程取id
    }

    /**
     * 更新updata时自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());//同一线程取id
    }
}