1. 程式人生 > >一起來學SpringBoot(十五)MybatisPlus的整合

一起來學SpringBoot(十五)MybatisPlus的整合

MyBatis-Plus(簡稱 MP)是一個MyBatis的增強工具 ,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。本篇文章介紹的是與springboot的整合。

在這裡插入圖片描述

特性

  • 無侵入:只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑

  • 損耗小:啟動即會自動注入基本 CURD,效能基本無損耗,直接面向物件操作

  • 強大的 CRUD 操作:內建通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求

  • 支援 Lambda 形式呼叫:通過 Lambda 表示式,方便的編寫各類查詢條件,無需再擔心欄位寫錯

  • 支援多種資料庫:支援 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多種資料庫

  • 支援主鍵自動生成:支援多達 4 種主鍵策略(內含分散式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題

  • 支援 XML 熱載入:Mapper 對應的 XML 支援熱載入,對於簡單的 CRUD 操作,甚至可以無 XML 啟動

  • 支援 ActiveRecord 模式:支援 ActiveRecord 形式呼叫,實體類只需繼承 Model 類即可進行強大的 CRUD 操作

  • 支援自定義全域性通用操作

    :支援全域性通用方法注入( Write once, use anywhere )

  • 支援關鍵詞自動轉義:支援資料庫關鍵詞(order、key…)自動轉義,還可自定義關鍵詞

  • 內建程式碼生成器:採用程式碼或者 Maven 外掛可快速生成 Mapper 、 Model 、 Service 、 Controller 層程式碼,支援模板引擎,更有超多自定義配置等您來使用

  • 內建分頁外掛:基於 MyBatis 物理分頁,開發者無需關心具體操作,配置好外掛之後,寫分頁等同於普通 List 查詢

  • 內建效能分析外掛:可輸出 Sql 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢

  • 內建全域性攔截外掛

    :提供全表 delete 、 update 操作智慧分析阻斷,也可自定義攔截規則,預防誤操作

  • 內建 Sql 注入剝離器:支援 Sql 注入剝離,有效預防 Sql 注入攻擊

    不要忘記依賴

    <!-- mp -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>
    

程式碼生成器

不多說這個非常爽,執行下能生成基本結構。我這裡稍微加了點註釋,寫好表名直接執行就ok了

package com.maoxs.generator;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;

/**
 * @author fulin
 * @since 2018-09-12
 */
public class MysqlGenerator {

    public static void Generator(String[] tableName) {

        String projectPath = System.getProperty("user.dir");

        //============================== 全域性配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(projectPath + "/springboot-mybatisplus/src/main/java")
                .setActiveRecord(true)// 是否支援 AR
                .setAuthor("fulin") //設定作者名字
                .setFileOverride(true) //檔案覆蓋(全新檔案)
                .setIdType(IdType.AUTO)//主鍵策略
                .setBaseResultMap(true) //SQL 對映檔案
                .setBaseColumnList(true)//SQL 片段
                .setOpen(false);
        //============================== 資料來源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MARIADB)
                .setUrl("jdbc:mariadb://localhost:3306/test")
                .setDriverName("org.mariadb.jdbc.Driver")
                .setUsername("root")
                //.setSchemaName("public")
                .setPassword("123456");
        //==============================包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.maoxs")//配置父包路徑
                .setModuleName("base")//配置業務包路徑
                .setMapper("mapper")
                .setEntity("entity")
                .setService("service")
                .setController("controller");
        //.setServiceImpl("service.impl"); 會自動生成 impl,可以不設定
        //============================== 自定義配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定義輸入檔名稱
                return projectPath + "/springboot-mybatisplus/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        //============================== 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel)//設定命名規則  underline_to_camel 底線變駝峰
                .setColumnNaming(NamingStrategy.underline_to_camel)//設定設定列命名  underline_to_camel 底線變駝峰
                //.setSuperEntityClass("com.maoxs.pojo")//設定繼承類
                //.setSuperControllerClass("com.maoxs.controller")//設定繼承類
                .setEntityLombokModel(true)//是否加入lombok
                .setInclude(tableName)//設定表名
                //.setSuperEntityColumns("id") //設定超級超級列
                .setControllerMappingHyphenStyle(true)//設定controller對映聯字元
                .setTablePrefix(pc.getModuleName() + "_");//表的字首
        //============================== 生成配置
        AutoGenerator mpg = new AutoGenerator();
        mpg.setCfg(cfg)
                .setTemplate(new TemplateConfig().setXml(null))
                .setGlobalConfig(gc)
                .setDataSource(dsc)
                .setPackageInfo(pc)
                .setStrategy(strategy)
                // 選擇 freemarker 引擎需要指定如下加,注意 pom 依賴必須有!
                .setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
    public static void main(String[] args) {
        Generator(new String[]{"x", "xx"});
    }
}

這只是生成程式碼的工作,然後呢為了確保你生成的Mapper介面可以掃描到,還需要這樣的一個配置

package com.maoxs.conf;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author fulin
 * @since 2018-09-10
 */
@Configuration
@MapperScan("com.maoxs.base.mapper")
public class MybatisPlusConfig {

}

@MapperScan 是用來掃描你mapper所在的包,多個包的話英文逗號隔開即可。剩下的大多數MybatisPlus的配置基本都是在這裡配置。

crud

這邊就闡述什麼表名什麼的,可以自己嘗試建立,這裡只提到怎麼使用,重要的配置我會貼出.

這邊呢就貼出一個簡單的增刪改查的測試類。

package com.maoxs.crud;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.maoxs.SpringbootMybatisplusApplicationTests;
import com.maoxs.base.entity.User;
import com.maoxs.base.mapper.UserMapper;
import org.junit.Assert;
import org.junit.Test;

import javax.annotation.Resource;

public class CrudTest extends SpringbootMybatisplusApplicationTests {
    @Resource
    private UserMapper userMapper;

    @Test
    public void Insert() {
        User user = new User();
        user.setAge(17);
        user.setName("我是付林");
        int num = userMapper.insert(user);
        Assert.assertTrue(num > 0);
        System.out.println("插入成功Id為" + user.getId());
    }

    @Test
    public void Delete() {
        Assert.assertTrue(userMapper.deleteById(14L) > 0);
        Assert.assertTrue(userMapper.delete(new QueryWrapper<User>().lambda().eq(User::getName, "我是付林")) > 0);
    }

    @Test
    public void Update() {
        Assert.assertTrue(userMapper.updateById(new User().setId(1L).setAge(100).setName("我是付林")) > 0);
        Assert.assertTrue(userMapper.update(new User(),
                new UpdateWrapper<User>().lambda().set(User::getAge, 2).eq(User::getId, 2)
        ) > 0);
    }

    @Test
    public void Select() {
        Assert.assertEquals("cfulin", userMapper.selectById(3L).getName());
        User user = userMapper.selectOne(new QueryWrapper<User>().lambda().eq(User::getId, 2));
        Assert.assertEquals("付林1", user.getName());
        Assert.assertTrue(2 == user.getAge());
    }
}

這裡呢說明一下Wrapper 這可是個好玩的東西,相當於QBC那樣的動態sql拼接,這裡mybatisplus是3.0以上的版本,算是一個大版本,這裡呢條件的拼接呢都使用了 lambda 方式。如果不想使用,比如new QueryWrapper().lambda().eq(User::getId, 2) 可以寫為new QueryWrapper().eq(“id”, 2)

AR(ActiveRecord)

在web後臺開發領域,經常會遇到應用程式操作資料庫的場景,目前市面上存在的資料庫包括mysql、postgresql、oracle、sqlite等,為了遮蔽不同資料庫的差異,產生了ORM(Object-Relational-Mapping),在實現層面,又分為DataMapper和ActiveRecord兩種。mybatis對其也有支援

在這裡插入圖片描述

package com.maoxs.crud;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maoxs.SpringbootMybatisplusApplicationTests;
import com.maoxs.base.entity.User;
import org.junit.Test;

/**
 * @program: plus
 * @description: Ar測試
 * @author: fulin
 * @create: 2018-09-24 12:13
 **/
public class ArTest extends SpringbootMybatisplusApplicationTests {
    @Test
    public void ARInsert() {
        User user = new User();
        user.setName("fulinlin");
        user.setAge(20);
        //欄位不為空插入
        user.insert();
        //ID為空插入,否則為更新
        user.insertOrUpdate();
    }

    @Test
    public void ARUpdate() {
        User user = new User();
        user.setName("快樂貓");
        user.setAge(24);
        user.setId(3L);
        //ID 修改
        user.updateById();
        //條件修改
        user.update(new UpdateWrapper<User>().lambda().eq(User::getId, "5"));
    }


    @Test
    public void ARSelect() {
        User user = new User();
        user.setId(4L);
        //setId
        user.selectById();
        //直接鍵入 Id
        user.selectById(24);
        //條件
        user.selectCount(new QueryWrapper<User>().lambda().eq(User::getId, 0));
        //查詢所有
        user.selectAll();
        //查詢總記錄數
        user.selectList(new QueryWrapper<User>().lambda().eq(User::getName, "fulinlin"));
        //查詢一個
        user.selectOne(new QueryWrapper());
        //分頁
        user.selectPage(new Page<>(1, 2), new QueryWrapper<>());
    }


    @Test
    public void ARDelete() {
        //刪除不存在的資料 在邏輯上也是成功的,返回結果 true
        User user = new User();
        user.setId(4L);
        user.deleteById();
        user.deleteById(31);
        //條件刪除
        user.delete(new QueryWrapper<User>().lambda().eq(User::getId, 3L));
    }
}

分頁

MybatisPlus也提供了一個分頁外掛,使用起來及其方便,這裡說明兩種情況下的分頁,一種是自帶的,一種是自定義的。不過呢做這些之前你要先引入這個配置。

/**
* 分頁外掛
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

普通分頁

普通分頁需要傳遞一個page 的物件,裡面說明你當前頁和分頁的大小,用起來也是非常的舒服。

@Test
public void Page() {
    Page<User> page = new Page<>(1, 5);
    IPage<User> userIPage = userMapper.selectPage(page, null);
    System.out.println(Collections.unmodifiableCollection(userIPage.getRecords()));
}

自定義分頁

如果在某些情況下需要自己定義分頁,那怎麼辦呢

首先呢在mapper介面中定義一個方法


/**
* 3.x 的 page 可以進行取值,多個入參記得加上註解
* 自定義 page 類必須放在入參第一位
* 返回值可以用 IPage<T> 接收 也可以使用入參的 MyPage<T> 接收
* todo 目前使用註解會報錯,寫在 xml 裡就沒事
* @param myPage 自定義 page
* @return 分頁資料
*/
MyPage<User> mySelectPage(@Param("pg") MyPage<User> myPage);

然後呢你需要在xml中寫一個select做繫結

<select id="mySelectPage" resultType="com.maoxs.base.entity.User">
	select *  from user where name like '%' #{pg.selectStr} '%'and age > #{pg.selectInt}
</select>

這裡呢,把用到的MyPage貼出

package com.maoxs.model;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
 * @author fulin
 * @since 2018-09-10
 */
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class MyPage<T> extends Page<T> {
    private static final long serialVersionUID = 5194933845448697148L;

    private Integer selectInt;
    private String selectStr;

    public MyPage(long current, long size)