Mybatis Plus 实现自动填充

本贴最后更新于 1371 天前,其中的信息可能已经物是人非

环境

JDK1.8.0_251+MySql5.7.22+maven-3.6.3+MybatisPlus3.0.5+SpringBoot2.2.2

实现步骤

首先查看我们部署的 MySQL:

image.png

创建一个数据库命名为 mybatis_plus,创建一张表为 user 表,

create table User(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);

添加数据:

INSERT INTO user(id,name,age,email) VALUES (1,'admin',18,'admin@126.com'),(2,'giles',19,'giles@126.com'),(3,'jone',22,'jone@126.com'),(4,'peter',23,'peter@126.com'),(5,'gosling',18,'gosling@126.com');

我们的数据库表一定配置完毕

接下来创建一个项目 mybatis_plus,创建过程就省略了,直接看我们的 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>mpdemo1010</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mpdemo1010</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
  
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

接着我们导入 mybatis plus 相关的依赖:

<!--导入mybatis-plus相关的依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

导入 mysql 依赖:

<!--导入mysql相关依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

导入 lombok 依赖:

	<!--lombok用来简化实体类-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

lombok 就是用来简化实体类操作的,简单来说就是不在需要我们再去写 get/set 方法了
最后的 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>mpdemo1010</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mpdemo1010</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--导入mybatis-plus相关依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

        <!--导入mysql相关依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--lombok用来简化实体类-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

接着我们创建实体类 User:

@Data
public class User {

    private Long id;

    private String name;
    private Integer age;
    private String email;

  
}

之后创建一个 UserMapper 并且继承 BaseMapper:

@Repository
public interface UserMapper extends BaseMapper<User> {
}

然后在 AutoFillApplication 启动类上添加上 @MapperScan,为了使启动类能扫面 Mapper:

package com.giles.autofill;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.giles.autofill.mapper")
public class AutoFillApplication {

    public static void main(String[] args) {
        SpringApplication.run(AutoFillApplication.class, args);
    }


}

我么看一下 BaseMapper 源码:

public interface BaseMapper<T> {

    /**
     * <p>
     * 插入一条记录
     * </p>
     *
     * @param entity 实体对象
     */
    int insert(T entity);

    /**
     * <p>
     * 根据 ID 删除
     * </p>
     *
     * @param id 主键ID
     */
    int deleteById(Serializable id);

    /**
     * <p>
     * 根据 columnMap 条件,删除记录
     * </p>
     *
     * @param columnMap 表字段 map 对象
     */
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

    /**
     * <p>
     * 根据 entity 条件,删除记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 删除(根据ID 批量删除)
     * </p>
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

    /**
     * <p>
     * 根据 ID 修改
     * </p>
     *
     * @param entity 实体对象
     */
    int updateById(@Param(Constants.ENTITY) T entity);

    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param entity        实体对象 (set 条件值,不能为 null)
     * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
     */
    int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

    /**
     * <p>
     * 根据 ID 查询
     * </p>
     *
     * @param id 主键ID
     */
    T selectById(Serializable id);

    /**
     * <p>
     * 查询(根据ID 批量查询)
     * </p>
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

    /**
     * <p>
     * 查询(根据 columnMap 条件)
     * </p>
     *
     * @param columnMap 表字段 map 对象
     */
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

    /**
     * <p>
     * 根据 entity 条件,查询一条记录
     * </p>
     *
     * @param queryWrapper 实体对象
     */
    T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询总记录数
     * </p>
     *
     * @param queryWrapper 实体对象
     */
    Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 entity 条件,查询全部记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录
     * 注意: 只返回第一个字段的值
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 entity 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param page         分页查询条件(可以为 RowBounds.DEFAULT)
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类
     */
    IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}

我们发现里面已经有了我们大部分需要的 crud 操作,不再需要我们去配置这些操作了。

做完这些之后我们大部分工作完成了,我们现在配置 MySql 链接使程序能访问到 MySQL 进行操作:

application.properties 代码如下:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

昨晚这些之后我们要在 MySQL 中添加两个字段 insert_time 和 update_time 类型为 datatime:

image.png

同时在实体类上添加这两个字段并添加上 @TableField 注解:

