5、SpringBoot整合之SpringBoot整合MybatisPlus

SpringBoot整合MybatisPlus

目录(可点击直接跳转,但还是建议按照顺序观看,四部分具有一定的关联性):

实现基础的增删改查

实现自动填充功能

实现逻辑删除

实现分页

首先给出四部分完整的项目结构

一、实现基础的增删改查功能

1.创建项目、选择依赖

选择Spring Web、JDBC API、MyBatis Framework、MySQL Driver

2.在pom文件中引入相关依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <!-- 修改jdbc版本 -->
    <version>5.1.47</version>
    <scope>runtime</scope>
</dependency>

<!-- 引入MybatisPlus的启动器 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.2</version>
</dependency>

<!-- 引入lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

<!-- 引入druid连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

<!-- 引入log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

3.建库、建表、插入数据

CREATE DATABASE db_mybatisplus;

USE db_mybatisplus;

CREATE TABLE tab_teacher(
    pk_teacher_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '老师主键id,起始为1',
    teacher_name VARCHAR(10) COMMENT '老师姓名',
    teacher_sex CHAR(1) COMMENT '老师性别',
    teacher_salary DOUBLE(6,1) COMMENT '老师工资'
);

-- 反复执行多次,随机插入多条数据
INSERT INTO tab_teacher VALUES(
    NULL,
    SUBSTR(MD5(RAND()), 1, 5),
    IF(RAND()>0.5, '男', '女'),
    RAND()*10000+1000
);

SELECT * FROM tab_teacher;

4.配置核心配置文件

# 配置连接数据库的四大参数
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.url=jdbc:mysql://192.168.133.139/db_mybatisplus?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true

spring.datasource.username=root

spring.datasource.password=root

# 指定连接池的类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# 显示SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

5.创建实体类

package cn.byuan.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@NoArgsConstructor// 创建无参的构造方法
@AllArgsConstructor// 创建满参的构造方法
@Accessors(chain = true)// 使用链式方法
@Data// 重写toString方法等方法
@TableName("tab_teacher")// 对应表名
public class Teacher implements Serializable {
    @TableId(value = "pk_teacher_id", type = IdType.AUTO)// 主键必须有TableId注解
    private Integer teacherId;

    @TableField("teacher_name")
    private String teacherName;

    @TableField("teacher_sex")
    private String teacherSex;

    @TableField("teacher_salary")
    private Double teacherSalary;

}

6.创建Teacher类的dao接口,继承BaseMapper接口,使用BaseMapper接口的方法

这里我省去了mapper层,直接让dao层接口继承BaseMapper

这里要牢记一个原则:在启动类对继承BaseMapper的类进行扫描,谁继承BaseMapper类就对它进行扫描

package cn.byuan.dao;

import cn.byuan.entity.Teacher;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;

@Repository
public interface TeacherDao extends BaseMapper<Teacher> {

}

7.创建service接口及实现类

接口:

import cn.byuan.entity.Teacher;

import java.util.List;

public interface TeacherService {
//    添加一位老师
    Integer addOneTeacher(Teacher teacher);

//    根据id删除一位老师
    Integer deleteOneTeacherByTeacherId(Integer teacherId);

//    修改一位老师的信息
    Integer updateOneTeacher(Teacher teacher);

//    根据id查询一位老师
    Teacher getOneTeacherByTeacherId(Integer teacherId);

//    获取所有老师
    List<Teacher> getAllTeacher();
}

实现类:

package cn.byuan.service;

import cn.byuan.dao.TeacherDao;
import cn.byuan.entity.Teacher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TeacherServiceImp implements TeacherService{
    @Autowired
    private TeacherDao teacherDao;

    //    添加一位老师
    public Integer addOneTeacher(Teacher teacher){
        return teacherDao.insert(teacher);
    }

    //    根据id删除一位老师
    public Integer deleteOneTeacherByTeacherId(Integer teacherId){
        return teacherDao.deleteById(teacherId);
    }

    //    修改一位老师的信息
    public Integer updateOneTeacher(Teacher teacher){
        return teacherDao.updateById(teacher);
    }

    //    根据id查询一位老师
    public Teacher getOneTeacherByTeacherId(Integer teacherId){
        return teacherDao.selectById(teacherId);
    }

    //    获取所有老师
    public List<Teacher> getAllTeacher(){
        return teacherDao.selectList(null);
    }
}

