本文讲述了在SpringBoot 中使用Mybatis Plus如何实现一个自动填充功能。
平时在建数据表的时候都会有创建时间、创建者、修改时间和修改者这四个字段,对于这些大部分表都有的字段,每次在新增和修改的时候都要考虑到这几个字段有没有传进去,很麻烦。mybatisPlus有一个很好的解决方案。也就是公共字段自动填充的功能。
一般满足下面条件的字段就可以使用此功能:
(1)这个字段是大部分表都会有的;
(2)这个字段的值是固定的,或则字段值是可以在后台动态获取的。
阿里巴巴开发手册中也有这样的提示,如果对于这些公共字段可以进行统一处理,不需要每次进行插入或者更新操作的时候 set 一下,就可以提高开发效率,解放双手。
自动填充功能的主要使用步骤:
(1)新建一个表t_user增加create_time(创建时间)、create_user(创建者)、update_time(修改时间)、update_user(修改者) 等字段。
(2)需要在填充的公共字段上面添加@TableField注解
(3)自定义实现类 MyMetaObjectHandler,重写insertFill、updateFill方法 方法中设置created_time、updated_time等的值
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`age` int(10) DEFAULT NULL COMMENT '年龄',
`remarks` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_user` varchar(255) DEFAULT NULL COMMENT '创建人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_user` varchar(255) DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户信息表';
pom.xml配置如下:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.3version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.20version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.20version>
dependency>
application.yml(若没有,则在src/main/resources/下面新建此文件):
# 服务端口
server:
port: 8083
# 数据源配置
spring:
datasource:
name: test
url: jdbc:mysql://localhost:3306/db_user?&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSl=false
username: root
password:
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
## 配置连接池信息
## 初始化大小,最小,最大
initialSize: 5
minIdle: 5
maxActive: 30
## 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 超过时间限制是否回收
removeAbandoned: true
# 超时时间;单位为秒。180秒=3分钟
removeAbandonedTimeout: 180
# 关闭abanded连接时输出错误日志
logAbandoned: true
# mybatis-plus 默认扫描mapper.xml的目录
mybatis-plus:
mapper-locations: classpath*:/mapper/*.xml
#配置sql打印日志
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
创建一个实体类,然后在需要自动填充的属性上加注解 @TableField(fill = FieldFill.INSERT)、@TableField(fill = FieldFill.INSERT_UPDATE) 等注解。
package com.example.autofilldemo.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* @author qzz
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 用户id
*/
@TableId(value="id", type = IdType.AUTO)
private Integer id;
/**
* 名称
*/
@TableField("name")
private String name;
/**
* 年龄
*/
@TableField("age")
private Integer age;
/**
* 备注
*/
@TableField("remarks")
private String remarks;
/**
* 创建者
*/
@TableField(value = "create_user", fill = FieldFill.INSERT)
private String create_user;
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date create_time;
/**
* 修改时间
*/
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Date update_time;
/**
* 修改者id
*/
@TableField(value = "update_user", fill = FieldFill.INSERT_UPDATE)
private String update_user;
}
其中 fill 属性为字段自动填充策略,可选的参数如下所示:
package com.example.autofilldemo.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.autofilldemo.entity.User;
import org.springframework.stereotype.Repository;
/**
* @author qzz
*/
@Repository
public interface UserMapper extends BaseMapper<User> {
}
创建自定义实现类MyMetaObjectHandler 实现 MetaObjectHandler 接口,重写insertFill和updateFill方法
注意:
MyBatis Plus 版本不同,实现方式可能会有些许不同,在 3.3.0以上版本是实现 MetaObjectHandler接口,低版本可能是继承 MetaObjectHandler 抽象类,来实现对应的方法。
下面为实现插入和更新数据的字段填充逻辑,在插入对象时,对创建时间 create_time和修改时间 update_time自动填充为当前时间,创建者update_user、修改者update_user字段自动填充为当前用户id,在更新对象时,将修改时间 update_time修改为最新时间,修改者为当前用户id。
package com.example.autofilldemo.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 配置mybatis-plus自动填充类
* @author qzz
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ......");
this.fillStrategy(metaObject,"create_time", new Date());
this.fillStrategy(metaObject,"update_time", new Date());
this.setFieldValByName("create_user",getCurrentUserId(),metaObject);
this.setFieldValByName("update_user",getCurrentUserId(),metaObject);
log.info("end insert fill ......");
}
/**
* 修改填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ......");
this.fillStrategy(metaObject,"update_time", new Date());
this.fillStrategy(metaObject,"update_user", getCurrentUserId());
log.info("end update fill ......");
}
/**
* 获取当前用户id
* @return
*/
private String getCurrentUserId() {
return "1";
}
}
其中,默认填充策略为默认有值不覆盖,如果提供的值为 null 也不填充。
编写用户添加和编辑方法,检验是否在插入和更新操作时,是否会自动填充响应的字段。
package com.example.autofilldemo.controller;
import com.example.autofilldemo.dao.UserMapper;
import com.example.autofilldemo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @author qzz
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
/**
* 添加用户信息
*/
@PostMapping("add")
public Map<String,Object> addProduct(@RequestBody User user){
Map<String,Object> result = new HashMap<>();
int n = userMapper.insert(user);
if(n>0){
result.put("code","200");
result.put("id",user.getId());
}else{
result.put("code","400");
result.put("msg","添加用户失败");
}
return result;
}
/**
* 编辑商品信息
*/
@PostMapping("update")
public Map<String,Object> updateProduct(@RequestBody User user){
Map<String,Object> result = new HashMap<>();
int n = userMapper.updateById(user);
if(n>0){
result.put("code","200");
}else{
result.put("code","400");
result.put("msg","编辑用户失败");
}
return result;
}
}
启动项目,借助postman工具,测试:
(1)添加一个用户信息到数据库,可以看到并没有设置create_time、update_time、create_user和update_user,但程序会自动填充到数据库:
控制台打印信息:
数据库表数据结果:
说明用户新增时,创建时间、创建者、修改时间和修改者自动填充成功!
(2)编辑一个用户信息,同样可以看下update_time和update_user自动填充到数据库:
控制台打印信息如下:
查看数据库表数据信息:
用户更新时,修改时间和修改者自动填充成功!
另外,可以将公共字段封装到公共类中,比如BaseEntity,其他的实体类可以继承这个公共类,达到代码复用,减少冗余的效果:
package com.example.autofilldemo.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.util.Date;
/**
* 公共字段
* @author qzz
*/
@Data
public class BaseEntity {
/**
* 创建者
*/
@TableField(value = "create_user", fill = FieldFill.INSERT)
private String create_user;
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date create_time;
/**
* 修改时间
*/
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Date update_time;
/**
* 修改者id
*/
@TableField(value = "update_user", fill = FieldFill.INSERT_UPDATE)
private String update_user;
}
package com.example.autofilldemo.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* @author qzz
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_user")
public class User extends BaseEntity implements Serializable{
private static final long serialVersionUID = 1L;
/**
* 用户id
*/
@TableId(value="id", type = IdType.AUTO)
private Integer id;
/**
* 名称
*/
@TableField("name")
private String name;
/**
* 年龄
*/
@TableField("age")
private Integer age;
/**
* 备注
*/
@TableField("remarks")
private String remarks;
}
postman中请求编辑用户接口,结果如下:
控制台打印信息:
数据库表数据:
经过上面的测试,说明公共字段的自动填充是可以的。
本文的完整代码可点击下载https://github.com/katie1221/mybatis-plus-demo目录下的auto-fill-demo。