@TableField(fill = FieldFill.INSERT)
private Data createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

关于 @TableField 注解的作用请看 MybatisPlus 用户手册

下一步在 Test 中写入添加和更新方法:

@SpringBootTest
public class AutoFillApplicationTests {

    @Autowired
    private UserMapper userMapper;

    //添加操作
    @Test
    public void addUser() {
        User user = new User();
        user.setName("sun");
        user.setAge(23);
        user.setEmail("sun@qq.com");

//        user.setCreateTime(new Date());
//        user.setUpdateTime(new Date());

        int insert = userMapper.insert(user);
        System.out.println("insert:"+insert);
    }

    //修改操作
    @Test
    public void updateUser() {

        User user = new User();
        user.setId(1276496583329378306L);
        user.setAge(20);

        int row = userMapper.updateById(user);
        System.out.println(row);
    }
}

接着我们创建一个 Handler 并且实现 MetaObjectHandler:

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //使用mp实现添加操作,这个方法执行
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);

    }

    //使用mp实现修改操作,这个方法执行
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

我们查看源码发现:

default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) {
        if (metaObject.hasSetter(fieldName) && metaObject.hasGetter(fieldName)) {
            metaObject.setValue(fieldName, fieldVal);
        } else if (metaObject.hasGetter(Constants.ENTITY)) {
            Object et = metaObject.getValue(Constants.ENTITY);
            if (et != null) {
                MetaObject etMeta = SystemMetaObject.forObject(et);
                if (etMeta.hasSetter(fieldName)) {
                    etMeta.setValue(fieldName, fieldVal);
                }
            }
        }
        return this;
    }

很明显我们第一个参数局势要更新的字段的名称那,第二个就是类型,第三个就是 MetaObject;

测试运行

我们运行 Test 方法输出:

add 方法:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@87b5b49] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@816302479 wrapping com.mysql.cj.jdbc.ConnectionImpl@36361ddb] will not be managed by Spring
==>  Preparing: INSERT INTO user ( id, name, age, email, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 1276529195586445314(Long), sun(String), 23(Integer), sun@126.com(String), 2020-06-26 22:54:11.65(Timestamp), 2020-06-26 22:54:11.65(Timestamp)
<==    Updates: 1
 Time:16 ms - ID:com.giles.autofill.mapper.UserMapper.insert
Execute SQL:
    INSERT 
    INTO
        user
        ( id, name, age, email, create_time, update_time ) 
    VALUES
        ( 1276529195586445314, 'sun', 23, 'sun@126.com', '2020-06-26 22:54:11.65', '2020-06-26 22:54:11.65' )

Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@87b5b49]
insert:1

很明显我们的语句运行成功了,看一下数据库上面数据是否更新:

image.png

数据库上也更新了,说明没问题,之后我们测试更新的数据:

将自动生成的 id 复制到 update 方法中去:

 @Test
    public void updateUser() {

        User user = new User();
        user.setId(1276529195586445314L);
        user.setAge(20);

        int row = userMapper.updateById(user);
        System.out.println(row);
    }

可以看到我们的语句只是更新了年龄这一栏位正确的话只会更新年龄和更新时间栏位,运行效果看一下:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@573284a5] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@146346292 wrapping com.mysql.cj.jdbc.ConnectionImpl@1fba386c] will not be managed by Spring
==>  Preparing: UPDATE user SET age=?, update_time=? WHERE id=? 
==> Parameters: 20(Integer), 2020-06-26 22:59:01.722(Timestamp), 1276529195586445314(Long)
<==    Updates: 1
 Time:2 ms - ID:com.giles.autofill.mapper.UserMapper.updateById
Execute SQL:
    UPDATE
        user 
    SET
        age=20,
        update_time='2020-06-26 22:59:01.722' 
    WHERE
        id=1276529195586445314

Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@573284a5]
1


语句运行成功,看一下 MySQL:

image.png

更新其后两条语句对比:

更新前:

image.png

更新后:

image.png

我们发现只是更新了年龄和更新时间栏位说明我们的自动填充没有问题,至此自动填充就结束了。

感谢您抽出宝贵时间来阅读,如果这篇文章对你有帮助那真是我莫大的荣幸!!

  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 430 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...