8.在启动类对继承BaseMapper的类配置扫描

谁继承了BaseMapper就对谁进行扫描,因为之前我省去了mapper层,直接让dao层接口继承BaseMapper,因此这里扫描的是dao包

package cn.byuan;

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

@SpringBootApplication
@MapperScan("cn.byuan.dao")// 那一层继承了BaseMapper就对那一层进行扫描
public class Test005SpringbootMybatisplusApplication {

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

}

9.在测试类进行测试

package cn.byuan;

import cn.byuan.entity.Teacher;
import cn.byuan.service.TeacherService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class TeacherDaoOneTests {
    @Autowired
    private TeacherService teacherService;

    @Test
    void addOneTeacherTest(){
        Teacher teacher = new Teacher()
                .setTeacherName("test2")
                .setTeacherSex("女")
                .setTeacherSalary(9876.5);
        teacherService.addOneTeacher(teacher);
    }

    @Test
    void deleteOneTeacherByTeacherIdTest(){
        teacherService.deleteOneTeacherByTeacherId(2);
    }

    @Test
    void updateOneTeacher(){
        Teacher teacher = new Teacher()
                .setTeacherId(1)
                .setTeacherName("qwe12")
                .setTeacherSex("女")
                .setTeacherSalary(1234.5);
        teacherService.updateOneTeacher(teacher);
    }

    @Test
    void getOneTeacherByTeacherId(){
        teacherService.getOneTeacherByTeacherId(1);
    }

    @Test
    void getAllTeacher(){
        teacherService.getAllTeacher();
    }

}


测试结果:

二、实现自动填充功能

自动填充功能一般可以用作记录操作发生时间,如某列的最后修改时间等,本部分代码基于第一部分:实现基础的增删改查、

1.修改数据库中的表结构

-- 修改数据库中表结构
ALTER TABLE tab_teacher ADD create_time TIMESTAMP COMMENT '记录插入时间';

ALTER TABLE tab_teacher ADD update_time TIMESTAMP COMMENT '记录修改时间';

-- 更新所有表中数据
UPDATE tab_teacher SET create_time=NOW();

UPDATE tab_teacher SET update_time=NOW();

SELECT * FROM tab_teacher;

2.修改实体类

这一步简单来说就是将增加的两列添加进Teacher类的属性中,其余与第一部分保持一致;

为实现自动填充还应在新加入的两个属性的TableField中增加"fill"属性

package cn.byuan.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

@NoArgsConstructor// 创建无参的构造方法
@AllArgsConstructor// 创建满参的构造方法
@Accessors(chain = true)// 使用链式方法
@Data// 重写toString方法等方法
@TableName("tab_teacher")// 对应表名
public class Teacher implements Serializable {
    @TableId(value = "pk_teacher_id", type = IdType.AUTO)// 主键必须有TableId注解
    private Integer teacherId;

    @TableField("teacher_name")
    private String teacherName;

    @TableField("teacher_sex")
    private String teacherSex;

    @TableField("teacher_salary")
    private Double teacherSalary;

//    增加的两列属性
    @TableField(value = "create_time", fill = FieldFill.INSERT)// 插入时自动填充
    private Date createTime;

    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)// 插入和修改时自动填充
    private Date updateTime;

}

3.创建handler层,实现MetaObjectHandler接口,重写insertFill与updateFill方法,指定填充的字段及属性值

package cn.byuan.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class TeacherHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
        
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());

    }
}

4.进行测试

这里我们只测试增加和修改两个方法

package cn.byuan;

