其实我们在项目中可以发现我们在每一次的操作用户(添加,修改)用户的时候,都会对公共的字段进行更新,比如在添加用户的时候我们会对一下的字段进行更新
//用户的创建时间与更新时间
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//创建与更新用户的用户ID
employee.setCreateUser(empID);
employee.setUpdateUser(empID);
我们在更新用户的时候会对以下的字段进行更新
//更新当前的修改者
employee.setUpdateUser(empID);
//更新当前的修改时间
employee.setUpdateTime(LocalDateTime.now());
对用这种进行相同操作的公共字段我们可不可提取出来,单独的进行自动处理赖?没错我们的MyBatis-Plus举手说这个我可以,交给我。
我们的MP给我们提供了便捷的 公共字段自动填充 功能,可以直接将公共的字段提取出来,交付于我们的MP处理。
对于实现MP的自动填充我们需要的只有两步:
公共的字段中添加不同的更新处理注解
对应实体类的TableField注解添加
//表示插入时填充字段
@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; //修改者
创建自定义的MetaObjectHadler处理
@Controller
@Slf4j
public class MyMethObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段填充【insert】");
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("createUser", new Long(1l));
metaObject.setValue("updateUser", new Long(1l));
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段填充【update】");
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", new Long(1l));
}
}
这里其实我们的发现存在一个比较明显的问题的就是,我们无法获取用户的id信息
这里就需要引进一个ThreaLocal。在引入ThreaLocal之前我们先需要先观察确定一下,每一次客户端发送Http请求的时候,与之对应的会给服务端分配一个新的线程进行处理,因次在处理的过程当中,只要是涉及到config包下,自定义配置类中的方法都是数据同一个线程的处理。
为了验证,我们可以在每一个的类中都加入一个 提取当前的线程的id的方法,进行测试。
分别在以下类的调用的方法中加入 日志打印发现,调用者三个类时,调用的都是相同的一个线程
关于ThreadLocal方法的使用详解
public T get() { } // 用来获取ThreadLocal在当前线程中保存的变量副本
public void set(T value) { } //set()用来设置当前线程中变量的副本
public void remove() { } //remove()用来移除当前线程中变量的副本
protected T initialValue() { } //initialValue()是一个protected方法,一般是用来在使用时进行重写的
其实简单点来说就是,由于每一次的前端完整的一次请求,**LoginCheckFilter的doFilter**类中的方法都会启动一个新线程,并且该线程与
EmployeeController中的update ,MyMetaObjectHandler中的updateFill中启动的线程是同一个,因为我们可以通过**LoginCheckFilter的doFilter** ,为ThreadaLocal 设置一个当前的线程中的当前用户的副本,然后在**MyMetaObjectHandler**中取出当前用户
封装一个ThradLocal的对象获取类
public class BaseContext {
public static ThreadLocal<Long> threadLocal=new InheritableThreadLocal<>();
public Long getContextId(){
return threadLocal.get();
}
public void setContextId(Long id){
threadLocal.set(id);
}
}
对于分管理这部分其实与之前的部门管理之前没有什么大的区别,唯一需要注意的就是,我们的发现我们的后台解析**LocalDateTime**格式的数据时出现了问题,数据格式不再是 2022-08-17 10:37:37
的形式而是[2022, 8, 26, 17, 27, 28]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g6lmUBub-1661515318176)(C:\Users\Peggy\AppData\Roaming\Typora\typora-user-images\image-20220826194634780.png)]
这个是由于我们JSON在解析 **LocalDateTime**格式的数据时没有对于的序列化规则,所以采用的默认的序列化的规则,返回了一堆数组。解决的方式就是配置一个序列化的规则让其执行
当然其实也可以直接通过 **@JsonFormat(pattern = “yyyy年MM月dd日”)**的这种格式进行序列化
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue,
SerializerFeature.DisableCircularReferenceDetect
);
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
converters.add(0, fastJsonHttpMessageConverter);
}