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