import cn.byuan.entity.Teacher;
import cn.byuan.service.TeacherService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class TeacherDaoTwoTests {
    @Autowired
    private TeacherService teacherService;

    @Test
    void addOneTeacherTest(){
        Teacher teacher = new Teacher()
                .setTeacherName("test2")
                .setTeacherSex("女")
                .setTeacherSalary(9876.5);
        teacherService.addOneTeacher(teacher);
    }

    @Test
    void updateOneTeacher(){
        Teacher teacher = new Teacher()
                .setTeacherId(1)
                .setTeacherName("wer23")
                .setTeacherSex("女")
                .setTeacherSalary(1234.5);
        teacherService.updateOneTeacher(teacher);
    }
}

从SQL语句可以看出,在执行update方法时,已自动为我们填充字段

数据库中新插入数据也没有问题

三、实现逻辑删除功能

数据是无价的,因此一般而言我们不会直接删除数据。对于"删除"我们一般的做法是定义一个字段来记录本行数据的可见性

1.修改数据库中的表结构

添加一个字段作为标记

-- 修改数据库中表结构, 添加一个字段作为标记
ALTER TABLE tab_teacher ADD visibility TINYINT COMMENT "0表示未删除,1表示删除";

-- 更新表中所有数据, 全部设置为未删除
UPDATE tab_teacher SET visibility=0;

2.在实体类中添加字段,并添加TableField和TableLogic两个注解

package cn.byuan.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

@NoArgsConstructor// 创建无参的构造方法
@AllArgsConstructor// 创建满参的构造方法
@Accessors(chain = true)// 使用链式方法
@Data// 重写toString方法等方法
@TableName("tab_teacher")// 对应表名
public class Teacher implements Serializable {
    @TableId(value = "pk_teacher_id", type = IdType.AUTO)// 主键必须有TableId注解
    private Integer teacherId;

    @TableField("teacher_name")
    private String teacherName;

    @TableField("teacher_sex")
    private String teacherSex;

    @TableField("teacher_salary")
    private Double teacherSalary;

    @TableField(value = "create_time", fill = FieldFill.INSERT)// 插入时自动填充
    private Date createTime;

    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)// 插入和修改时自动填充
    private Date updateTime;
    
//    新添加进来的字段
    @TableField(value = "visibility", fill = FieldFill.INSERT)
    @TableLogic(value = "0", delval = "1")// 指定次字段为逻辑删除字段, 默认0是未删除, 1是已删除
    private Integer visibility;

}

3.在TeacherHandler中指定visibility字段的初始值

package cn.byuan.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class TeacherHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
        
//        新添加的字段
        this.strictInsertFill(metaObject, "visibility", Integer.class, 0);

    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());

    }
}

4.进行测试

这里只测试两个方法,一个是删除指定id值的老师,一个是根据被删除的老师id查询该老师是否可以被查询

package cn.byuan;

import cn.byuan.entity.Teacher;
import cn.byuan.service.TeacherService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class TeacherDaoThreeTests {
    @Autowired
    private TeacherService teacherService;

    @Test
    void deleteOneTeacherByTeacherIdTest(){
//        删除id为1的老师
        teacherService.deleteOneTeacherByTeacherId(1);
    }

    @Test
    void getOneTeacherByTeacherId(){
//        查询id为1的老师
        teacherService.getOneTeacherByTeacherId(1);
    }

}

可以看到,当我们执行delete方法时,实际上执行的是update方法

而查询语句并没有查询到该老师

数据库中id为1的老师信息依然存在

四、实现分页功能

1.创建一个配置类,通过方法返回一个PaginationInterceptor

package cn.byuan.conf;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("cn.byuan.dao")
public class PageConfig {
    @Bean
    public PaginationInterceptor PaginationInterceptor(){
        return new PaginationInterceptor();
    }
}

2.在service中根据selectPage方法进行分页

这里展示两种分页方式,对表中所有数据进行分页以及根据条件进行分页

接口:

package cn.byuan.service;

import cn.byuan.entity.Teacher;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.util.List;

