轉(zhuǎn)載自 https://www.javazhiyin.com/33686.html
前言
在 Springboot 系列文章第十一篇里(使用 Mybatis(自動(dòng)生成插件) 訪問數(shù)據(jù)庫(kù)),實(shí)驗(yàn)了 Springboot 結(jié)合 Mybatis 以及 Mybatis-generator 生成插件的開發(fā)過程,其實(shí)對(duì)于 Mybatis 來(lái)講還有很多優(yōu)秀方便好用的插件,比如這次要演示的 通用 Mapper 生成插件和分頁(yè)插件。
數(shù)據(jù)庫(kù)準(zhǔn)備
既然是持久層框架,先準(zhǔn)備一個(gè)用于實(shí)驗(yàn)操作的數(shù)據(jù)表,這次還是使用上一個(gè)實(shí)驗(yàn)使用的 mysql 數(shù)據(jù)庫(kù)中的 springboot.book 數(shù)據(jù)表。
未創(chuàng)建的可以在 mysql 數(shù)據(jù)庫(kù)的 springboot 庫(kù)中創(chuàng)建表 book 用于演示。
CREATE TABLE `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `author` varchar(255) DEFAULT NULL COMMENT '書籍作者', `name` varchar(255) DEFAULT NULL COMMENT '書籍名稱', `price` float NOT NULL COMMENT '書籍價(jià)格', `create_time` datetime NOT NULL COMMENT '創(chuàng)建時(shí)間', `description` varchar(255) DEFAULT NULL COMMENT '書籍描述', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
增加測(cè)試數(shù)據(jù)。
INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (2, '金庸', '笑傲江湖', 12, '2018-09-01 10:10:12', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (3, '羅貫中', '三國(guó)演義', 22, '2018-09-01 10:10:16', '是作家羅貫中創(chuàng)作的一部長(zhǎng)篇?dú)v史小說');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (4, '吳承恩', '西游記', 17, '2018-09-01 10:10:19', '是作家吳承恩創(chuàng)作的一部長(zhǎng)篇小說');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (5, '金庸1535767819284', '笑傲江湖1535767819284', 43, '2018-09-01 10:10:19', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535767819284');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (6, '金庸1535767819679', '笑傲江湖1535767819679', 24, '2018-09-01 10:10:20', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535767819679');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (7, '羅貫中1535769035138', '三國(guó)演義1535769035138', 20, '2018-09-01 10:30:35', '是羅貫中創(chuàng)作的一部小說1535769035138');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (9, '金庸1535783613226', '笑傲江湖1535783613226', 30, '2018-09-01 14:33:33', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535783613226');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (10, '金庸1535783618455', '笑傲江湖1535783618455', 30, '2018-09-01 14:33:38', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535783618455');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (11, '金庸1535783620634', '笑傲江湖1535783620634', 30, '2018-09-01 14:33:41', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535783620634');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (12, '金庸1535783672457', '笑傲江湖1535783672457', 30, '2018-09-01 14:34:32', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535783672457');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (13, '金庸1535783673664', '笑傲江湖1535783673664', 30, '2018-09-01 14:34:34', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535783673664');INSERT INTO `springboot`.`book`(`id`, `author`, `name`, `price`, `create_time`, `description`) VALUES (14, '金庸1535783939262', '笑傲江湖1535783939262', 30, '2018-09-01 14:38:59', '是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說1535783939262');
引入依賴
創(chuàng)建 Springboot 項(xiàng)目不提,引入 maven 依賴,主要是 mybastis 核心依賴以及 mybatis mapper 自動(dòng)生成插件、分頁(yè)插件、通用 Mapper 插件。依賴中的 druid 數(shù)據(jù)源部分,可以參考系列文章第九篇。
<dependencies> <!-- Spring Boot web 開發(fā)整合 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-json</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 阿里 fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <!-- Lombok 工具 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 導(dǎo)入配置文件處理器,在配置springboot相關(guān)文件時(shí)候會(huì)有提示 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!--添加數(shù)據(jù)庫(kù)鏈接 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Druid 數(shù)據(jù)源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!-- mybatis mapper自動(dòng)生成插件 --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.7</version> <scope>compile</scope> <optional>true</optional> </dependency> <!-- mybatis pagehelper 分頁(yè)插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.10</version> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.1.5</version> </dependency> <!-- mybatis 通用 Mapper --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>4.0.4</version> </dependency> </dependencies>
簡(jiǎn)單說明一下幾個(gè)不常見依賴的作用。
mybatis-generator-core 用于自動(dòng)生成 model、mapper 接口、mapper xml。
pagehelper-spring-boot-starter 用于分頁(yè)
mapper 用于增強(qiáng)增刪改查功能,集成了很多常用操作。
增加配置
關(guān)于 Druid 數(shù)據(jù)源的配置不再說明,可以參考系列文章第九篇。配置中主要配置了項(xiàng)目編碼、數(shù)據(jù)源信息、durid 數(shù)據(jù)源和 mybatis 的 mapper 位置以及 mybatis 映射別名的包路徑。還有 pagehelper 分頁(yè)插件部分。
############################################################# 服務(wù)啟動(dòng)端口號(hào)server.port=8080spring.profiles.active=dev# 編碼server.tomcat.uri-encoding=utf-8spring.http.encoding.force=truespring.http.encoding.charset=UTF-8spring.http.encoding.enabled=true############################################################spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=utf-8&serverTimezone=GMT%2B8spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.username=rootspring.datasource.password=123# 使用 druid 數(shù)據(jù)源spring.datasource.type:com.alibaba.druid.pool.DruidDataSourcespring.datasource.initialSize:5spring.datasource.minIdle:5spring.datasource.maxActive:20spring.datasource.maxWait:60000spring.datasource.timeBetweenEvictionRunsMillis:60000spring.datasource.minEvictableIdleTimeMillis:300000spring.datasource.validationQuery:SELECT 1 FROM DUALspring.datasource.testWhileIdle:truespring.datasource.testOnBorrow:falsespring.datasource.testOnReturn:falsespring.datasource.poolPreparedStatements:truespring.datasource.filters:statspring.datasource.maxPoolPreparedStatementPerConnectionSize:20spring.datasource.useGlobalDataSourceStat:truespring.datasource.connectionProperties:druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500############################################################# mybatismybatis.mapper-locations=classpath:mapper/*.xmlmybatis.type-aliases-package=net.codingme.boot.domain############## mybatis page配置######################## restart 類加載加載 include 進(jìn)去的 jar 包。restart.include.mapper=/mapper-[\w-\.]+jarrestart.include.pagehelper=/pagehelper-[\w-\.]+jar# mappers 多個(gè)接口時(shí)逗號(hào)隔開mapper.mappers=net.codingme.boot.util.MybatisMappermapper.not-empty=falsemapper.identity=MYSQL# pagehelperpagehelper.helperDialect=mysqlpagehelper.reasonable=truepagehelper.supportMethodsArguments=truepagehelper.params=count=countSql# 輸出 mybatis SQL 日志logging.level.net.codingme.boot.domain.mapper=debug
一些說明。
mapper.mappers=net.codingme.boot.util.MybatisMapper用于包含一個(gè)自己編寫的 mapper。restart.include熱部署logging.level.net.codingme.boot.domain.mapper=debug輸出 Mybatis SQL 這里要指定自己 mapper 所在的包路徑
通用 Mapper
在上一篇文章中也演示了自動(dòng)生成,那是通用的一種生成方式,這次我們引入通用 Mapper 再進(jìn)行生成,這樣生成的代碼更加簡(jiǎn)潔。
為了方便理解,先看一下項(xiàng)目最終結(jié)構(gòu)。

<figcaption style="box-sizing: border-box; margin-top: 10px; font-size: 0.7em; color: rgb(153, 153, 153); line-height: inherit; text-align: center;">項(xiàng)目接口</figcaption>
自動(dòng)生成配置
自動(dòng)生成通用接口分為兩步,第一步是編寫生成配置文件,注釋已經(jīng)添加了,直接看代碼。
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration> <context id="MysqlContext" targetRuntime="MyBatis3Simple" defaultModelType="flat"> <property name="beginningDelimiter" value="`"/> <property name="endingDelimiter" value="`"/> <property name="javaFileEncoding" value="UTF-8"/> <!-- 是否使用通用 Mapper 提供的注釋工具,默認(rèn) true 使用,這樣在生成代碼時(shí)會(huì)包含字段的注釋(目前只有 mysql 和 oracle 支持)--> <property name="useMapperCommentGenerator" value="true"/> <plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <!-- 配置后生成的 Mapper 接口都會(huì)自動(dòng)繼承這個(gè)接口--> <property name="mappers" value="tk.mybatis.mapper.common.MySqlMapper"/> </plugin> <plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <!-- 配置后生成的 Mapper 接口都會(huì)自動(dòng)繼承這個(gè)接口 --> <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/> <!-- 是否區(qū)分大小寫,默認(rèn) false --> <property name="caseSensitive" value="true"/> </plugin> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=utf-8&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true" userId="root" password="123"> </jdbcConnection> <!-- 對(duì)于生成的pojo所在包 --> <javaModelGenerator targetPackage="net.codingme.boot.domain" targetProject="src/main/java"/> <!-- 對(duì)于生成的mapper所在目錄 --> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/> <!-- 配置mapper對(duì)應(yīng)的java映射 --> <javaClientGenerator targetPackage="net.codingme.boot.domain.mapper" targetProject="src/main/java" type="XMLMAPPER"/> <!-- 要生成那些表(更改tableName和domainObjectName就可以) --> <table tableName="book" domainObjectName="Book"/> </context></generatorConfiguration>
與上次不同的是這次增加了兩個(gè) plugin,后面生成的 Mapper 接口都會(huì)自動(dòng)繼承這些類。
自動(dòng)生成代碼
寫好配置文件之后,還需要寫一個(gè)生成程序,用于加載配置文件,運(yùn)行就可以生成相關(guān)的實(shí)體類、Mapper 接口、Mapper xml .
import org.mybatis.generator.api.MyBatisGenerator;import org.mybatis.generator.config.Configuration;import org.mybatis.generator.config.xml.ConfigurationParser;import org.mybatis.generator.internal.DefaultShellCallback;import java.io.File;import java.util.ArrayList;/** * <p> * Mybatis generator的逆向生成工具類 * * @Author niujinpeng */public class MybatisGenerator { public void generator() throws Exception { ArrayList<String> warnings = new ArrayList<>(); boolean overwrite = true; // 指定你想工程配置文件 File configFile = new File("generatorConfig.xml"); System.out.println(configFile.getAbsolutePath()); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); for (String warning : warnings) { System.out.println(warning); } } public static void main(String[] args) throws Exception { MybatisGenerator mybatisGenerator = new MybatisGenerator(); mybatisGenerator.generator(); }}
自動(dòng)生成結(jié)果
運(yùn)行完畢上面程序之后,自動(dòng)生成了 Book.java.
@Table(name = "book")@ToString // 手動(dòng)添加的 tostring 注解public class Book { @Id private Integer id; /** * 書籍作者 */ private String author; /** * 書籍名稱 */ private String name; /** * 書籍價(jià)格 */ private Float price; // 省略下面的自動(dòng)生成代碼
通用 Mapper
上面的程序也自動(dòng)生成了 BookMapper 接口,且繼承了配置的 MySqlMapper 和 Mapper 接口。
import net.codingme.boot.domain.Book;import org.springframework.stereotype.Repository;import tk.mybatis.mapper.common.Mapper;import tk.mybatis.mapper.common.MySqlMapper;@Repositorypublic interface BookMapper extends MySqlMapper<Book>, Mapper<Book> {}
這兩個(gè)接口里實(shí)現(xiàn)了很多常用操作。

<figcaption style="box-sizing: border-box; margin-top: 10px; font-size: 0.7em; color: rgb(153, 153, 153); line-height: inherit; text-align: center;">通用 Mapper 里的方法</figcaption>
生成完成之后要在 Springboot 啟動(dòng)器上添加 MapperScan 注解指定要掃描的 mapper 位置。
@tk.mybatis.spring.annotation.MapperScan(basePackages = "net.codingme.boot.domain.mapper")@SpringBootApplicationpublic class BootApplication { public static void main(String[] args) { SpringApplication.run(BootApplication.class, args); }}
單元測(cè)試和分頁(yè)測(cè)試
編寫 BookMapperTest 單元測(cè)試用于測(cè)試 BookMapper 的方法。
package net.codingme.boot.domain.mapper;import com.github.pagehelper.Page;import com.github.pagehelper.PageHelper;import com.github.pagehelper.PageInfo;import net.codingme.boot.domain.Book;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)@SpringBootTestpublic class BookMapperTest { @Autowired private BookMapper bookMapper; @Test public void testSelectOne() { Book book = new Book(); book.setId(2); Book selectOne = bookMapper.selectOne(book); Assert.assertNotNull(selectOne); System.out.println(selectOne); } @Test public void testSelectByPrimaryKey() { Book book = bookMapper.selectByPrimaryKey(2); Assert.assertNotNull(book); System.out.println(book); } /** * 分頁(yè)測(cè)試 */ @Test public void testSelectPageInfo() { PageHelper.startPage(2, 3); List<Book> bookList = bookMapper.selectAll(); Assert.assertNotNull(bookList); System.out.println("查詢出數(shù)量:" + bookList.size()); PageInfo<Book> pageInfo = PageInfo.of(bookList); System.out.println("總數(shù)量:" + pageInfo.getTotal()); System.out.println("總頁(yè)數(shù):" + pageInfo.getPages()); System.out.println("頁(yè)大?。? + pageInfo.getPageSize()); System.out.println("第幾頁(yè):" + pageInfo.getPageNum()); System.out.println("當(dāng)前量:" + pageInfo.getSize()); } /** * 分頁(yè)測(cè)試 */ @Test public void testSelectPage() { PageHelper.startPage(2, 3); List<Book> bookList = bookMapper.selectAll(); Assert.assertNotNull(bookList); System.out.println("查詢出數(shù)量:" + bookList.size()); System.out.println("總數(shù)量:" + ((Page)bookList).getTotal()); System.out.println("總頁(yè)數(shù):" + ((Page)bookList).getPages()); System.out.println("第幾頁(yè):" + ((Page)bookList).getPageNum()); }}
從代碼中可以看到分頁(yè)的實(shí)現(xiàn)主要是 PageHelper 的設(shè)置,在設(shè)置 PageHelper 之后的第一個(gè)查詢會(huì)進(jìn)行分頁(yè)。像上面的例子會(huì)查詢第二頁(yè),每頁(yè)三條這樣。
PageHelper.startPage(2, 3);List<Book> bookList = bookMapper.selectAll();
其實(shí)使用了分頁(yè)插件之后返回的數(shù)據(jù)類型是一個(gè) Page 類,總數(shù)等分頁(yè)信息都已經(jīng)返回,如果要取出來(lái)使用就需要強(qiáng)制轉(zhuǎn)換類型然后取出,上面也是演示了兩種方式。
// 方式 1PageInfo<Book> pageInfo = PageInfo.of(bookList);System.out.println("總數(shù)量:" + pageInfo.getTotal());System.out.println("總頁(yè)數(shù):" + pageInfo.getPages());System.out.println("頁(yè)大?。? + pageInfo.getPageSize());System.out.println("第幾頁(yè):" + pageInfo.getPageNum());System.out.println("當(dāng)前量:" + pageInfo.getSize());// 方式 2System.out.println("查詢出數(shù)量:" + bookList.size());System.out.println("總數(shù)量:" + ((Page)bookList).getTotal());System.out.println("總頁(yè)數(shù):" + ((Page)bookList).getPages());System.out.println("第幾頁(yè):" + ((Page)bookList).getPageNum());
運(yùn)行 BookMapperTest 類測(cè)試所有的單元測(cè)試。

<figcaption style="box-sizing: border-box; margin-top: 10px; font-size: 0.7em; color: rgb(153, 153, 153); line-height: inherit; text-align: center;">單元測(cè)試結(jié)果</figcaption>
發(fā)現(xiàn)單元測(cè)試全部通過,查看一個(gè)分頁(yè)查詢(testSelectPageInfo)輸出情況。
2019-03-08 16:07:52.226 DEBUG 26764 --- [ main] n.c.b.d.m.BookMapper.selectAll_COUNT : ==> Preparing: SELECT count(0) FROM book 2019-03-08 16:07:52.227 DEBUG 26764 --- [ main] n.c.b.d.m.BookMapper.selectAll_COUNT : ==> Parameters: 2019-03-08 16:07:52.229 DEBUG 26764 --- [ main] n.c.b.d.m.BookMapper.selectAll_COUNT : <== Total: 12019-03-08 16:07:52.231 DEBUG 26764 --- [ main] n.c.b.d.mapper.BookMapper.selectAll : ==> Preparing: SELECT id,author,name,price,create_time,description FROM book LIMIT ?, ? 2019-03-08 16:07:52.233 DEBUG 26764 --- [ main] n.c.b.d.mapper.BookMapper.selectAll : ==> Parameters: 3(Integer), 3(Integer)2019-03-08 16:07:52.236 DEBUG 26764 --- [ main] n.c.b.d.mapper.BookMapper.selectAll : <== Total: 3查詢出數(shù)量:3總數(shù)量:12總頁(yè)數(shù):4頁(yè)大?。?第幾頁(yè):2當(dāng)前量:3
再查看一個(gè)普通查詢(testSelectByPrimaryKey)輸出情況。
2019-03-08 16:07:52.241 DEBUG 26764 --- [ main] n.c.b.d.m.BookMapper.selectByPrimaryKey : ==> Preparing: SELECT id,author,name,price,create_time,description FROM book WHERE id = ? 2019-03-08 16:07:52.242 DEBUG 26764 --- [ main] n.c.b.d.m.BookMapper.selectByPrimaryKey : ==> Parameters: 2(Integer)2019-03-08 16:07:52.244 DEBUG 26764 --- [ main] n.c.b.d.m.BookMapper.selectByPrimaryKey : <== Total: 1Book(id=2, author=金庸, name=笑傲江湖, price=12.0, createTime=Sat Sep 01 10:10:12 GMT+08:00 2018, description=是作家金庸創(chuàng)作的一部長(zhǎng)篇武俠小說)
文中代碼已經(jīng)上傳到 Github (https://github.com/niumoo/springboot)
想要了解這幾個(gè)插件的其他信息,可以查看官方文檔。
如何使用分頁(yè)插件(https://pagehelper.github.io/docs/howtouse/)
Mapper插件 (https://github.com/abel533/Mapper/wiki/1.3-spring-boot)
MyBatis Generator (http://www.mybatis.org/generator/)