前言
在之前的博客中介紹了Spring boot
整合Mybatis
以及Druid
,本篇博客主要介紹如何在Spring boot中整合Mybatis的逆向工程Mybatis Generator
以下簡稱為MBG
,以及實際項目中十分方便簡單的物理分頁插件PageHelper
,使用這些插件能極大的減輕我們的開發(fā)過程那些簡單重復的過程六荒,本篇博客在項目已經(jīng)整合了Mybatis
的基礎上進行,沒有整合Mybatis
的朋友可以參考 Spring boot整合Mybatis掏击。
文章首發(fā)于個人博客:【http://www.xiongfrblog.cn】
整合MBG
為什么使用MBG
使用過Mybatis
的朋友應該都知道卵皂,在使用之前我們需要根據(jù)數(shù)據(jù)庫表的情況在項目中創(chuàng)建出對應的實體類砚亭,sql
語句接口層殴玛,XML
文件等,這一系列的操作是非常簡單的添祸,但又是必不可少的滚粟,耗時耗力還沒什么營養(yǎng),如果數(shù)據(jù)庫的表足夠多的時候還要手動創(chuàng)建這些內(nèi)容刃泌,那對程序員來說簡直是一種折磨凡壤,所以在實際的開發(fā)過程中MBG
是非常有必要的,下面我們就詳細介紹如何在Spring boot
項目中配置MBG
耙替。
在pom.xml中添加MBG插件
在<plugins></plugins>
標簽中添加如下內(nèi)容:
<!-- Mybatis Generator插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<!-- 配置文件的位置 -->
<configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
<!-- 允許移動生成的文件 -->
<verbose>true</verbose>
<!-- 是否覆蓋亚侠,true表示會替換生成的Java文件,false則不覆蓋 -->
<overwrite>true</overwrite>
</configuration>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
</dependencies>
</plugin>
其中configurationFile
:MBG
配置文件的位置可以根據(jù)自己的實際情況改寫俗扇。
注意:如上所示硝烂,我們在插件內(nèi)還添加了mysql
,mybatis
的依賴項铜幽,這兩項依賴我們在項目的依賴項里已經(jīng)添加過了滞谢,但是這里還需要再添加一次,我在配置這里的時候如果這里不添加執(zhí)行插件的時候就會報錯除抛。
添加generatorConfig.xml配置文件
這一步是我們生成實體類等的關鍵狮杨,所有的規(guī)則都是在這個配置文件里配置的。
首先在src/main/resources
目錄下創(chuàng)建generator
目錄到忽,在該目錄下創(chuàng)建generatorConfig.xml
配置文件禾酱,內(nèi)容如下:
<?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>
<!-- 導入配置文件 -->
<properties resource="application.properties"/>
<!-- defaultModelType="flat" s設置復合主鍵時不單獨為主鍵創(chuàng)建實體 -->
<context id="MySql" defaultModelType="flat" targetRuntime="MyBatis3Simple">
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 當表名或者字段名為SQL關鍵字的時候,可以設置該屬性為true绘趋,MBG會自動給表名或字段名添加分隔符(反單引號) -->
<property name="autoDelimitKeywords" value="true"/>
<!-- 由于beginningDelimiter和endingDelimiter的默認值為雙引號(")颤陶,在Mysql中不能這么寫,所以還要將這兩個默認值改為反單引號(`)陷遮, -->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- 生成的POJO實現(xiàn)java.io.Serializable接口 -->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<!--注釋-->
<commentGenerator>
<!-- 阻止生成注釋 -->
<property name="suppressAllComments" value="true"/>
<!-- 注釋里不添加日期 -->
<property name="suppressDate" value="true"/>
</commentGenerator>
<!-- 數(shù)據(jù)庫連接滓走,直接通過${}讀取application.properties里的配置 -->
<jdbcConnection
driverClass="${spring.datasource.driverClassName}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}"/>
<!-- 生成POJO對象,并將類放到com.web.springbootmybatis.entity包下 -->
<javaModelGenerator targetPackage="com.web.springboot.entity" targetProject="src/main/java"></javaModelGenerator>
<!-- 生成mapper xml文件帽馋,并放到resources下的mapper文件夾下 -->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"></sqlMapGenerator>
<!-- 生成mapper xml對應dao接口搅方,放到com.web.springbootmybatis.dao包下-->
<javaClientGenerator targetPackage="com.web.springboot.dao" targetProject="src/main/java" type="XMLMAPPER"></javaClientGenerator>
<!-- table標簽可以有多個,至少一個绽族,tableName指定表名姨涡,可以使用_和%通配符,我這里的配置表明匹配所有的表 -->
<table tableName="%">
<!-- 是否只生成POJO對象 -->
<property name="modelOnly" value="false"/>
<!-- 插入一條數(shù)據(jù)時吧慢,將id映射到實體類中 -->
<generatedKey column="id" sqlStatement="Mysql"/>
</table>
</context>
</generatorConfiguration>
上面的配置是最常用的配置涛漂,注意使用的時候包名,數(shù)據(jù)庫連接等某些配置需要根據(jù)自己的實際情況改寫,一般使用這個就已經(jīng)可以了匈仗,如果有其他的特別的需求可以參考這篇博客瓢剿,里邊講解了該配置文件所有標簽,屬性的意思悠轩,解釋的非常清楚间狂,想要深入了解的朋友請移步【傳送門】
執(zhí)行插件
- 在
eclipse
中鉴象,右鍵項目-->Run As
-->Maven build...
-->在Goals
中填寫命令mybatis-generator:generate
,點擊Run
即可何鸡。 - 在命令行中運行,需要切換到項目
pom.xml
文件所在的目錄,運行命令mvn mybatis-generator:generate
即可氢惋。
執(zhí)行完之后會發(fā)現(xiàn)項目中已經(jīng)創(chuàng)好了相應的類以及接口文件,項目結構圖:
實體類demo:
package com.web.springboot.entity;
import java.io.Serializable;
public class SysUser implements Serializable {
private Integer id;
private String usercode;
private String username;
private String password;
private String salt;
private String locked;
private static final long serialVersionUID = 1L;
//省略getter.setter方法
}
sql
接口demo:
package com.web.springboot.dao;
import com.web.springboot.entity.SysUser;
import java.util.List;
public interface SysUserMapper {
int deleteByPrimaryKey(Integer id);
int insert(SysUser record);
SysUser selectByPrimaryKey(Integer id);
List<SysUser> selectAll();
int updateByPrimaryKey(SysUser record);
}
xml
文件demo:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.web.springboot.dao.SysUserMapper" >
<resultMap id="BaseResultMap" type="com.web.springboot.entity.SysUser" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="usercode" property="usercode" jdbcType="VARCHAR" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<result column="salt" property="salt" jdbcType="VARCHAR" />
<result column="locked" property="locked" jdbcType="CHAR" />
</resultMap>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from sys_user
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.web.springboot.entity.SysUser" >
<selectKey resultType="java.lang.Integer" keyProperty="id" order="BEFORE" >
SELECT LAST_INSERT_ID()
</selectKey>
insert into sys_user (id, usercode, username,
`password`, salt, locked
)
values (#{id,jdbcType=INTEGER}, #{usercode,jdbcType=VARCHAR}, #{username,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR}, #{salt,jdbcType=VARCHAR}, #{locked,jdbcType=CHAR}
)
</insert>
<update id="updateByPrimaryKey" parameterType="com.web.springboot.entity.SysUser" >
update sys_user
set usercode = #{usercode,jdbcType=VARCHAR},
username = #{username,jdbcType=VARCHAR},
`password` = #{password,jdbcType=VARCHAR},
salt = #{salt,jdbcType=VARCHAR},
locked = #{locked,jdbcType=CHAR}
where id = #{id,jdbcType=INTEGER}
</update>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select id, usercode, username, `password`, salt, locked
from sys_user
where id = #{id,jdbcType=INTEGER}
</select>
<select id="selectAll" resultMap="BaseResultMap" >
select id, usercode, username, `password`, salt, locked
from sys_user
</select>
</mapper>
我使用過的就這兩種,親測可行熊赖,還有其他的方式,具體請參考官方文檔【傳送門】
配置中的一些常見錯誤及解決方式
-
pom.xml
文件中添加完插件之后報錯如下:Plugin execution not covered by lifecycle configuration: org.mybatis.generator:mybatis-generator-maven-plugin:1.3.2:generate (execution: Generate MyBatis Artifacts, phase: generate-sources)
解決方式:在
<plugins>
標簽外再套一個<pluginManagement>
標簽,如下:<build> <pluginManagement> <plugins> <plugin> ... </plugin> <plugin> ... </plugin> .... </plugins> </pluginManagement> </build>
如果還沒解決可以參照這里【傳送門】
-
執(zhí)行插件的時候失敗并報錯如下:
在這里插入圖片描述這一類錯誤出現(xiàn)的最多俱笛,解決的辦法也不是唯一的传趾,我根據(jù)自己的踩坑以及網(wǎng)上的資料提供兩個大的方向。
解決方式:
- 插件版本問題磕仅,可以網(wǎng)上搜索換一個版本試試簸呈。
-
generatorConfig.xml
里邊有錯誤,比如變量名不對蜕便,包名不對等,仔細檢查往往有驚喜兼贸。
整合PageHelper
PageHelper
是一款非常簡單的分頁插件,只需要兩行代碼即可鸯檬,不需要我們自己編寫sql
語句螺垢,自動幫我們實現(xiàn),非常好用,下面開始介紹Spring boot
整合PageHelper
枉圃。
添加依賴
首先在pom.xml
文件中添加依賴,如下:
<!-- springboot分頁插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<!-- 特別注意版本問題 -->
<version>1.2.3</version>
</dependency>
添加這個依賴之后坎穿,我們其實不需要再添加mybatis-spring-boot-starter
的依賴了返劲,因為pagehelper-spring-boot-starter
已經(jīng)將其包含在其中了。
配置文件中添加配置
在aiilication.properties
文件中添加如下內(nèi)容:
#pageHelper配置
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.params=count=countSql
pagehelper.supportMethodsArguments=true
這里簡單介紹下幾個參數(shù)的意思孵延,網(wǎng)上的教程普遍沒寫亲配,這里介紹下:
-
helperDialect
:配置使用哪種數(shù)據(jù)庫語言,不配置的話pageHelper也會自動檢測,我這里使用的mysql
犬钢。 -
reasonable
:配置分頁參數(shù)合理化功能思灰,默認是false。啟用合理化時官辈,如果pageNum<1會查詢第一頁,如果pageNum>總頁數(shù)會查詢最后一頁晴股; 禁用合理化時电湘,如果pageNum<1或pageNum>總頁數(shù)會返回空數(shù)據(jù)。 -
params
:為了支持startPage(Object params)
方法寂呛,增加了該參數(shù)來配置參數(shù)映射,用于從對象中根據(jù)屬性名取值幻妓, 可以配置pageNum
,pageSize
,count
,pageSizeZero
,reasonable
劫拢,不配置映射的用默認值,默認值為pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
妹沙。 -
supportMethodsArguments
:支持通過Mapper
接口參數(shù)來傳遞分頁參數(shù)距糖,默認值false
,分頁插件會從查詢方法的參數(shù)值中悍引,自動根據(jù)上面params
配置的字段中取值缸剪,查找到合適的值時就會自動分頁杏节。
更多參數(shù)的介紹請移步【傳送門】
代碼中使用
經(jīng)過上面的介紹使用MBG
已經(jīng)為我們創(chuàng)建好了實體類典阵,sql
接口以及xml
文件,現(xiàn)在我們需要創(chuàng)建service
層嫉鲸,這里我們利用泛型知識先創(chuàng)建一個service
層的基類接口IBaseService.java
歹啼,之后所有的service
接口都繼承這個基類接口,這在實際的項目中是很有必要的,減少重復沒必要的操作狸眼,代碼如下:
package com.web.springboot.service;
import java.util.List;
/**
* @author Promise
* @createTime 2019年1月20日 下午8:24:40
* @description service接口層基類,包含基本的 CRUD操作岁钓。
*/
public interface IBaseService<T> {
/**
* 根據(jù)主鍵刪除
* @param id
* @return
*/
int deleteByPrimaryKey(Object id);
/**
* 新增一條記錄
* @param entity
* @return
*/
int insert(T entity);
/**
* 根據(jù)主鍵查詢
* @param id
* @return
*/
T selectByPrimaryKey(Object id);
/**
* 查詢?nèi)坑涗? * @return
*/
List<T> selectAll();
/**
* 根據(jù)主鍵修改數(shù)據(jù)
* @param entity
* @return
*/
int updateByPrimaryKey(T entity);
}
該基類接口定義了基本的CRUD
操作,我這里寫的比較簡單品嚣,實際中完全可以根據(jù)自己的需求完善钧大。
然后創(chuàng)建ISysUserService.java
接口拓型,繼承該基類接口,并定義兩個我們驗證pageHelper
的方法:
package com.web.springboot.service;
import java.util.List;
import com.github.pagehelper.PageInfo;
import com.web.springboot.entity.SysUser;
/**
* @author Promise
* @createTime 2019年1月20日 下午8:31:09
* @description
*/
public interface ISysUserService extends IBaseService<SysUser>{
List<SysUser> findAllByPage(int pageNum, int pageSize);
PageInfo<SysUser> findAllByPage2(int pageNum, int pageSize);
}
-
findAllByPage
:實現(xiàn)簡單的分頁劣挫,返回所需對象的list
集合,其中參數(shù)pageNum
代表當前頁压固,pageSize
代表每頁多少條數(shù)據(jù)。 -
findAllByPage2
:實現(xiàn)簡單的分頁坎炼,返回PageInfo<T>
對象拦键,包括所需對象的list
集合,還包括數(shù)據(jù)庫總記錄數(shù)芬为,總頁數(shù),當前頁氧敢,下一頁等諸多信息,其中參數(shù)pageNum
代表當前頁询张,pageSize
代表每頁多少條數(shù)據(jù)。
可以根據(jù)項目實際需要選擇使用哪一種方法份氧。
接口實現(xiàn)類SysUserServiceImpl.java
,代碼如下:
package com.web.springboot.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.web.springboot.dao.SysUserMapper;
import com.web.springboot.entity.SysUser;
import com.web.springboot.service.ISysUserService;
/**
* @author Promise
* @createTime 2019年1月20日 下午8:31:50
* @description
*/
@Service("sysUserService")
public class SysUserServiceImpl implements ISysUserService{
@Autowired
private SysUserMapper sysUserMapper;
@Override
public int deleteByPrimaryKey(Object id) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int insert(SysUser entity) {
// TODO Auto-generated method stub
return 0;
}
@Override
public SysUser selectByPrimaryKey(Object id) {
// TODO Auto-generated method stub
return sysUserMapper.selectByPrimaryKey((Integer)id);
}
@Override
public List<SysUser> selectAll() {
// TODO Auto-generated method stub
return null;
}
@Override
public int updateByPrimaryKey(SysUser entity) {
// TODO Auto-generated method stub
return 0;
}
@Override
public List<SysUser> findAllByPage(int pageNum, int pageSize) {
// TODO Auto-generated method stub
PageHelper.startPage(pageNum, pageSize);
List<SysUser> lists = sysUserMapper.selectAll();
return lists;
}
@Override
public PageInfo<SysUser> findAllByPage2(int pageNum, int pageSize) {
// TODO Auto-generated method stub
PageHelper.startPage(pageNum, pageSize);
List<SysUser> lists = sysUserMapper.selectAll();
PageInfo<SysUser> pageInfo = new PageInfo<SysUser>(lists);
return pageInfo;
}
}
可以看到該類中實現(xiàn)了我們在基類接口IBaseService.java
以及ISysUSerService.java
里邊定義的所有方法,這里我們先重點關注findAllByPage(int pageNum, int pageSize)
方法中的
PageHelper.startPage(pageNum, pageSize);
List<SysUser> lists = sysUserMapper.selectAll();
這段代碼钮糖,第一句使用了我們的分頁插件酌住,就這一句即可酪我,需要注意的是查詢語句必須緊跟這一句且叁,且只能使用一次,意思就是如果還有一個分頁查詢需要再定義一次PageHelper.startPage(pageNum, pageSize)
逞带。
再來說findAllByPage2(int pageNum, int pageSize)
方法,只比上邊的方法多一句話穆趴,且返回結果不一樣
PageInfo<SysUser> pageInfo = new PageInfo<SysUser>(lists);
當然,PageHelper
還有其它的多種使用方式遇汞,上面的方式要想保證正確性必須要查詢代碼緊跟分頁代碼才行,需要程序員去控制络它,這就增加了出現(xiàn)錯誤的幾率化戳,所以這里再介紹一種更為安全的方式--ISelect
接口方式:
findAllByPage(int pageNum, int pageSize)
改版:
@Override
public List<SysUser> findAllByPage(int pageNum, int pageSize) {
//這種寫法需要jdk8 lambda用法
Page<SysUser> page = PageHelper.startPage(pageNum, pageSize).doSelectPage(()-> sysUserMapper.selectAll());
//如果是低版本的jdk,則使用如下寫法(兩種寫法根據(jù)自己jdk版本二選一)
Page<SysUser> page = PageHelper.startPage(pageNum, pageSize).doSelectPage(new ISelect() {
@Override
public void doSelect() {
sysUserMapper.selectAll();
}
});
return page;
}
看到這里有的朋友或許會發(fā)現(xiàn)我們返回的是一個
Page<SysUser>
對象,而方法定義的是一個List<SysUser>
對象点楼,這里我直接貼出PageHelper
中該方法定義的源碼大家就一目了然了:
public class Page<E> extends ArrayList<E> implements Closeable {
//為了不占過多的篇幅递鹉,這里只貼出方法定義的源碼藏斩,想要了解具體內(nèi)容請自行查看源碼。
//可以看到該方法繼承了ArrayList<T>這也是我們可以直接返回Page<SysUser>的原因媳拴。
}
findAllByPage2(int pageNum, int pageSize)
改版:
@Override
public PageInfo<SysUser> findAllByPage2(int pageNum, int pageSize) {
//這種寫法需要jdk8 lambda用法
PageInfo<SysUser> pageInfo = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(()-> sysUserMapper.selectAll());
//如果是低版本的jdk,則使用如下寫法(兩種寫法根據(jù)自己jdk版本二選一)
PageInfo<SysUser> pageInfo = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(new ISelect() {
@Override
public void doSelect() {
sysUserMapper.selectAll();
}
});
return pageInfo;
}
這里就給出這兩種使用PageHelper
的方法了兆览,想要了解更多請移步【傳送門】
接下來創(chuàng)建測試控制器TestController.java
,如下:
package com.web.springboot.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.github.pagehelper.PageInfo;
import com.web.springboot.entity.SysUser;
import com.web.springboot.service.ISysUserService;
/**
* @author Promise
* @createTime 2019年1月20日 下午8:21:02
* @description
*/
@RestController
public class TestController {
@Autowired
private ISysUserService sysUserService;
@RequestMapping("/users/{pageNum}/{pageSize}")
public Object getAllUser(@PathVariable int pageNum, @PathVariable int pageSize) {
List<SysUser> lists=sysUserService.findAllByPage(pageNum, pageSize);
return lists;
}
@RequestMapping("/users2/{pageNum}/{pageSize}")
public Object getAllUser2(@PathVariable int pageNum, @PathVariable int pageSize) {
PageInfo<SysUser> pageInfo=sysUserService.findAllByPage2(pageNum, pageSize);
return pageInfo;
}
}
好了抬探,代碼就編寫完成了帆赢!
驗證分頁
在這之前,我們需要在數(shù)據(jù)中準備一些數(shù)據(jù)线梗,這里先貼上我的數(shù)據(jù)庫數(shù)據(jù)情況椰于,實際以自身的數(shù)據(jù)庫數(shù)據(jù)為準:
啟動項目,瀏覽器訪問localhost:8080/users/1/2
仪搔,表示訪問第一頁瘾婿,每頁兩條數(shù)據(jù),結果如下:
對比數(shù)據(jù)庫烤咧,數(shù)據(jù)返回正確偏陪,接下來訪問localhost:8080/user2/1/2
,結果如下:
發(fā)現(xiàn)json
數(shù)據(jù)沒有格式,不利于我們查看煮嫌,可以使用在線json
格式轉(zhuǎn)化工具格式化內(nèi)容如下:
{
"pageNum": 1,
"pageSize": 2,
"size": 2,
"startRow": 1,
"endRow": 2,
"total": 6,
"pages": 3,
"list": [{
"id": 1,
"usercode": "Promise",
"username": "eran",
"password": "123456",
"salt": null,
"locked": "0"
}, {
"id": 2,
"usercode": "Promise2",
"username": "eran",
"password": "123456",
"salt": null,
"locked": "0"
}],
"prePage": 0,
"nextPage": 2,
"isFirstPage": true,
"isLastPage": false,
"hasPreviousPage": false,
"hasNextPage": true,
"navigatePages": 8,
"navigatepageNums": [1, 2, 3],
"navigateFirstPage": 1,
"navigateLastPage": 3,
"lastPage": 3,
"firstPage": 1
}
可以發(fā)現(xiàn)返回了很多有用的內(nèi)容朴恳,這里就不一一介紹了寸认,字段都淺顯易懂,實際開發(fā)中我們可以根據(jù)需要選擇使用哪種方式。
結語
關于Spring boot
整合MBG
以及pageHelper
的內(nèi)容就到這里了,下篇博客見洲守。bye~