spring boot(二)整合mybatis plus+ 分頁外掛 + 程式碼生成

_否極泰來發表於2021-07-28

先建立spring boot專案,不知道怎麼建立專案的 可以看我上一篇文章

用到的環境 JDK8 、maven、lombok、mysql 5.7
swagger 是為了方便介面測試

一、Spring boot 整合mybatis plus

mysql資料庫準備

建議建立一個新的資料庫測試
執行下面初始化SQL:


-- 建立測試使用者表
CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主鍵ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年齡',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱',
	PRIMARY KEY (id)
);

-- 增加測試資料
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

1、新增 maven依賴

        <!--mybatis-plus start-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.29</version>
        </dependency>

        <!-- 提供mysql驅動 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!--mybatis-plus end-->

2、application.yml配置

server:
  port: 9999

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource # 使用druid資料來源
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3308/test?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false
    username: root
    password: 999999999

3、在 Spring Boot 啟動類中新增 @MapperScan 註解,掃描 Mapper 資料夾:

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.example.springbootmybatisplus.dao")
@SpringBootApplication
public class SpringbootMybatisPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisPlusApplication.class, args);
    }

}

4、編碼,寫例子測試

4.1、 編寫實體類 User.java

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

4.2、 編寫Mapper類 UserMapper.java

package com.example.springbootmybatisplus.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springbootmybatisplus.entity.User;

public interface UserMapper extends BaseMapper<User> {

}

4.3、 編寫TestController介面進行測試

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springbootmybatisplus.dao.UserMapper;
import com.example.springbootmybatisplus.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("testUser")
public class TestController {
    @Autowired
    UserMapper userMapper;

    //直接分頁查詢
    @RequestMapping(value = "/selectPage",method = RequestMethod.GET)
    public IPage<User> selectPage(){
        log.info("selectPage start");
        IPage<User> page = new Page<>(1,2);
        userMapper.selectPage(page,null);
        if(CollUtil.isNotEmpty(page.getRecords())){
            page.getRecords().forEach(data->{
                log.info("{}",data);
            });
        }
        log.info("selectPage end");
        return page;
    }
    @RequestMapping(value = "/selectById",method = RequestMethod.GET)
    public User selectById(@RequestParam("id")Integer id){
        log.info("selectById start");
        User user = userMapper.selectById(id);
        log.info("user:{}",user);
        log.info("selectById end");
        return user;
    }
}

4.4、 啟動專案,介面進行測試
第一步先訪問:http://127.0.0.1:9999/testUser/selectById?id=1
第二步再訪問介面:http://127.0.0.1:9999/testUser/selectPage

控制檯輸出


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.3)