public interface TeacherService {
//    添加一位老师
    Integer addOneTeacher(Teacher teacher);

//    根据id删除一位老师
    Integer deleteOneTeacherByTeacherId(Integer teacherId);

//    修改一位老师的信息
    Integer updateOneTeacher(Teacher teacher);

//    根据id查询一位老师
    Teacher getOneTeacherByTeacherId(Integer teacherId);

//    获取所有老师
    List<Teacher> getAllTeacher();

//    该部分增加的方法
//    对表中所有信息进行分页, 传入参数为要查询的页数
    Page<Teacher> getAllTeacherPage(Integer pageNumber);

//    按条件(性别)进行分页
    Page<Teacher> getAllTeacherByTeacherSexPage(Integer pageNumber, String teacherSex);
}

实现类:

package cn.byuan.service;

import cn.byuan.dao.TeacherDao;
import cn.byuan.entity.Teacher;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TeacherServiceImp implements TeacherService{
    @Autowired
    private TeacherDao teacherDao;

    //    添加一位老师
    public Integer addOneTeacher(Teacher teacher){
        return teacherDao.insert(teacher);
    }

    //    根据id删除一位老师
    public Integer deleteOneTeacherByTeacherId(Integer teacherId){
        return teacherDao.deleteById(teacherId);
    }

    //    修改一位老师的信息
    public Integer updateOneTeacher(Teacher teacher){
        return teacherDao.updateById(teacher);
    }

    //    根据id查询一位老师
    public Teacher getOneTeacherByTeacherId(Integer teacherId){
        return teacherDao.selectById(teacherId);
    }

    //    获取所有老师
    public List<Teacher> getAllTeacher(){
        return teacherDao.selectList(null);
    }
    
    //    该部分增加的方法
    //    对表中所有信息进行分页, 传入参数为要查询的页数
    public Page<Teacher> getAllTeacherPage(Integer pageNumber){
        QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();

        Page<Teacher> teacherPage = new Page<>(pageNumber, 5);// 每页大小为5

        teacherDao.selectPage(teacherPage, teacherQueryWrapper);

        return teacherPage;
    }

    //    按条件(性别)进行分页
    public Page<Teacher> getAllTeacherByTeacherSexPage(Integer pageNumber, String teacherSex){
        QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();

        teacherQueryWrapper.eq("teacher_sex", teacherSex);// 根据条件进行分页, 这里填写的是表中的列名

        Page<Teacher> teacherPage = new Page<>(pageNumber, 5);

        teacherDao.selectPage(teacherPage, teacherQueryWrapper);
        return teacherPage;
    }
}

3.进行测试

package cn.byuan;

import cn.byuan.entity.Teacher;
import cn.byuan.service.TeacherService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class TeacherDaoFourTests {
    @Autowired
    private TeacherService teacherService;

    @Test
    void getAllTeacherPageTest(){
        //    查看第三页
        Page<Teacher> teacherPage = teacherService.getAllTeacherPage(3);

        teacherPage.getRecords().forEach(System.out::println);
    }

    @Test
    void getAllTeacherByTeacherSexPageTest(){
        //    查询男生第1页的内容
        Page<Teacher> teacherPage = teacherService.getAllTeacherByTeacherSexPage(1, "男");

        teacherPage.getRecords().forEach(System.out::println);
    }
}

测试结果

附:Page对象的一些常用方法

Page<Object> page = new Page<>(1, 6);// 指定当前页, 每页记录数
page.getCurrent();// 获取当前页
page.getTotal();// 获取总记录数
page.getSize();// 获取每页的记录数
page.getRecords();// 获取当前页数据的集合
page.getPages();// 获取总页数
page.hasNext();// 是否存在下一页
page.hasPrevious();// 是否存在上一页

源码地址:https://github.com/byuan98/springboot-integration/tree/master/test005_springboot_mybatisplus

posted @ 2021-07-06 21:14  张知非  阅读(7924)  评论(0编辑  收藏  举报