當前位置:
首頁 > 知識 > SpringBoot | 第九章:Mybatis-plus 的集成和使用

SpringBoot | 第九章:Mybatis-plus 的集成和使用

(點擊

上方公眾號

,可快速關注)




來源:oKong ,


blog.lqdev.cn/2018/07/21/springboot/chapter-nine/




前言



本章節開始介紹數據訪問方面的相關知識點。對於後端開發者而言,和資料庫打交道是每天都在進行的,所以一個好用的ORM框架是很有必要的。目前,絕大部分公司都選擇MyBatis框架作為底層資料庫持久化框架。




多說幾句




看著現在Mybatis框架的大行其道,讓我不禁想起,大學時期,當時還是hibernate的時代,現在基本已經忘記了。而當時,Mybatis的前身iBatis還在書中的某個章節出現過。當時大學老師的意思是:目前國內基本沒有使用iBatis的公司,所以這一章節略過,略,過。。。現在對這個還記憶猶新,看著現在Mybatis大行其道,不禁令人唏噓呀。




Mybatis-Plus




Mybatis-Plus(簡稱MP)是一個 Mybatis 的增強工具,在 Mybatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。




官方網站:http://mp.baomidou.com




簡單來說,Mybatis-Plus是Mybatis的增強工具包,其簡化了CRUD操作,提供了代碼生成器,強大的條件構造器(這是我最喜歡的一個),同時內置了多個實用插件:標配的分頁插件、性能分析插件、全局攔截插件等。使得開發過程中,基本的範式代碼都一句話解決了,省去了很多重複的操作(程序猿存在的意義呢,說好的讓我們搬磚呢!)。




SpringBoot集成




這裡選用的mybatis-plus版本為:2.1.9,


mybatisplus-spring-boot-starter版本為:1.0.5。


對應Mybatis版本為:3.4.5




0. 這裡以user表為例子,資料庫為mysql





DROP TABLE IF EXISTS `user`;


CREATE TABLE `user` (


  `id` bigint(20) DEFAULT NULL COMMENT "唯一標示",


  `code` varchar(20) DEFAULT NULL COMMENT "編碼",


  `name` varchar(64) DEFAULT NULL COMMENT "名稱",


  `status` char(1) DEFAULT "1" COMMENT "狀態 1啟用 0 停用",


  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT "創建時間",


  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT "修改時間"


) ENGINE=InnoDB DEFAULT CHARSET=utf8;




1. pom依賴:




<!--mybatis plus -->


<dependency>


    <groupId>com.baomidou</groupId>


    <artifactId>mybatisplus-spring-boot-starter</artifactId>


    <version>1.0.5</version>


</dependency>


<dependency>


    <groupId>com.baomidou</groupId>


    <artifactId>mybatis-plus</artifactId>


    <version>2.1.9</version>


</dependency>




2. 配置文件(當然也可以直接使用@Bean的方式進行或者通過application配置文件進行,詳見官網)




spring-mybatis.xml


 