2021-07-27 22:52:25.127  INFO 23542 --- [           main] c.e.s.SpringbootMybatisPlusApplication   : Starting SpringbootMybatisPlusApplication using Java 1.8.0_231 on localhost with PID 23542 (/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/target/classes started by xkq in /Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus)
2021-07-27 22:52:25.130  INFO 23542 --- [           main] c.e.s.SpringbootMybatisPlusApplication   : No active profile set, falling back to default profiles: default
2021-07-27 22:52:25.770  WARN 23542 --- [           main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.baomidou.cloud.service.*.mapper*]' package. Please check your configuration.
2021-07-27 22:52:26.039  INFO 23542 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9999 (http)
2021-07-27 22:52:26.045  INFO 23542 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-07-27 22:52:26.046  INFO 23542 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.50]
2021-07-27 22:52:26.093  INFO 23542 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-07-27 22:52:26.093  INFO 23542 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 918 ms
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.4.1 
2021-07-27 22:52:26.902  INFO 23542 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9999 (http) with context path ''
2021-07-27 22:52:26.903  INFO 23542 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed
2021-07-27 22:52:26.913  INFO 23542 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)
2021-07-27 22:52:26.922  INFO 23542 --- [           main] s.d.s.w.s.ApiListingReferenceScanner     : Scanning for api listing references
2021-07-27 22:52:27.026  INFO 23542 --- [           main] c.e.s.SpringbootMybatisPlusApplication   : Started SpringbootMybatisPlusApplication in 2.274 seconds (JVM running for 2.733)
2021-07-27 22:52:35.289  INFO 23542 --- [nio-9999-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-07-27 22:52:35.289  INFO 23542 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-07-27 22:52:35.290  INFO 23542 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2021-07-27 22:52:45.023  INFO 23542 --- [nio-9999-exec-7] c.e.s.controller.TestController          : selectById start
2021-07-27 22:52:45.067  INFO 23542 --- [nio-9999-exec-7] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
2021-07-27 22:52:45.273  INFO 23542 --- [nio-9999-exec-7] c.e.s.controller.TestController          : user:User(id=1, name=Jone, age=18, email=test1@baomidou.com)
2021-07-27 22:52:45.274  INFO 23542 --- [nio-9999-exec-7] c.e.s.controller.TestController          : selectById end
2021-07-27 22:53:38.385  INFO 23542 --- [nio-9999-exec-9] c.e.s.controller.TestController          : selectPage start
2021-07-27 22:53:38.431  INFO 23542 --- [nio-9999-exec-9] c.e.s.controller.TestController          : User(id=1, name=Jone, age=18, email=test1@baomidou.com)
2021-07-27 22:53:38.432  INFO 23542 --- [nio-9999-exec-9] c.e.s.controller.TestController          : User(id=2, name=Jack, age=20, email=test2@baomidou.com)
2021-07-27 22:53:38.432  INFO 23542 --- [nio-9999-exec-9] c.e.s.controller.TestController          : User(id=3, name=Tom, age=28, email=test3@baomidou.com)
2021-07-27 22:53:38.432  INFO 23542 --- [nio-9999-exec-9] c.e.s.controller.TestController          : User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
2021-07-27 22:53:38.432  INFO 23542 --- [nio-9999-exec-9] c.e.s.controller.TestController          : User(id=5, name=Billie, age=24, email=test5@baomidou.com)
2021-07-27 22:53:38.432  INFO 23542 --- [nio-9999-exec-9] c.e.s.controller.TestController          : selectPage end

從日誌中可以看到,selectById方法能查詢資料,但是分頁查詢沒有生效,後面會說怎麼整合分頁外掛。

上面程式碼都是參考mybaits plus官方整合h2的例子,然後整合成mysql資料庫的,mybaits plus詳細文件可以訪問官方地址

二、mybatis plus 分頁外掛

上面的分頁沒有生效,我們可以輸出執行的SQL,看下實際執行的SQL

1、application.yml 配置列印SQL日誌

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置這個 會把輸出執行的SQL

2、訪問下面介面,檢視日誌輸出

繼續:第一步先訪問:http://127.0.0.1:9999/testUser/selectById?id=1
第二步再訪問介面:http://127.0.0.1:9999/testUser/selectPage


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.3)

