最簡單的通用Mapper的使用手冊不瞭解一下?

通用Mapper的定義

通用Mapper 是一個 Mybatis 的增強工具,在 Mybatis 的基礎上只做增強不做改變,爲簡化開發、提高效率而生。開發人員可以隨意的按照自己的需要選擇通用方法,還可以很方便的開發自己的通用方法,極其方便的使用MyBatis單表的增刪改查。
本文下從如下三個方面來介紹:

  1. SpringBoot如何整合通用mapper
  2. 如何使用通用Mapper的方法
  3. 通用方法怎麼來的

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>

如上我們需要引入四個依賴一個是jpa依賴,一個是通用Mapper自身的依賴,一個是MyBatis逆向工程需要的依賴,最後就是連接mysql的依賴。依賴引入之後,接下來就是配置逆向工程。(PS:逆向工程就是幫助我們生成Model,Dao以及XML)。

第二步:配置逆向工程

  1. 首先我們需要在resources目錄下新建一個屬性文件config.properties用來定義數據庫連接,生成類的目標包等信息。定義如下:
#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的目標包名
modelTargetPackage=com.jay.model
#dao的目標包名
daoTargetPackage=com.jay.mapper
  1. 前面我們新建的屬性文件其實是給後面的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>

        <!--連接數據庫-->
        <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的數據表-->
        <table tableName="classroom"></table>

    </context>
</generatorConfiguration>

需要注意的是定義的屬性名要與屬性文件中的一致,比如jdbc.driverClass

第三步:定義逆向工程的啓動類

將相關的必要的配置弄好之後,接下來我們就來定義逆向工程的啓動類。這個啓動類的代碼也相對比較簡單,代碼如下所示:

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);
        }
    }
}

第四步 測試逆向工程

準備工作都做好之後,接下來,我們就來測試生成model,dao,XML等文件吧。我們直接運行Generator類正常的話就可以得到生成的Model,Dao和XML,生成結果如下圖所示:

在這裏插入圖片描述

怎麼用?

如何調用方法?

說完了逆向工程,生成了我們需要的Dao類之後,接下來我們就要看看怎麼使用了Dao類,調用其擁有的通用方法,其實調用也相當簡單。下面我先給出一個調用示例:
我們定義了一個ClassroomServiceImpl業務類,並且實現了三個方法,分別是調用insert方法保存班級,調用selectByPrimaryKey方法根據主鍵查找班級,調用select方法根據班級名稱查找班級。這些方法都是ClassroomMapper接口中自帶的方法。

@Service
public class ClassroomServiceImpl implements ClassroomService {
    @Autowired
    private ClassroomMapper classroomMapper;

	//保存班級
    @Override
    public boolean saveClassroom(Classroom classroom) {
        int result = classroomMapper.insert(classroom);
        return result == 1 ? true : false;
    }
	//根據主鍵查找
    @Override
    public Classroom getClassroomById(int id) {
        Classroom classroom = classroomMapper.selectByPrimaryKey(id);
        return classroom;
    }
	//根據某個字段查找
    @Override
    public List<Classroom> getClassroomByName(String name) {
        Classroom param = new Classroom();
        param.setName(name);
        List<Classroom> classrooms = classroomMapper.select(param);
        return classrooms;
    }
}

然後,我們在啓動類中添加一個掃描Mapper的註解@MapperScan,這個註解一定要加,不然會找不到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("********啓動項目成功");
	}
}

添加完相關的方法之後,最後就是添加測試類測試這些方法是否起作用了,

@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("優秀的三班");
        classroomService.saveClassroom(classroom);
    }
	//測試保存班級
    @Test
    public void saveClassroom() throws Exception {
        Classroom classroom = new Classroom();
        classroom.setId(4);
        classroom.setClassId(4);
        classroom.setClassType("1");
        classroom.setName("優秀的四班");
        boolean b = classroomService.saveClassroom(classroom);
        Assert.assertTrue(b);
    }
	//測試主鍵查詢
    @Test
    public void getClassroomById() throws Exception {
        Classroom classroomById = classroomService.getClassroomById(3);
        Assert.assertEquals("優秀的三班", classroomById.getName());
    }
	//測試按照名稱查詢
    @Test
    public void getClassroomByName() throws Exception {
        List<Classroom> classrooms = classroomService.getClassroomByName("優秀的三班");
        Assert.assertEquals("優秀的三班", classrooms.get(0).getName());

    }
}

運行測試用例的結果如下:
在這裏插入圖片描述

方法哪裏來的

說完了怎麼用之後,通用Mapper的使用方法我們就說完了。接下來我們來看看ClassroomMapper中的方法是怎麼來的吧,不看代碼我們想當然的會以爲這些方法會在ClassroomMapper接口中有定義,但事實是這樣子的麼? 這裏先留一個彩蛋,請聽我慢慢道來。
首先,我們來看看生成的XML文件。
在這裏插入圖片描述
我們很驚奇的發現XML裏面竟然一條SQL語句都莫得,那對應的ClassroomMapper接口中也應該沒有定義相關的方法呀。那問題來了,這些個增刪改查的方法是哪裏來的呢?
在這裏插入圖片描述
這有點讓人摸不着頭腦,百思不得姐。話不多說,還是讓我們接着看看ClassroomMapper接口吧!

public interface ClassroomMapper extends Mapper<Classroom> {
}

果然,一個方法都沒有定義,只是繼承了一個Mapper<Classroom>接口,那麼這些方法就有應該來源於是Mapper接口了,爲了驗證我們的猜測,讓我們一起來看看這個自帶神力的Mapper接口吧。