<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"


       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"


       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


 


    <!--創建jdbc數據源 這裡直接使用阿里的druid資料庫連接池 -->


    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">


        <property name="driverClassName" value="${mysql.driver}"/>


        <property name="url" value="${mysql.url}"/>


        <property name="username" value="${mysql.username}"/>


        <property name="password" value="${mysql.password}"/>


        <!-- 初始化連接大小 -->


        <property name="initialSize" value="0"/>


        <!-- 連接池最大使用連接數量 -->


        <property name="maxActive" value="20"/>


        <!-- 連接池最大空閑 -->


        <property name="maxIdle" value="20"/>


        <!-- 連接池最小空閑 -->


        <property name="minIdle" value="0"/>


        <!-- 獲取連接最大等待時間 -->


        <property name="maxWait" value="60000"/>


 


        <property name="validationQuery" value="${validationQuery}"/>


        <property name="testOnBorrow" value="false"/>


        <property name="testOnReturn" value="false"/>


        <property name="testWhileIdle" value="true"/>


 


        <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 -->


        <property name="timeBetweenEvictionRunsMillis" value="60000"/>


        <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->


        <property name="minEvictableIdleTimeMillis" value="25200000"/>


 


        <!-- 打開removeAbandoned功能 -->


        <property name="removeAbandoned" value="true"/>


        <!-- 1800秒,也就是30分鐘 -->


        <property name="removeAbandonedTimeout" value="1800"/>


        <!-- 關閉abanded連接時輸出錯誤日誌 -->


        <property name="logAbandoned" value="true"/>


 


        <!-- 監控資料庫 -->


        <property name="filters" value="mergeStat"/>


    </bean>


 


    <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx -->


    <bean id="transactionManager"


          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">


        <property name="dataSource" ref="dataSource" />


    </bean>


 


    <!-- 可通過註解控制事務 -->


    <tx:annotation-driven transaction-manager="transactionManager"/>


 


    <!--mybatis-->


    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">


        <property name="dataSource" ref="dataSource"/>


        <!-- 自動掃描mapper.xml文件,支持通配符 -->


        <property name="mapperLocations" value="classpath:mapper/**/*.xml"/>


        <!-- 配置文件,比如參數配置(是否啟動駝峰等)、插件配置等 -->


        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>


        <!-- 啟用別名,這樣就無需寫全路徑類名了,具體可自行查閱資料 -->


        <property name="typeAliasesPackage" value="cn.lqdev.learning.springboot.chapter9.biz.entity"/>


        <!-- MP 全局配置注入 -->


        <property name="globalConfig" ref="globalConfig"/>


    </bean>


    <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">


        <!--


            AUTO->`0`("資料庫ID自增")QW


             INPUT->`1`(用戶輸入ID")


            ID_WORKER->`2`("全局唯一ID")


            UUID->`3`("全局唯一ID")


        -->


        <property name="idType" value="3" />


    </bean>


    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">


    <!-- 自動掃描包路徑,介面自動註冊為一個bean類 -->


        <property name="basePackage" value="cn.lqdev.learning.springboot.chapter9.biz.dao"/>


    </bean>


 


</beans>




3. 編寫啟動類,應用啟動時自動載入配置xml文件





/**


 *  mybatisPlus 配置類,使其載入配置文件


 * @author oKong


 *


 */


@Configuration


@ImportResource(locations = {"classpath:/mybatis/spring-mybatis.xml"})


//@MapperScan("cn.lqdev.learning.springboot.chapter9.biz.dao")


//@EnableTransactionManagement


public class MybatisPlusConfig {


 


}




至此,mybatis-plus就配置完成了,接下來,利用代碼生成器一次性創建所需的dao、mapper、通用CRUDservice類。




4. 編寫代碼生成器類




由於生成器依賴velocity模版引擎,故需要加入依賴:





<dependency>


    <groupId>org.apache.velocity</groupId>


    <artifactId>velocity-engine-core</artifactId>


    <version>2.0</version>


    <scope>test</scope>


</dependency>




MysqlGenerator,此類較長,相關配置可根據實際情況信息修改替換。





public class MysqlGenerator {


 


    private static final String PACKAGE_NAME = "cn.lqdev.learning.springboot.chapter9";


    private static final String MODULE_NAME = "biz";


    private static final String OUT_PATH = "D:\develop\code";


    private static final String AUTHOR = "oKong";


 


    private static final String DRIVER = "com.mysql.jdbc.Driver";


    private static final String URL = "jdbc:mysql://127.0.0.1:3306/learning?useUnicode=true&characterEncoding=UTF-8";


    private static final String USER_NAME = "root";


    private static final String PASSWORD = "123456";


 


    /**


     * <p>


     * MySQL 生成演示


     * </p>


     */


    public static void main(String[] args) {


        // 自定義需要填充的欄位


        List<TableFill> tableFillList = new ArrayList<TableFill>();


 


        // 代碼生成器


        AutoGenerator mpg = new AutoGenerator().setGlobalConfig(


                // 全局配置


                new GlobalConfig().setOutputDir(OUT_PATH)// 輸出目錄


                        .setFileOverride(true)// 是否覆蓋文件


                        .setActiveRecord(true)// 開啟 activeRecord 模式


                        .setEnableCache(false)// XML 二級緩存


                        .setBaseResultMap(false)// XML ResultMap


                        .setBaseColumnList(true)// XML columList


                        .setAuthor(AUTHOR)


                        // 自定義文件命名,注意 %s 會自動填充表實體屬性!


                        .setXmlName("%sMapper").setMapperName("%sDao")


        // .setServiceName("MP%sService")


        // .setServiceImplName("%sServiceDiy")


        // .setControllerName("%sAction")


        ).setDataSource(


                // 數據源配置


                new DataSourceConfig().setDbType(DbType.MYSQL)// 資料庫類型


                        .setTypeConvert(new MySqlTypeConvert() {


                            // 自定義資料庫表欄位類型轉換【可選】


                            @Override


                            public DbColumnType processTypeConvert(String fieldType) {


                                System.out.println("轉換類型:" + fieldType);


                                // if ( fieldType.toLowerCase().contains( "tinyint" ) ) {


                                // return DbColumnType.BOOLEAN;


                                // }


                                return super.processTypeConvert(fieldType);


                            }


                        }).setDriverName(DRIVER).setUsername(USER_NAME).setPassword(PASSWORD).setUrl(URL))


                .setStrategy(


                        // 策略配置


                        new StrategyConfig()


                                // .setCapitalMode(true)// 全局大寫命名


                                .setDbColumnUnderline(true)// 全局下劃線命名


                                // .setTablePrefix(new String[]{"unionpay_"})// 此處可以修改為您的表前綴


                                .setNaming(NamingStrategy.underline_to_camel)// 表名生成策略


                                // .setInclude(new String[] {"citycode_org"}) // 需要生成的表


                                // .setExclude(new String[]{"test"}) // 排除生成的表


                                // 自定義實體,公共欄位


                                // .setSuperEntityColumns(new String[]{"test_id"})


                                .setTableFillList(tableFillList)


                                // 自定義實體父類


                                // .setSuperEntityClass("com.baomidou.demo.common.base.BsBaseEntity")


                                // // 自定義 mapper 父類


                                // .setSuperMapperClass("com.baomidou.demo.common.base.BsBaseMapper")


                                // // 自定義 service 父類


                                // .setSuperServiceClass("com.baomidou.demo.common.base.BsBaseService")


                                // // 自定義 service 實現類父類


                                // .setSuperServiceImplClass("com.baomidou.demo.common.base.BsBaseServiceImpl")


                                // 自定義 controller 父類


                                // .setSuperControllerClass("com.baomidou.demo.TestController")


                                // 【實體】是否生成欄位常量(默認 false)


                                // public static final String ID = "test_id";


                                .setEntityColumnConstant(true)


                                // 【實體】是否為構建者模型(默認 false)


                                // public User setName(String name) {this.name = name; return this;}


                                .setEntityBuilderModel(true)


                                // 【實體】是否為lombok模型(默認 false)<a href="https://projectlombok.org/">document</a>


                                .setEntityLombokModel(true)


                // Boolean類型欄位是否移除is前綴處理


                // .setEntityBooleanColumnRemoveIsPrefix(true)


                // .setRestControllerStyle(true)


                // .setControllerMappingHyphenStyle(true)


                ).setPackageInfo(


                        // 包配置


                        new PackageConfig().setModuleName(MODULE_NAME).setParent(PACKAGE_NAME)// 自定義包路徑


                                .setController("controller")// 這裡是控制器包名,默認 web


                                .setXml("mapper").setMapper("dao")


 


                ).setCfg(


                        // 注入自定義配置,可以在 VM 中使用 cfg.abc 設置的值


                        new InjectionConfig() {


                            @Override


                            public void initMap() {


                                Map<String, Object> map = new HashMap<String, Object>();


                                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");


                                this.setMap(map);


                            }


                        }.setFileOutConfigList(


                                Collections.<FileOutConfig>singletonList(new FileOutConfig("/templates/mapper.xml.vm") {


                                    // 自定義輸出文件目錄


                                    @Override


                                    public String outputFile(TableInfo tableInfo) {


                                        return OUT_PATH + "/xml/" + tableInfo.getEntityName() + "Mapper.xml";


                                    }


                                })))


                .setTemplate(


                        // 關閉默認 xml 生成,調整生成 至 根目錄


                        new TemplateConfig().setXml(null)


        // 自定義模板配置,模板可以參考源碼 /mybatis-plus/src/main/resources/template 使用 copy


        // 至您項目 src/main/resources/template 目錄下,模板名稱也可自定義如下配置:


        // .setController("...");


        // .setEntity("...");


        // .setMapper("...");


        // .setXml("...");


        // .setService("...");


        // .setServiceImpl("...");


        );


 


        // 執行生成


        mpg.execute();


    }


 


}




運行後即可,省了多少事!







簡單實例




簡單演示下增刪改查及分頁的使用。




使用分頁時,mybatis-config.xml需要加入分頁插件:PerformanceInterceptor





<plugins>


  <!-- 分頁插件配置 -->


  <plugin interceptor="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></plugin>


</plugins>




編寫控制層





/**


 * 用戶控制層 簡單演示增刪改查及分頁


 * @author oKong


 *


 */


@RestController


@RequestMapping("/user")


public class UserController {


 


    @Autowired


    IUserService userService;


 


    @PostMapping("add")


    //正常業務時, 需要在user類裡面進行事務控制,控制層一般不進行業務控制的。


    //@Transactional(rollbackFor = Exception.class)


    public Map<String,String> addUser(@Valid @RequestBody UserReq userReq){


 


        User user = new User();


        user.setCode(userReq.getCode());


        user.setName(userReq.getName());


        //由於設置了主鍵策略 id可不用賦值 會自動生成


        //user.setId(0L);


        userService.insert(user);


        Map<String,String> result = new HashMap<String,String>();


        result.put("respCode", "01");


        result.put("respMsg", "新增成功");


        //事務測試


        //System.out.println(1/0);


        return result;


    }


 


    @PostMapping("update")


    public Map<String,String> updateUser(@Valid @RequestBody UserReq userReq){


 


        if(userReq.getId() == null || "".equals(userReq.getId())) {


            throw new CommonException("0000", "更新時ID不能為空");


        }


        User user = new User();


        user.setCode(userReq.getCode());


        user.setName(userReq.getName());


        user.setId(Long.parseLong(userReq.getId()));        


        userService.updateById(user);


        Map<String,String> result = new HashMap<String,String>();


        result.put("respCode", "01");


        result.put("respMsg", "更新成功");


        return result;


    }


 


    @GetMapping("/get/{id}")


    public Map<String,Object> getUser(@PathVariable("id") String id){


        //查詢


        User user = userService.selectById(id);


        if(user == null) {


            throw new CommonException("0001", "用戶ID:" + id + ",未找到");


        }


        UserResp resp = UserResp.builder()


                .id(user.getId().toString())


                .code(user.getCode())


                .name(user.getName())


                .status(user.getStatus())


                .build();


        Map<String,Object> result = new HashMap<String,Object>();


        result.put("respCode", "01");


        result.put("respMsg", "成功");


        result.put("data", resp);


        return result;


    }


 


    @GetMapping("/page")


    public Map<String,Object> pageUser(int current, int size){


        //分頁


        Page<User> page = new Page<>(current, size);


        Map<String,Object> result = new HashMap<String,Object>();


        result.put("respCode", "01");


        result.put("respMsg", "成功");


        result.put("data", userService.selectPage(page));


        return result;


    }       


}




啟動應用後,使用postman依次訪問對應的url地址即可。







資料庫:







分頁







由於配置了分析插件,控制台會輸出執行的sql語句







其他的就不一一貼圖了。




關於事務




正常情況下,只需要在服務層中加入@Transactional即可,事務相關的此章節不進行闡述,之後有機會會專門拿一個章節來說明下。




示例中為了方便,直接在控制層中加入了@Transactional進行事務測試,正式開發過程中,強烈建議在服務層進行業務控制,控制層一般上是進行邏輯判斷的!




實體對象欄位為枚舉類




可能在實際開發中,大家會碰到,為了方便,一些類型、狀態欄位會編寫成枚舉類型,比如啟用狀態:DISABLE(「0」),ENABLE(「1」)。此時可通過配置typeHandlers進行自定義類型的處理,這裡簡單以EnumOrdinalTypeHandler(存儲enum類里的序號值)進行示例,當然也可根據需要進行自定義處理器的編寫,比如編寫一個通用的枚舉轉換器等,其他相關知識點,大家可自行谷歌。




StatusEnums





public enum StatusEnum {


 


    DISABLE,


    ENABLE;


 


}




將user對象修改成枚舉類型





/**


 * 狀態1 啟用 0 停用


 */


private StatusEnum status;




配置文件mybatis-config.xml加入處理類





<typeHandlers>


   <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"


     javaType="cn.lqdev.learning.springboot.chapter9.biz.entity.StatusEnum"/>


</typeHandlers>




之後就會自動進行轉換了。大家可下載示例,進行實際操作下。







總結




本章節主要是對Mybatis-plus的集成和簡單使用進行了說明,詳細的用法,可到官網查看,官網有詳細的使用指南,這裡就不班門弄斧了。至此,對於一般的開發需求基本上都可以滿足了。接下來的章節會重點講解其他配套工具的使用,敬請期待!




最後




目前互聯網上很多大佬都有springboot系列教程,如有雷同,請多多包涵了。本文是作者在電腦前一字一句敲的,每一步都是實踐的。若文中有所錯誤之處,還望提出,謝謝。




系列






  • SpringBoot | 第一章:第一個 SpringBoot 應用



  • SpringBoot | 第二章:lombok 介紹及簡單使用



  • SpringBoot | 第三章:springboot 配置詳解



  • SpringBoot | 第四章:日誌管理



  • SpringBoot | 第五章:多環境配置



  • SpringBoot | 第六章:常用註解介紹及簡單使用



  • SpringBoot | 第七章:過濾器、監聽器、攔截器



  • SpringBoot | 第八章:統一異常、數據校驗處理




【關於投稿】




如果大家有原創好文投稿,請直接給公號發送留言。




① 留言格式:


【投稿】+《 文章標題》+ 文章鏈接

② 示例:


【投稿】《不要自稱是程序員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/

③ 最後請附上您的個人簡介哈~






看完本文有收穫?請轉發分享給更多人


關注「ImportNew」,提升Java技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 ImportNew 的精彩文章:

領域驅動設計,為何死灰復燃?
SpringBoot | 第十章:Swagger 2 的集成和使用

TAG:ImportNew |