2021-07-27 22:57:56.973  INFO 26426 --- [           main] c.e.s.SpringbootMybatisPlusApplication   : Starting SpringbootMybatisPlusApplication using Java 1.8.0_231 on localhost with PID 26426 (/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/target/classes started by xkq in /Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus)
2021-07-27 22:57:56.976  INFO 26426 --- [           main] c.e.s.SpringbootMybatisPlusApplication   : No active profile set, falling back to default profiles: default
2021-07-27 22:57:57.620  WARN 26426 --- [           main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.baomidou.cloud.service.*.mapper*]' package. Please check your configuration.
2021-07-27 22:57:57.895  INFO 26426 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9999 (http)
2021-07-27 22:57:57.902  INFO 26426 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-07-27 22:57:57.902  INFO 26426 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.50]
2021-07-27 22:57:57.966  INFO 26426 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-07-27 22:57:57.966  INFO 26426 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 941 ms
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
Parsed mapper file: 'file [/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/target/classes/mapper/TestTableMapper.xml]'
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.4.1 
2021-07-27 22:57:58.826  INFO 26426 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9999 (http) with context path ''
2021-07-27 22:57:58.827  INFO 26426 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed
2021-07-27 22:57:58.836  INFO 26426 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)
2021-07-27 22:57:58.846  INFO 26426 --- [           main] s.d.s.w.s.ApiListingReferenceScanner     : Scanning for api listing references
2021-07-27 22:57:58.968  INFO 26426 --- [           main] c.e.s.SpringbootMybatisPlusApplication   : Started SpringbootMybatisPlusApplication in 2.363 seconds (JVM running for 2.816)
2021-07-27 22:58:04.020  INFO 26426 --- [nio-9999-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-07-27 22:58:04.020  INFO 26426 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-07-27 22:58:04.021  INFO 26426 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2021-07-27 22:58:04.044  INFO 26426 --- [nio-9999-exec-1] c.e.s.controller.TestController          : selectById start
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ca5a623] was not registered for synchronization because synchronization is not active
2021-07-27 22:58:04.087  INFO 26426 --- [nio-9999-exec-1] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
JDBC Connection [com.mysql.jdbc.JDBC4Connection@2a83b478] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ca5a623]
2021-07-27 22:58:04.295  INFO 26426 --- [nio-9999-exec-1] c.e.s.controller.TestController          : user:User(id=1, name=Jone, age=18, email=test1@baomidou.com)
2021-07-27 22:58:04.295  INFO 26426 --- [nio-9999-exec-1] c.e.s.controller.TestController          : selectById end
2021-07-27 22:58:09.794  INFO 26426 --- [nio-9999-exec-2] c.e.s.controller.TestController          : selectPage start
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@28b417c9] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.jdbc.JDBC4Connection@2a83b478] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user
==> Parameters: 
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==        Row: 2, Jack, 20, test2@baomidou.com
<==        Row: 3, Tom, 28, test3@baomidou.com
<==        Row: 4, Sandy, 21, test4@baomidou.com
<==        Row: 5, Billie, 24, test5@baomidou.com
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@28b417c9]
2021-07-27 22:58:09.818  INFO 26426 --- [nio-9999-exec-2] c.e.s.controller.TestController          : User(id=1, name=Jone, age=18, email=test1@baomidou.com)
2021-07-27 22:58:09.818  INFO 26426 --- [nio-9999-exec-2] c.e.s.controller.TestController          : User(id=2, name=Jack, age=20, email=test2@baomidou.com)
2021-07-27 22:58:09.818  INFO 26426 --- [nio-9999-exec-2] c.e.s.controller.TestController          : User(id=3, name=Tom, age=28, email=test3@baomidou.com)
2021-07-27 22:58:09.818  INFO 26426 --- [nio-9999-exec-2] c.e.s.controller.TestController          : User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
2021-07-27 22:58:09.818  INFO 26426 --- [nio-9999-exec-2] c.e.s.controller.TestController          : User(id=5, name=Billie, age=24, email=test5@baomidou.com)
2021-07-27 22:58:09.818  INFO 26426 --- [nio-9999-exec-2] c.e.s.controller.TestController          : selectPage end

從執行SQL的日誌看到selectById方法沒問題,主要是selectPage方法沒有加limit分頁

3、配置mybatis plus分頁外掛,新增MybatisPlusConfig.java

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//Spring boot方式
@Configuration
public class MybatisPlusConfig {

//    // 舊版
//    @Bean
//    public PaginationInterceptor paginationInterceptor() {
//        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
//        // 設定請求的頁面大於最大頁後操作, true調回到首頁,false 繼續請求  預設false
//        // paginationInterceptor.setOverflow(false);
//        // 設定最大單頁限制數量,預設 500 條,-1 不受限制
//        // paginationInterceptor.setLimit(500);
//        // 開啟 count 的 join 優化,只針對部分 left join
//        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
//        return paginationInterceptor;
//    }

    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

4、測試MybatisPlusInterceptor分頁外掛

加完MybatisPlusConfig後重啟服務,訪問介面: http://127.0.0.1:9999/testUser/selectPage
從SQL執行日誌可以看出 先執行COUNT查詢總條數,最後在LIMIT分頁取資料,說明分頁外掛配置成功了

2021-07-27 23:02:40.225  INFO 28656 --- [nio-9999-exec-2] c.e.s.controller.TestController          : selectPage start
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6acc6ecd] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.jdbc.JDBC4Connection@2320cee0] will not be managed by Spring
==>  Preparing: SELECT COUNT(*) FROM user
==> Parameters: 
<==    Columns: COUNT(*)
<==        Row: 5
<==      Total: 1
==>  Preparing: SELECT id,name,age,email FROM user LIMIT ?
==> Parameters: 2(Long)
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==        Row: 2, Jack, 20, test2@baomidou.com
<==      Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6acc6ecd]
2021-07-27 23:02:40.299  INFO 28656 --- [nio-9999-exec-2] c.e.s.controller.TestController          : User(id=1, name=Jone, age=18, email=test1@baomidou.com)
2021-07-27 23:02:40.299  INFO 28656 --- [nio-9999-exec-2] c.e.s.controller.TestController          : User(id=2, name=Jack, age=20, email=test2@baomidou.com)
2021-07-27 23:02:40.299  INFO 28656 --- [nio-9999-exec-2] c.e.s.controller.TestController          : selectPage end

三、 mybatis plus 程式碼生成器

我對 mybatis plus 程式碼生成器的需求就是:
1、生成的程式碼 需要支援單表的crud
2、程式碼生成器通常預設生成的檔案是controller、service、servieImpl、mapper(dao)、xml、entity;但是我還想多生成一個Vo類(多生成一個vo,主要是為了後期業務熟練了,想對已有的模版 進行修改 或者 增加生成新的生成檔案,可以做一個參考)
3、xml檔案 我要生成到 /src/main/resources/mapper資料夾下面

1、這是程式碼生成器需要生成的表,及測試資料

-- 建立表
CREATE TABLE `test_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL COMMENT '名稱',
  `start_date` date DEFAULT NULL COMMENT '開始日期',
  `create_time` datetime DEFAULT NULL COMMENT '建立時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='測試-表';

-- 建立一條測試資料
INSERT INTO `test_table` VALUES (1, '你好', '2021-07-27', '2021-07-27 23:10:02');

2、Vo類模版檔案

路徑及檔名是:/my_template/my_entity_vo.java.ftl
把mybatis-plus-generator.jar包的entity模版檔案複製出來,模版內容稍微改了下類名和package,實際生成的檔案跟entity差不多
下圖就是我複製模版的位置,因為我選擇的是freemarker 模版,就複製了字尾是ftl的檔案
image

最終my_entity_vo.java.ftl模版內容如下:

package com.example.springbootmybatisplus.vo;

<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if swagger2>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
</#if>
<#if entityLombokModel>
import lombok.Data;
import lombok.EqualsAndHashCode;
    <#if chainModel>
import lombok.experimental.Accessors;
    </#if>
</#if>

/**
 * <p>
 * ${table.comment!}
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if entityLombokModel>
@Data
    <#if superEntityClass??>
@EqualsAndHashCode(callSuper = true)
    <#else>
@EqualsAndHashCode(callSuper = false)
    </#if>
    <#if chainModel>
@Accessors(chain = true)
    </#if>
</#if>
<#if table.convert>
@TableName("${table.name}")
</#if>
<#if swagger2>
@ApiModel(value="${entity}物件", description="${table.comment!}")
</#if>
<#if superEntityClass??>
public class ${entity}Vo extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
<#elseif activeRecord>
public class ${entity}Vo extends Model<${entity}> {
<#else>
public class ${entity}Vo implements Serializable {
</#if>

<#if entitySerialVersionUID>
    private static final long serialVersionUID = 1L;
</#if>
<#-- ----------  BEGIN 欄位迴圈遍歷  ---------->
<#list table.fields as field>
    <#if field.keyFlag>
        <#assign keyPropertyName="${field.propertyName}"/>
    </#if>

    <#if field.comment!?length gt 0>
        <#if swagger2>
    @ApiModelProperty(value = "${field.comment}")
        <#else>
    /**
     * ${field.comment}
     */
        </#if>
    </#if>
    <#if field.keyFlag>
        <#-- 主鍵 -->
        <#if field.keyIdentityFlag>
    @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
        <#elseif idType??>
    @TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
        <#elseif field.convert>
    @TableId("${field.annotationColumnName}")
        </#if>
        <#-- 普通欄位 -->
    <#elseif field.fill??>
    <#-- -----   存在欄位填充設定   ----->
        <#if field.convert>
    @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
        <#else>
    @TableField(fill = FieldFill.${field.fill})
        </#if>
    <#elseif field.convert>
    @TableField("${field.annotationColumnName}")
    </#if>
    <#-- 樂觀鎖註解 -->
    <#if (versionFieldName!"") == field.name>
    @Version
    </#if>
    <#-- 邏輯刪除註解 -->
    <#if (logicDeleteFieldName!"") == field.name>
    @TableLogic
    </#if>
    private ${field.propertyType} ${field.propertyName};
</#list>
<#------------  END 欄位迴圈遍歷  ---------->

<#if !entityLombokModel>
    <#list table.fields as field>
        <#if field.propertyType == "boolean">
            <#assign getprefix="is"/>
        <#else>
            <#assign getprefix="get"/>
        </#if>
    public ${field.propertyType} ${getprefix}${field.capitalName}() {
        return ${field.propertyName};
    }

    <#if chainModel>
    public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
    <#else>
    public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
    </#if>
        this.${field.propertyName} = ${field.propertyName};
        <#if chainModel>
        return this;
        </#if>
    }
    </#list>
</#if>

<#if entityColumnConstant>
    <#list table.fields as field>
    public static final String ${field.name?upper_case} = "${field.name}";

    </#list>
</#if>
<#if activeRecord>
    @Override
    protected Serializable pkVal() {
    <#if keyPropertyName??>
        return this.${keyPropertyName};
    <#else>
        return null;
    </#if>
    }

</#if>
<#if !entityLombokModel>
    @Override
    public String toString() {
        return "${entity}{" +
    <#list table.fields as field>
        <#if field_index==0>
            "${field.propertyName}=" + ${field.propertyName} +
        <#else>
            ", ${field.propertyName}=" + ${field.propertyName} +
        </#if>
    </#list>
        "}";
    }
</#if>
}

3、新增maven依賴

我選擇使用freemarker作為模版引擎,所以需要引入freemarker依賴

        <!--mybatis-plus 程式碼生成器 start-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>
        <!--mybatis-plus 程式碼生成器 end-->

4、配置檔案新增掃描xml位置以及實體類的位置

這個主要是為了讓mapper(dao)跟xml檔案裡面的方法關聯起來

mybatis-plus:
  #xml檔案路徑,多個路徑有xml檔案用逗號分隔
  mapper-locations: classpath*:/mapper/**/*.xml
  #實體掃描,多個package用逗號或者分號分隔
  typeAliasesPackage: com.example.springbootmybatisplus.entity

5、程式碼生成器啟動類

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
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.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import lombok.extern.slf4j.Slf4j;

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

// 演示例子,執行 main 方法控制檯輸入模組表名回車自動生成對應專案目錄中
@Slf4j
public class CodeGenerator {

    /**
     * <p>
     * 讀取控制檯內容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("請輸入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("請輸入正確的" + tip + "!");
    }

    public static void main(String[] args) {
        // 程式碼生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全域性配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        log.info("projectPath:{}",projectPath);

        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("小旋風");//開發人員
        gc.setOpen(false);//程式碼生成後,是否開啟資料夾
        gc.setSwagger2(true);// 實體屬性 Swagger2 註解
        gc.setFileOverride(false);//是否覆蓋已有檔案(true會覆蓋 已經存在的檔案)
        /**
         * 只使用 java.util.date 代替
         */
        gc.setDateType(DateType.ONLY_DATE);

        gc.setBaseColumnList(true);//開啟 baseColumnList
        gc.setBaseResultMap(true);//開啟 BaseResultMap

        mpg.setGlobalConfig(gc);

        // 資料來源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://127.0.0.1:3308/test?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("999999999");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
//        pc.setModuleName(scanner("模組名"));
        pc.setParent("com.example.springbootmybatisplus");
        pc.setMapper("dao");//生產的mapper 放到dao目錄下


        mpg.setPackageInfo(pc);

        // 自定義配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        // 如果模板引擎是 freemarker
        String templatePath = "/my_template/my_entity_req.java.ftl";//多生成一個實體類,僅僅做參考,沒有這個需求的,可以去掉
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";

        String templatePathXml = "/templates/mapper.xml.ftl";//下面templateConfig.setXml(null); 自定義生成xml,預設的xml設定為null

        // 自定義輸出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定義配置會被優先輸出
        focList.add(new FileOutConfig(templatePathXml) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定義輸出檔名 , 如果你 Entity 設定了前字尾、此處注意 xml 的名稱會跟著發生變化!!
                return projectPath + "/src/main/resources/mapper/"
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });


        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定義輸出檔名 , 如果你 Entity 設定了前字尾、此處注意 xml 的名稱會跟著發生變化!!
                return projectPath + "/src/main/java/com/example/springbootmybatisplus/vo/" +tableInfo.getEntityName() + "Vo" + StringPool.DOT_JAVA;
            }
        });
        /*
        cfg.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判斷自定義資料夾是否需要建立
                checkDir("呼叫預設方法建立的目錄,自定義目錄用");
                if (fileType == FileType.MAPPER) {
                    // 已經生成 mapper 檔案判斷存在,不想重新生成返回 false
                    return !new File(filePath).exists();
                }
                // 允許生成模板檔案
                return true;
            }
        });
        */
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定義輸出模板
        //指定自定義模板路徑,注意不要帶上.ftl/.vm, 會根據使用的模板引擎自動識別
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();

        /**
         * 設定不生成 預設的xml,因為生成的位置會在 java資料夾下面,
         * 我想生成的xml放到resources.mapper資料夾下面,
         * 所以使用設定了自定義【templatePathXml】的模版去生成
         */
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//        strategy.setSuperEntityClass("你自己的父類實體,沒有就不用設定!");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 公共父類
//        strategy.setSuperControllerClass("你自己的父類控制器,沒有就不用設定!");
        // 寫於父類中的公共欄位
//        strategy.setSuperEntityColumns("id"); //沒有父類公共欄位的去掉
        strategy.setInclude(scanner("表名,多個英文逗號分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");

        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
}

5、執行CodeGenerator類的main方法

在控制檯輸入要生成的表名【test_table】,下面是輸出日誌:

23:43:45.919 [main] INFO com.example.springbootmybatisplus.generator.CodeGenerator - projectPath:/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus
請輸入表名,多個英文逗號分割:
test_table
23:43:55.961 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================準備生成檔案...==========================
23:43:56.555 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/mapper.xml.ftl;  檔案:/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/src/main/resources/mapper//TestTableMapper.xml
23:43:56.641 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/entity.java.ftl;  檔案:/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/src/main/java/com/example/springbootmybatisplus/entity/TestTable.java
23:43:56.643 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/mapper.java.ftl;  檔案:/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/src/main/java/com/example/springbootmybatisplus/dao/TestTableMapper.java
23:43:56.645 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/service.java.ftl;  檔案:/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/src/main/java/com/example/springbootmybatisplus/service/ITestTableService.java
23:43:56.646 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/serviceImpl.java.ftl;  檔案:/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/src/main/java/com/example/springbootmybatisplus/service/impl/TestTableServiceImpl.java
23:43:56.648 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/controller.java.ftl;  檔案:/Users/xkq/Downloads/it/xkq_git專案/springboot-example/springboot-mybatis-plus/src/main/java/com/example/springbootmybatisplus/controller/TestTableController.java
23:43:56.648 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================檔案生成完成!!!==========================

6、最終生成的效果圖如下

image

7、測試生成的程式碼

寫個查詢方法,來測試一下

7.1、TestTableMapper.xml 新增getCustomOne方法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springbootmybatisplus.dao.TestTableMapper">

    <!-- 通用查詢對映結果 -->
    <resultMap id="BaseResultMap" type="com.example.springbootmybatisplus.entity.TestTable">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="start_date" property="startDate" />
        <result column="create_time" property="createTime" />
    </resultMap>

    <!-- 通用查詢結果列 -->
    <sql id="Base_Column_List">
        id, name, start_date, create_time
    </sql>

    <select id="getCustomOne" resultMap="BaseResultMap" >
        select id, name, start_date, create_time from test_table limit 1
    </select>
</mapper>

7.2、TestTableMapper.java 新增getCustomOne方法

import com.example.springbootmybatisplus.entity.TestTable;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * <p>
 * 測試-表 Mapper 介面
 * </p>
 *
 * @author 小旋風
 * @since 2021-07-27
 */
public interface TestTableMapper extends BaseMapper<TestTable> {
    public TestTable getCustomOne();
}

7.3、編寫介面進行測試

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springbootmybatisplus.dao.TestTableMapper;
import com.example.springbootmybatisplus.entity.TestTable;
import com.example.springbootmybatisplus.service.ITestTableService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 測試-表 前端控制器
 * </p>
 *
 * @author 小旋風
 * @since 2021-07-27
 */
@RestController
@RequestMapping("/test-table")
public class TestTableController {

        @Autowired
    private ITestTableService testTableService;

    @Autowired
    private TestTableMapper testTableMapper;

    @RequestMapping(value = "/getCustomOne",method = RequestMethod.GET)
    public TestTable getCustomOne(){
        //這個方法主要是驗證 mapper跟xml檔案 關聯上了,mapper-locations生效了
        return testTableMapper.getCustomOne();
    }

    @RequestMapping(value = "/page",method = RequestMethod.GET)
    public IPage<TestTable> page(){
        Page<TestTable> page = new Page();
        page.setSize(10);
        return testTableService.page(page);
    }
}

7.4、訪問介面

訪問介面:http://127.0.0.1:9999/test-table/getCustomOne
日誌輸出如下:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@262025d3] was not registered for synchronization because synchronization is not active
2021-07-27 23:53:18.981  INFO 55251 --- [nio-9999-exec-1] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
JDBC Connection [com.mysql.jdbc.JDBC4Connection@30c4c95c] will not be managed by Spring
==>  Preparing: select id, name, start_date, create_time from test_table limit 1
==> Parameters: 
<==    Columns: id, name, start_date, create_time
<==        Row: 1, 你好, 2021-07-27, 2021-07-27 23:10:02.0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@262025d3]

image
日誌輸出無報錯,瀏覽器上也看到返回結果了,說明程式碼生成器整合成功了~

三、整合swaager

上面的例子,不放整合swagger的程式碼了,畢竟spring boot整合mybaits plus需要配置的東西不多,放在一起有點亂,就單獨拎出來寫,整合swagger 是為了方便測試介面用。

1、pom.xml新增依賴:

        <!--測試介面 新增swagger start-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.6.1</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.6.1</version>
        </dependency>
        <!--測試介面 新增swagger end-->

2、配置SwaggerConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;


@Configuration
@EnableSwagger2
public class SwaggerConfig {

    private Boolean swaggerEnabled = true;//是否啟用swagger 可以把配置放到配置檔案

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(swaggerEnabled)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.springbootmybatisplus"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("介面文件")
                .description("spring boot整合mybatis plus~")
                .termsOfServiceUrl("https://www.cnblogs.com/x-kq/p/15068023.html")
                .version("6.6.6")
                .build();
    }
}

3、swagger訪問地址

訪問這個地址測試介面比較方便
http://127.0.0.1:9999/swagger-ui.html


程式碼我已經傳到gitee了,有興趣的可以clone,傳送門


相關文章