天天看點

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

目錄

  • ​​通用Mapper的定義​​
  • ​​SpringBoot如何整合通用mapper​​
  • ​​第一步:引入依賴​​
  • ​​第二步:配置逆向工程​​
  • ​​第三步:定義逆向工程的啟動類​​
  • ​​第四步 測試逆向工程​​
  • ​​怎麼用?​​
  • ​​如何調用方法?​​
  • ​​方法哪裡來的​​
  • ​​Mapper​​
  • ​​BaseMapper接口​​
  • ​​ExampleMapper接口​​
  • ​​RowBoundsMapper接口​​
  • ​​總結​​
  • ​​參考​​
  • ​​源碼位址:​​

通用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,生成結果如下圖所示:

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

怎麼用?

如何調用方法?

說完了逆向工程,生成了我們需要的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的使用手冊不了解一下?

方法哪裡來的

說完了怎麼用之後,通用Mapper的使用方法我們就說完了。接下來我們來看看ClassroomMapper中的方法是怎麼來的吧,不看代碼我們想當然的會以為這些方法會在ClassroomMapper接口中有定義,但事實是這樣子的麼? 這裡先留一個彩蛋,請聽我慢慢道來。

首先,我們來看看生成的XML檔案。

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

我們很驚奇的發現XML裡面竟然一條SQL語句都莫得,那對應的ClassroomMapper接口中也應該沒有定義相關的方法呀。那問題來了,這些個增删改查的方法是哪裡來的呢?

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

這有點讓人摸不着頭腦,百思不得姐。話不多說,還是讓我們接着看看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​

​​接口裡也沒有金屋藏嬌呀,同樣的它也是一個方法都沒有定義,隻是很單純的繼承了​

​BaseMapper​

​​,​

​ExampleMapper​

​​,​

​RowBoundsMapper​

​​和​

​Marker​

​​這四個接口,其中​

​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接口也是繼承了​

​SelectByExampleMapper​

​​,​

​SelectCountByExampleMapper​

​​,​

​DeleteByExampleMapper​

​​,​

​UpdateByExampleMapper​

​​已經​

​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 -
 *
 * @param <T> 不能為空
 * @author liuzh
 */
public interface RowBoundsMapper<T> extends
        SelectByExampleRowBoundsMapper<T>,
        SelectRowBoundsMapper<T> {

}      

總結

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

參考

源碼位址: