原创

mybatis-plus 生成代码

温馨提示:
本文最后更新于 2023年03月08日,已超过 386 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

1.导入依赖

导入最新版本的mybatis-plus-generator的maven依赖,因为要使用到数据库,所有也要导入mysql的包

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.3</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.31</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3</version>
</dependency>

2.生成代码

mp提供了两种生成方法。

  • 快速生成
    快速生成是将各种配置全部写在代码中,直接生成
      FastAutoGenerator.create("url", "username", "password")
          .globalConfig(builder -> {
              builder.author("baomidou") // 设置作者
                  .enableSwagger() // 开启 swagger 模式
                  .fileOverride() // 覆盖已生成文件
                  .outputDir("D://"); // 指定输出目录
          })
          .packageConfig(builder -> {
              builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名
                  .moduleName("system") // 设置父包模块名
                  .pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
          })
          .strategyConfig(builder -> {
              builder.addInclude("t_simple") // 设置需要生成的表名
                  .addTablePrefix("t_", "c_"); // 设置过滤表前缀
          })
          .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
          .execute();
    
  • 交互式生成
    交互式生成是一部分配置写在代码中,一部分配置可以手动输入进行配置

      FastAutoGenerator.create(DATA_SOURCE_CONFIG)
          // 全局配置
          .globalConfig((scanner, builder) -> builder.author(scanner.apply("请输入作者名称?")).fileOverride())
          // 包配置
          .packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))
          // 策略配置
          .strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
                              .controllerBuilder().enableRestStyle().enableHyphenStyle()
                              .entityBuilder().enableLombok().addTableFills(
                                      new Column("create_time", FieldFill.INSERT)
                              ).build())
          /*
              模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
             .templateEngine(new BeetlTemplateEngine())
             .templateEngine(new FreemarkerTemplateEngine())
           */
          .execute();
    
      // 处理 all 情况
      protected static List<String> getTables(String tables) {
          return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
      }
    

3.详细配置

本篇文章使用快速和交互式共存的方式进行代码的生成,把一些固定的配置使用快速配置,把需要手动切换的配置使用手动进行输入。

1. 数据库配置(DataSourceConfig)

先创建一个数据库配置文件在resources
db.yml

url: jdbc:mysql:///misv2?serverTimezone=GMT%2B8
username: root
password: root

然后在main方法中进行加载配置文件

Properties properties = new Properties();
InputStream in = ClassLoader.getSystemResourceAsStream("db.yml");
try {
    properties.load(in);
} catch (IOException e) {
    log.error("配置文件不存在");
    throw new RuntimeException(e);
}
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");

我们看到FastAutoGenerator.cteate方法需要的一个参数是
file
DataSourceConfig.Builder
我们使用该内部类中的一个构造方法
file

DataSourceConfig.Builder dataSourceConfig = new DataSourceConfig.Builder(url, username, password);

然后将该dataSourceConfig传入

2. 全局配置(GlobalConfig)

接下来进行全局配置
file
注意下这个过时了
file
这些内容我们不需要手动输入,就直接写在代码中

// 全局配置
.globalConfig((builder) -> builder.author("coco")
        //禁止打开输出目录
        .disableOpenDir()
        //输出目录
        .outputDir(System.getProperty("user.dir") + "\\module\\generator\\src\\main\\java\\top\\wangqi\\")
        //开启springdoc 如果自己使用的是swagger 就用.enableSwagger
        .enableSpringdoc()
        //注释时间
        .commentDate("yyyy-MM-dd")
        //时间策略
        .dateType(DateType.TIME_PACK))

具体的时间类型在这
file

3. 包配置(PackageConfig)

这里我们也不需要手动配置,就直接写在代码中,方法可能不全,自己探索
file

// 包配置
.packageConfig((builder) -> builder
        //就是你src/java之后到你启动类那一层
        .parent("com\\zzw\\mis\\")
        //父包模块名
        .moduleName("mis-module-generator")
        //entity包名
        .entity("entity")
        //service包名
        .service("service")
        //service实现类包名
        .serviceImpl("service.impl")
        //控制器包名
        .controller("controller")
        //Mapper 包名    
        .mapper("dao")
        //Mapper XML 包名
        .xml("mapper")
        //路径配置信息  Collections.singletonMap(OutputFile.mapperXml, "D://")
        // .pathInfo()
        //子包名 这块貌似是在包路径上再拼上一个路径
        //.joinPackage("")
)

4. 模板配置(TemplateConfig)

file

//模板配置
.templateConfig((builder -> builder
        //设置 controller 模板路径
        .controller("/templates/controller.ftl")
        //设置实体模板路径(JAVA)
        .entity("/templates/entity.ftl")
        //设置 service 模板路径
        .service("/templates/service.ftl")
        //设置 serviceImpl 模板路径
        .serviceImpl("/templates/serviceImpl.ftl")
        //设置 mapper 模板路径
        .mapper("/templates/mapper.ftl")
        //设置 mapperXml 模板路径
        .xml("/templates/mapper.xml.ftl")))

如果不限于内置的模板的话可以自己进行修改,传入模板的地址
内置模板在这里
file

5. 注入配置(InjectionConfig)

file

Map<String, String> customFileMap = new HashMap<>(3);
customFileMap.put("Vo.java", "/templates/vo.ftl");
customFileMap.put("Query.java", "/templates/query.ftl");
customFileMap.put("Convert.java", "/templates/convert.ftl");
Map<String, Object> propMap = new HashMap<>(1);
propMap.put("superQueryClass", true);

//注入配置
.injectionConfig(builder -> builder
        //自定义属性
        .customMap(propMap)
        //自定义配置模板文件
        .customFile(customFileMap))

6. 策略配置(StrategyConfig)

file
file
file
file
file

// 策略配置
.strategyConfig((scanner, builder) -> builder
        //表字段前缀
        .addTablePrefix("buss_")
        //输入需要生成的表
        .addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
        //controller配置
        .controllerBuilder()
            //开启rest风格
            .enableRestStyle()
            //开启驼峰转连字符
            .enableHyphenStyle()
        //实体配置
        .entityBuilder()
            //开启lombok
            .enableLombok()
            //设置父类
            .superClass("com.zzw.mis.framework.mybatis.entity.BaseEntity")
            //乐观锁数据库字段名
            .versionColumnName("version")
            //乐观锁实体字段名
            .versionPropertyName("version")
            //逻辑删除字段数据库字段
            .logicDeleteColumnName("deleted")
            //逻辑删除实体字段
            .logicDeletePropertyName("deleted")
            //格式化文件名
            .formatFileName("%sEntity")
            //添加父类的字段
            .addSuperEntityColumns("id", "version", "deleted", "creator", "create_time", "updater", "update_time")
            //字段填充
            .addTableFills(new Column("create_time", FieldFill.INSERT))
            //主键策略
            .idType(IdType.ASSIGN_UUID)
        //service配置
        .serviceBuilder()
            //service接口父类
            .superServiceClass("com.zzw.mis.framework.mybatis.service.BaseService")
            //service实现类父类
            .superServiceImplClass("com.zzw.mis.framework.mybatis.service.impl.BaseServiceImpl")
        //mapper配置
        .mapperBuilder()
            //父类
            .superClass("com.zzw.mis.framework.mybatis.dao.BaseDao")
            //设置mapper注解
            .mapperAnnotation(Mapper.class)
            //启用 BaseResultMap 生成
            .enableBaseResultMap()
        .build())

7. 模板引擎配置

.templateEngine(new FreemarkerTemplateEngine())
TestTemplateEngine.java 模板引擎配置代码 这是我主要是配置自定义的vo和query等自定义文件的生成

package com.zzw.mis;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.List;
import java.util.Map;

/**
 * <p>项目名称: zzw-tech </p>
 * <p>包名称: com.zzw.mis </p>
 * <p>描述:  </p>
 * <p>  </p>
 * <p>创建时间: 2022/12/1 17 </p>
 *
 * @author coco
 * @version v1.0
 */
public class TestTemplateEngine extends FreemarkerTemplateEngine {
    @Override
    protected void outputCustomFile (@NotNull List<CustomFile> customFiles, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        String name = tableInfo.getName();
        int i = name.indexOf("_");
        String substring1 = name.substring(i + 1);
        String tableName = NamingStrategy.underlineToCamel(substring1);
        String substring = tableName.substring(0, 1).toUpperCase();
        tableName = substring + tableName.substring(1);
        String parentPath = getPathInfo(OutputFile.parent);
        String finalTableName = tableName;
        objectMap.put("tableName", finalTableName);
        customFiles.forEach(file -> {
            String[] split = file.getTemplatePath().split("/");
            String s = split[split.length - 1];
            String[] split1 = s.split("\\.");
            String dir = split1[0];
            String filePath = StringUtils.isNotBlank(file.getFilePath()) ? file.getFilePath() : parentPath + File.separator + dir;
            if (StringUtils.isNotBlank(file.getPackageName())) {
                filePath = filePath + File.separator + dir + file.getPackageName();
            }
            String fileName = filePath + File.separator + finalTableName + file.getFileName();
            outputFile(new File(fileName), objectMap, file.getTemplatePath(), file.isFileOverride());
        });
    }
}

8. 接下来就完了 生成代码 踩坑改bug

哦豁,启动报错了
file
找不到freemaker文件,我们加入依赖

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

继续报错
file
找不到我定义的那几个文件
找来找去原来是自定义文件位置放错了,要放在resources下
然后启动
哦豁 继续报错
file
还是找不到文件,但是这次是没找到mapper.ftl.ftl,但是我明明写的是mapper.ftl啊,所以,freemarker中查找视图是不需要添加后缀的,我们去掉
file
继续运行,还是有问题
file
这里主要是没有设置mapper xml文件的位置和总体文件的位置问题
我们在package 配置中加入

.pathInfo(Collections.singletonMap(OutputFile.xml, dir + "\mis-cloud-module\mis-module-generator\src\main\resources\mapper"))

file
我们这两边都加了,所以去掉一边
然后启动
file
成功,但是对我来说还有一些小瑕疵,我在查看entity的时候,发现数据库的bit类型返回到后端代码也是Byte
file
我们的需求是boolean
继续修改

9. 修改数据库类型与实体类型的对应

当我去修改的时候才发现,是我数据库的问题
file
mybatis-plus中的类型转换是当数据库字段为bit(1)和tinyint(1)时才会转换为boolean,而我的没写长度,于是乎给我转换为Byte了。这波大意了啊!
最后,我们的代码就成功生成,暂时没发现什么问题。上全部代码

代码结构
file

pom.xml

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mis-cloud-module</artifactId>
        <groupId>com.zzw.mis</groupId>
        <version>2.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mis-module-generator</artifactId>
    <packaging>jar</packaging>
    <name>mis-module-generator</name>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.zzw.mis</groupId>
            <artifactId>mis-cloud-mybatis</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-webmvc-core</artifactId>
        </dependency>
    </dependencies>
</project>

db.yml

url: jdbc:mysql:///bigdata?serverTimezone=GMT%2B8
username: root
password: root
module: mis-cloud-module/mis-module-generator
parent: com.zzw.mis

App.java

package com.zzw.mis;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.fill.Column;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Mapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * Hello world!
 */
@Slf4j
public class App {
    public static void main (String[] args) {
        Properties properties = new Properties();
        InputStream in = ClassLoader.getSystemResourceAsStream("db.yml");
        try {
            properties.load(in);
        } catch (IOException e) {
            log.error("配置文件不存在");
            throw new RuntimeException(e);
        }
        String dir = System.getProperty("user.dir");
        String url = properties.getProperty("url");
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        String module = properties.getProperty("module");
        String parent = properties.getProperty("parent");
        DataSourceConfig.Builder dataSourceConfig = new DataSourceConfig.Builder(url, username, password);
        dataSourceConfig.typeConvert(new MySqlTypeConvert());
        Map<String, String> customFileMap = new HashMap<>(3);
        customFileMap.put("Vo.java", "templates/vo.ftl");
        customFileMap.put("Query.java", "templates/query.ftl");
        customFileMap.put("Convert.java", "templates/convert.ftl");
        Map<String, Object> propMap = new HashMap<>();
        propMap.put("superQueryClass", "BaseQuery");
        propMap.put("queryDir", "query");
        propMap.put("voDir", "vo");
        propMap.put("convertDir", "convert");
        FastAutoGenerator.create(dataSourceConfig)
                // 全局配置
                .globalConfig((builder) -> builder.author("coco")
                        //禁止打开输出目录
                        .disableOpenDir()
                        //输出目录
                        .outputDir(dir + "\\" + module + "\\src\\main\\java")
                        //开启springdoc 如果自己使用的是swagger 就用.enableSwagger
                        .enableSpringdoc()
                        //注释时间
                        .commentDate("yyyy-MM-dd")
                        //时间策略
                        .dateType(DateType.TIME_PACK))
                // 包配置
                .packageConfig((builder) -> builder
                                //就是你src/java之后到你启动类那一层
                                .parent(parent)
                                //父包模块名
                                // .moduleName("mis-module-generator")
                                //entity包名
                                .entity("entity")
                                //service包名
                                .service("service")
                                //service实现类包名
                                .serviceImpl("service.impl")
                                //控制器包名
                                .controller("controller")
                                //Mapper 包名
                                .mapper("dao")
                                //Mapper XML 包名
                                //xml文件输出位置
                                .pathInfo(Collections.singletonMap(OutputFile.xml, dir + "\\" + module + "\\src\\main\\resources\\mapper"))
                        //路径配置信息  Collections.singletonMap(OutputFile.mapperXml, "D://")
                        // .pathInfo()
                        //子包名 这块貌似是在包路径上再拼上一个路径
                        //.joinPackage("")

                )
                //模板配置
                .templateConfig((builder -> builder
                        //设置 controller 模板路径
                        .controller("templates/controller")
                        //设置实体模板路径(JAVA)
                        .entity("templates/entity")
                        //设置 service 模板路径
                        .service("templates/service")
                        //设置 serviceImpl 模板路径
                        .serviceImpl("templates/serviceImpl")
                        //设置 mapper 模板路径
                        .mapper("templates/mapper")
                        //设置 mapperXml 模板路径
                        .xml("templates/mapper.xml")))

                //注入配置
                .injectionConfig(builder -> builder
                        //自定义属性
                        .customMap(propMap)
                        //自定义配置模板文件
                        .customFile(customFileMap))
                // 策略配置
                .strategyConfig((scanner, builder) -> builder
                        //表字段前缀
                        .addTablePrefix("buss_")
                        //输入需要生成的表
                        .addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
                        //controller配置
                        .controllerBuilder()
                        //开启rest风格
                        .enableRestStyle()
                        //开启驼峰转连字符
                        .enableHyphenStyle()
                        //实体配置
                        .entityBuilder()
                        //开启lombok
                        .enableLombok()
                        //设置父类
                        .superClass("com.zzw.mis.framework.mybatis.entity.BaseEntity")
                        //乐观锁数据库字段名
                        .versionColumnName("version")
                        //乐观锁实体字段名
                        .versionPropertyName("version")
                        //逻辑删除字段数据库字段
                        .logicDeleteColumnName("deleted")
                        //逻辑删除实体字段
                        .logicDeletePropertyName("deleted")
                        //格式化文件名
                        .formatFileName("%sEntity")
                        //添加父类的字段
                        .addSuperEntityColumns("id", "version", "deleted", "creator", "create_time", "updater", "update_time")
                        //字段填充
                        .addTableFills(new Column("create_time", FieldFill.INSERT))
                        //主键策略
                        .idType(IdType.ASSIGN_UUID)
                        //service配置
                        .serviceBuilder()
                        //service接口父类
                        .superServiceClass("com.zzw.mis.framework.mybatis.service.BaseService")
                        //service实现类父类
                        .superServiceImplClass("com.zzw.mis.framework.mybatis.service.impl.BaseServiceImpl")
                        //service文件命名
                        .formatServiceFileName("%sService")
                        //mapper配置
                        .mapperBuilder()
                        //父类
                        .superClass("com.zzw.mis.framework.mybatis.dao.BaseDao")
                        //设置mapper注解
                        .mapperAnnotation(Mapper.class)
                        //启用 BaseResultMap 生成
                        .enableBaseResultMap().build()).templateEngine(new TestTemplateEngine())
                /*
                    模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
                   .templateEngine(new BeetlTemplateEngine())
                 */.execute();
        // System.out.println(System.getProperty("user.dir") + "\\mis-cloud-module\\mis-module-generator\\src\\main\\java\\com\\zzw\\mis\\");

    }

    // 处理 all 情况
    protected static List<String> getTables (String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }
}

TestTemplateEngine.java

package com.zzw.mis;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.List;
import java.util.Map;

/**
 * <p>项目名称: zzw-tech </p>
 * <p>包名称: com.zzw.mis </p>
 * <p>描述:  </p>
 * <p>  </p>
 * <p>创建时间: 2022/12/1 17 </p>
 *
 * @author coco
 * @version v1.0
 */
public class TestTemplateEngine extends FreemarkerTemplateEngine {
    @Override
    protected void outputCustomFile (@NotNull List<CustomFile> customFiles, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        String name = tableInfo.getName();
        int i = name.indexOf("_");
        String substring1 = name.substring(i + 1);
        String tableName = NamingStrategy.underlineToCamel(substring1);
        String substring = tableName.substring(0, 1).toUpperCase();
        tableName = substring + tableName.substring(1);
        String parentPath = getPathInfo(OutputFile.parent);
        String finalTableName = tableName;
        objectMap.put("tableName", finalTableName);
        customFiles.forEach(file -> {
            String[] split = file.getTemplatePath().split("/");
            String s = split[split.length - 1];
            String[] split1 = s.split("\\.");
            String dir = split1[0];
            String filePath = StringUtils.isNotBlank(file.getFilePath()) ? file.getFilePath() : parentPath + File.separator + dir;
            if (StringUtils.isNotBlank(file.getPackageName())) {
                filePath = filePath + File.separator + dir + file.getPackageName();
            }
            String fileName = filePath + File.separator + finalTableName + file.getFileName();
            outputFile(new File(fileName), objectMap, file.getTemplatePath(), file.isFileOverride());
        });
    }
}

4.结尾

到这里了,就点个赞吧,如果觉得可以分享好友收藏网站下次再来看。

正文到此结束
本文目录