最簡(jiǎn)單的通用Mapper的使用手冊(cè)不了解一下?
目錄
通用Mapper的定義
通用Mapper 是一個(gè) Mybatis 的增強(qiáng)工具,在 Mybatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生。開發(fā)人員可以隨意的按照自己的需要選擇通用方法,還可以很方便的開發(fā)自己的通用方法,極其方便的使用MyBatis單表的增刪改查。
本文下從如下三個(gè)方面來介紹:
- SpringBoot如何整合通用mapper
- 如何使用通用Mapper的方法
- 通用方法怎么來的
SpringBoot如何整合通用mapper
第一步:引入依賴
<!--mapper需要依賴jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--MyBatis 通用 Mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.1.4</version>
</dependency>
<!-- SpringBoot - MyBatis 逆向工程 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- mysql連接需要的類 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
如上我們需要引入四個(gè)依賴一個(gè)是jpa依賴,一個(gè)是通用Mapper自身的依賴,一個(gè)是MyBatis逆向工程需要的依賴,最后就是連接mysql的依賴。依賴引入之后,接下來就是配置逆向工程。(PS:逆向工程就是幫助我們生成Model,Dao以及XML)。
第二步:配置逆向工程
- 首先我們需要在resources目錄下新建一個(gè)屬性文件
config.properties
用來定義數(shù)據(jù)庫連接,生成類的目標(biāo)包等信息。定義如下:
#jdbcConnection 連接
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatisdemo?useUnicode=true&characterEncoding=utf8
jdbc.user=root
jdbc.password=admin
#targetProject是包所在的位置
#mac 下
targetProject=/Volumes/Develop/WorkSpace/auto_java/auto-mapper-demo/src/main/
#model的目標(biāo)包名
modelTargetPackage=com.jay.model
#dao的目標(biāo)包名
daoTargetPackage=com.jay.mapper
- 前面我們新建的屬性文件其實(shí)是給后面的XML文件用的,接下來我們就來看看XML文件
generatorConfig.xml
吧。
<!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="config.properties"/>
<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!--配置生成類的插件-->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
<property name="caseSensitive" value="true"/>
</plugin>
<!--連接數(shù)據(jù)庫-->
<jdbcConnection driverClass="${jdbc.driverClass}"
connectionURL="${jdbc.url}"
userId="${jdbc.user}"
password="${jdbc.password}">
</jdbcConnection>
<!--指定model的生成路徑-->
<javaModelGenerator targetPackage="${modelTargetPackage}"
targetProject="${targetProject}/java"/>
<!--指定mapper的生成路徑-->
<sqlMapGenerator targetPackage="mapper"
targetProject="${targetProject}/resources"/>
<!--指定dao的生成路徑-->
<javaClientGenerator targetPackage="${daoTargetPackage}"
targetProject="${targetProject}/java"
type="XMLMAPPER"/>
<!--指定需要生成Model,Dao,Xml的數(shù)據(jù)表-->
<table tableName="classroom"></table>
</context>
</generatorConfiguration>
需要注意的是定義的屬性名要與屬性文件中的一致,比如jdbc.driverClass
第三步:定義逆向工程的啟動(dòng)類
將相關(guān)的必要的配置弄好之后,接下來我們就來定義逆向工程的啟動(dòng)類。這個(gè)啟動(dòng)類的代碼也相對(duì)比較簡(jiǎn)單,代碼如下所示:
public class Generator {
public static InputStream getResourceAsStream(String path){
return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
}
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(getResourceAsStream("generatorConfig.xml"));
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
for (String warning : warnings) {
System.out.println(warning);
}
}
}
第四步 測(cè)試逆向工程
準(zhǔn)備工作都做好之后,接下來,我們就來測(cè)試生成model,dao,XML等文件吧。我們直接運(yùn)行Generator類正常的話就可以得到生成的Model,Dao和XML,生成結(jié)果如下圖所示:
怎么用?
如何調(diào)用方法?
說完了逆向工程,生成了我們需要的Dao類之后,接下來我們就要看看怎么使用了Dao類,調(diào)用其擁有的通用方法,其實(shí)調(diào)用也相當(dāng)簡(jiǎn)單。下面我先給出一個(gè)調(diào)用示例:
我們定義了一個(gè)ClassroomServiceImpl
業(yè)務(wù)類,并且實(shí)現(xiàn)了三個(gè)方法,分別是調(diào)用insert
方法保存班級(jí),調(diào)用selectByPrimaryKey
方法根據(jù)主鍵查找班級(jí),調(diào)用select
方法根據(jù)班級(jí)名稱查找班級(jí)。這些方法都是ClassroomMapper接口中自帶的方法。
@Service
public class ClassroomServiceImpl implements ClassroomService {
@Autowired
private ClassroomMapper classroomMapper;
//保存班級(jí)
@Override
public boolean saveClassroom(Classroom classroom) {
int result = classroomMapper.insert(classroom);
return result == 1 ? true : false;
}
//根據(jù)主鍵查找
@Override
public Classroom getClassroomById(int id) {
Classroom classroom = classroomMapper.selectByPrimaryKey(id);
return classroom;
}
//根據(jù)某個(gè)字段查找
@Override
public List<Classroom> getClassroomByName(String name) {
Classroom param = new Classroom();
param.setName(name);
List<Classroom> classrooms = classroomMapper.select(param);
return classrooms;
}
}
然后,我們?cè)趩?dòng)類中添加一個(gè)掃描Mapper的注解@MapperScan
,這個(gè)注解一定要加,不然會(huì)找不到Mapper接口 。
@SpringBootApplication
//使之可以掃描到mapper接口
@MapperScan(basePackages = "com.jay.mapper")
public class AutoMapperDemoApplication {
public static void main(String[] args) {
SpringApplication.run(AutoMapperDemoApplication.class, args);
System.out.println("********啟動(dòng)項(xiàng)目成功");
}
}
添加完相關(guān)的方法之后,最后就是添加測(cè)試類測(cè)試這些方法是否起作用了,
@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class ClassroomServiceImplTest {
@Autowired
private ClassroomService classroomService;
@Before
public void setUp() {
Classroom classroom = new Classroom();
classroom.setId(3);
classroom.setClassId(3);
classroom.setClassType("0");
classroom.setName("優(yōu)秀的三班");
classroomService.saveClassroom(classroom);
}
//測(cè)試保存班級(jí)
@Test
public void saveClassroom() throws Exception {
Classroom classroom = new Classroom();
classroom.setId(4);
classroom.setClassId(4);
classroom.setClassType("1");
classroom.setName("優(yōu)秀的四班");
boolean b = classroomService.saveClassroom(classroom);
Assert.assertTrue(b);
}
//測(cè)試主鍵查詢
@Test
public void getClassroomById() throws Exception {
Classroom classroomById = classroomService.getClassroomById(3);
Assert.assertEquals("優(yōu)秀的三班", classroomById.getName());
}
//測(cè)試按照名稱查詢
@Test
public void getClassroomByName() throws Exception {
List<Classroom> classrooms = classroomService.getClassroomByName("優(yōu)秀的三班");
Assert.assertEquals("優(yōu)秀的三班", classrooms.get(0).getName());
}
}
運(yùn)行測(cè)試用例的結(jié)果如下:
方法哪里來的
說完了怎么用之后,通用Mapper的使用方法我們就說完了。接下來我們來看看ClassroomMapper中的方法是怎么來的吧,不看代碼我們想當(dāng)然的會(huì)以為這些方法會(huì)在ClassroomMapper接口中有定義,但事實(shí)是這樣子的么? 這里先留一個(gè)彩蛋,請(qǐng)聽我慢慢道來。
首先,我們來看看生成的XML文件。
我們很驚奇的發(fā)現(xiàn)XML里面竟然一條SQL語句都莫得,那對(duì)應(yīng)的ClassroomMapper接口中也應(yīng)該沒有定義相關(guān)的方法呀。那問題來了,這些個(gè)增刪改查的方法是哪里來的呢?
這有點(diǎn)讓人摸不著頭腦,百思不得姐。話不多說,還是讓我們接著看看ClassroomMapper接口吧!
public interface ClassroomMapper extends Mapper<Classroom> {
}
果然,一個(gè)方法都沒有定義,只是繼承了一個(gè)Mapper<Classroom>
接口,那么這些方法就有應(yīng)該來源于是Mapper
接口了,為了驗(yàn)證我們的猜測(cè),讓我們一起來看看這個(gè)自帶神力的Mapper
接口吧。
Mapper
/**
* 通用Mapper接口,其他接口繼承該接口即可
* <p/>
* <p>這是一個(gè)例子,自己擴(kuò)展時(shí)可以參考</p>
* <p/>
* <p>項(xiàng)目地址 : <a target="_blank">https://github.com/abel533/Mapper</a></p>
*
* @param <T> 不能為空
* @author liuzh
*/
public interface Mapper<T> extends
BaseMapper<T>,
ExampleMapper<T>,
RowBoundsMapper<T>,
Marker {
}
哦豁,這個(gè)Mapper
接口里也沒有金屋藏嬌呀,同樣的它也是一個(gè)方法都沒有定義,只是很單純的繼承了BaseMapper
,ExampleMapper
,RowBoundsMapper
和Marker
這四個(gè)接口,其中Marker
只是一個(gè)標(biāo)記接口,暫不在我們的介紹范圍內(nèi)!(PS:不得不說這個(gè)框架的作者牛逼呀)按照上面分析的思路我們很自然的認(rèn)為,這些方法應(yīng)該是由上面的三個(gè)接口定義的。那么就讓它們一一粉墨登場(chǎng)吧。
首先出場(chǎng)的是我們的 BaseMapper接口。
BaseMapper接口
/**
* 通用Mapper接口,其他接口繼承該接口即可
* <p/>
* <p>這是一個(gè)例子,自己擴(kuò)展時(shí)可以參考</p>
* <p/>
* <p>項(xiàng)目地址 : <a target="_blank">https://github.com/abel533/Mapper</a></p>
*
* @param <T> 不能為空
* @author liuzh
*/
public interface BaseMapper<T> extends
BaseSelectMapper<T>,
BaseInsertMapper<T>,
BaseUpdateMapper<T>,
BaseDeleteMapper<T> {
}
朋友們,這完全是跟Mapper
接口一模一樣的套路呀。BaseMapper
接口里面也是啥方法都沒有定義,同樣是繼承了好幾個(gè)接口,一個(gè)是BaseSelectMapper
接口,一個(gè)是BaseInsertMapper
接口,一個(gè)是BaseUpdateMapper
接口,最后一個(gè)是BaseDeleteMapper
。從接口的命名我們不難猜測(cè)出這些個(gè)接口的作用。下面我們就分別介紹下他們。
- 從BaseSelectMapper 接口的定義來看,其主要就是定義基礎(chǔ)的查詢,最簡(jiǎn)單的查詢請(qǐng)交就給它吧。我們進(jìn)入它的身體里一探究竟。
/**
* 通用Mapper接口,基礎(chǔ)查詢
*
* @param <T> 不能為空
* @author liuzh
*/
public interface BaseSelectMapper<T> extends
SelectOneMapper<T>,
SelectMapper<T>,
SelectAllMapper<T>,
SelectCountMapper<T>,
SelectByPrimaryKeyMapper<T>,
ExistsWithPrimaryKeyMapper<T> {
}
套路真的好深呀,進(jìn)到BaseSelectMapper
接還是沒有看到有方法定義,同樣的只是繼承好些個(gè)接口。不要心急,不要煩躁,我們馬上就可以看到真正干活的接口了。這里我選取SelectMapper
接口做一個(gè)剖析。
/**
* 通用Mapper接口,查詢
*
* @param <T> 不能為空
* @author liuzh
*/
public interface SelectMapper<T> {
/**
* 根據(jù)實(shí)體中的屬性值進(jìn)行查詢,查詢條件使用等號(hào)
*
* @param record
* @return
*/
@SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")
List<T> select(T record);
}
看到這兒朋友們是不是恍然大悟,這不就是前面classroomMapper.select(param)
調(diào)用的這個(gè)方法么!??!這個(gè)方法是根據(jù)動(dòng)態(tài)SQL(dynamicSQL)來執(zhí)行SQL語句的。其只能根據(jù)實(shí)體中的屬性值進(jìn)行查詢,并且查詢條件使用等號(hào)。其他的接口也是一樣的道理的。在此就不在贅述了。
總之就是一個(gè)接口里定義一個(gè)方法,并且這個(gè)方法的SQL是動(dòng)態(tài)生成的。
ExampleMapper接口
說完了BaseMapper接口,接下來就讓我們來看看ExampleMapper接口吧,這個(gè)接口的查詢條件是傳入Example來查詢。例如:
可以直接帶關(guān)鍵字查詢,類似于動(dòng)態(tài)的拼接SQL的方式。
@Override
public List<Classroom> getClassByExample() {
Example classRoomExample = new Example(Classroom.class);
Example.Criteria criteria = classRoomExample.createCriteria();
criteria.andLike("name", "%班%");
criteria.andEqualTo("classType", "0");
List<Classroom> classrooms = classroomMapper.selectByExample(classRoomExample);
return classrooms;
}
同樣的ExampleMapper接口也是繼承了SelectByExampleMapper
,SelectCountByExampleMapper
,DeleteByExampleMapper
,UpdateByExampleMapper
已經(jīng)UpdateByExampleSelectiveMapper
這五個(gè)接口,每個(gè)接口里面都定義了一個(gè)方法。也是通過動(dòng)態(tài)SQL來生成執(zhí)行語句。在此就不在贅述了。
/**
* 通用Mapper接口,Example查詢
*
* @param <T> 不能為空
* @author liuzh
*/
public interface ExampleMapper<T> extends
SelectByExampleMapper<T>,
SelectCountByExampleMapper<T>,
DeleteByExampleMapper<T>,
UpdateByExampleMapper<T>,
UpdateByExampleSelectiveMapper<T> {
}
最后,我們來看下RowBoundsMapper接口,這個(gè)接口繼承了SelectByExampleRowBoundsMapper
接口和SelectRowBoundsMapper
接口。主要是配合分頁插件PageHelper來實(shí)現(xiàn)分頁查詢的。分頁查詢可以詳細(xì)看Mybatis-PageHelper分頁插件的使用與相關(guān)原理分析。
RowBoundsMapper接口
/**
* 通用Mapper接口,帶RowBounds參數(shù)的查詢
* <p/>
* 配合分頁插件PageHelper可以實(shí)現(xiàn)物理分頁
* <p/>
* PageHelper - http://git.oschina.net/free/Mybatis_PageHelper
*
* @param <T> 不能為空
* @author liuzh
*/
public interface RowBoundsMapper<T> extends
SelectByExampleRowBoundsMapper<T>,
SelectRowBoundsMapper<T> {
}
總結(jié)
本文首先介紹了如何在SpringBoot中整合通用的Mapper,其中詳細(xì)介紹了逆向工程的使用。接著就是介紹了通用方法的調(diào)用,通用Mapper運(yùn)用動(dòng)態(tài)SQL的方式,省去了編寫SQL的繁瑣,實(shí)現(xiàn)了單表的基本的增刪改查方法,極大的提高了對(duì)單表操作的效率。最后就是介紹了通用Mapper內(nèi)置的方法。希望對(duì)讀者朋友們有所幫助。如有疑問歡迎與我聯(lián)系。
參考
https://github.com/abel533/Mapper
源碼地址:
https://github.com/XWxiaowei/auto-mapper-demo
作者:碼農(nóng)飛哥
微信公眾號(hào):碼農(nóng)飛哥