Mapper

/**
 * 通用Mapper接口,其他接口繼承該接口即可
 * <p/>
 * <p>這是一個例子,自己擴展時可以參考</p>
 * <p/>
 * <p>項目地址 : <a href="https://github.com/abel533/Mapper" 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 {

}

哦豁,這個Mapper接口裏也沒有金屋藏嬌呀,同樣的它也是一個方法都沒有定義,只是很單純的繼承了BaseMapperExampleMapperRowBoundsMapperMarker這四個接口,其中Marker只是一個標記接口,暫不在我們的介紹範圍內!(PS:不得不說這個框架的作者牛逼呀)按照上面分析的思路我們很自然的認爲,這些方法應該是由上面的三個接口定義的。那麼就讓它們一一粉墨登場吧。
首先出場的是我們的 BaseMapper接口。

BaseMapper接口

/**
 * 通用Mapper接口,其他接口繼承該接口即可
 * <p/>
 * <p>這是一個例子,自己擴展時可以參考</p>
 * <p/>
 * <p>項目地址 : <a href="https://github.com/abel533/Mapper" 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接口裏面也是啥方法都沒有定義,同樣是繼承了好幾個接口,一個是BaseSelectMapper接口,一個是BaseInsertMapper接口,一個是BaseUpdateMapper接口,最後一個是BaseDeleteMapper。從接口的命名我們不難猜測出這些個接口的作用。下面我們就分別介紹下他們。

  1. 從BaseSelectMapper 接口的定義來看,其主要就是定義基礎的查詢,最簡單的查詢請交就給它吧。我們進入它的身體裏一探究竟。

/**
 * 通用Mapper接口,基礎查詢
 *
 * @param <T> 不能爲空
 * @author liuzh
 */
public interface BaseSelectMapper<T> extends
        SelectOneMapper<T>,
        SelectMapper<T>,
        SelectAllMapper<T>,
        SelectCountMapper<T>,
        SelectByPrimaryKeyMapper<T>,
        ExistsWithPrimaryKeyMapper<T> {
}

套路真的好深呀,進到BaseSelectMapper接還是沒有看到有方法定義,同樣的只是繼承好些個接口。不要心急,不要煩躁,我們馬上就可以看到真正幹活的接口了。這裏我選取SelectMapper接口做一個剖析。

/**
 * 通用Mapper接口,查詢
 *
 * @param <T> 不能爲空
 * @author liuzh
 */
public interface SelectMapper<T> {

    /**
     * 根據實體中的屬性值進行查詢,查詢條件使用等號
     *
     * @param record
     * @return
     */
    @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")
    List<T> select(T record);

}

看到這兒朋友們是不是恍然大悟,這不就是前面classroomMapper.select(param)調用的這個方法麼!!!這個方法是根據動態SQL(dynamicSQL)來執行SQL語句的。其只能根據實體中的屬性值進行查詢,並且查詢條件使用等號。其他的接口也是一樣的道理的。在此就不在贅述了。
總之就是一個接口裏定義一個方法,並且這個方法的SQL是動態生成的。

ExampleMapper接口

說完了BaseMapper接口,接下來就讓我們來看看ExampleMapper接口吧,這個接口的查詢條件是傳入Example來查詢。例如:
可以直接帶關鍵字查詢,類似於動態的拼接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接口也是繼承了SelectByExampleMapperSelectCountByExampleMapperDeleteByExampleMapperUpdateByExampleMapper已經UpdateByExampleSelectiveMapper這五個接口,每個接口裏面都定義了一個方法。也是通過動態SQL來生成執行語句。在此就不在贅述了。

/**
 * 通用Mapper接口,Example查詢
 *
 * @param <T> 不能爲空
 * @author liuzh
 */
public interface ExampleMapper<T> extends
        SelectByExampleMapper<T>,
        SelectCountByExampleMapper<T>,
        DeleteByExampleMapper<T>,
        UpdateByExampleMapper<T>,
        UpdateByExampleSelectiveMapper<T> {

}

最後,我們來看下RowBoundsMapper接口,這個接口繼承了SelectByExampleRowBoundsMapper接口和SelectRowBoundsMapper接口。主要是配合分頁插件PageHelper來實現分頁查詢的。分頁查詢可以詳細看Mybatis-PageHelper分頁插件的使用與相關原理分析

RowBoundsMapper接口

/**
 * 通用Mapper接口,帶RowBounds參數的查詢
 * <p/>
 * 配合分頁插件PageHelper可以實現物理分頁
 * <p/>
 * PageHelper - http://git.oschina.net/free/Mybatis_PageHelper
 *
 * @param <T> 不能爲空
 * @author liuzh
 */
public interface RowBoundsMapper<T> extends
        SelectByExampleRowBoundsMapper<T>,
        SelectRowBoundsMapper<T> {

}

總結

本文首先介紹瞭如何在SpringBoot中整合通用的Mapper,其中詳細介紹了逆向工程的使用。接着就是介紹了通用方法的調用,通用Mapper運用動態SQL的方式,省去了編寫SQL的繁瑣,實現了單表的基本的增刪改查方法,極大的提高了對單表操作的效率。最後就是介紹了通用Mapper內置的方法。希望對讀者朋友們有所幫助。如有疑問歡迎與我聯繫。

參考

https://github.com/abel533/Mapper

源碼地址:

https://github.com/XWxiaowei/auto-mapper-demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章