SpringBoot集成MySQL-MyBatisPlus代码自动生成
in JavaDevelop with 0 comment

SpringBoot集成MySQL-MyBatisPlus代码自动生成

in JavaDevelop with 0 comment

添加依赖(旧版)


<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.1</version>
</dependency>

<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
</dependency>

代码(3.5.1之前, 旧版)

官方地址

注意配置到测试模块, 因为最后不会进行打包.

public class CodeGet {

    public static void main(String[] args) {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("C:\\Users\\tarena\\zymall\\service\\model_vod"+"/src/main/java");
        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setAuthor("liyunfei");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://101.35.121.103:32759/zy_vod");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root1234");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        // com.atguigu.ggkt.vod.
        pc.setModuleName("model_vod"); //模块名
        pc.setParent("com.zy");
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();

        strategy.setInclude("teacher");

        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);

        // 6、执行
        mpg.execute();
    }
}

添加依赖(新版)

包括mybatis-plus-generator和默认的模板引擎velocity依赖的velocity-engine-core。

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.2</version>
</dependency>
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
</dependency>

代码生成配置(新版, 3.5.1之后)

import com.baomidou.mybatisplus.generator.FastAutoGenerator;

/**
 * This class is for xxxx.
 *
 * @author pdai
 */
public class TestGenCode {

    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/test_db?useSSL=false&autoReconnect=true&characterEncoding=utf8", "test", "bfXa4Pt2lUUScy8jakXf")
                .globalConfig(builder ->
                        builder.author("pdai") // 设置作者
                                .enableSwagger() // 开启 swagger 模式
                )
                .packageConfig(builder ->
                        builder.parent("tech.pdai.springboot.mysql8.mybatisplus.anno") // 设置父包名
                                .moduleName("gencode") // 设置父包模块名
                )
                .strategyConfig(builder ->
                        builder.addInclude("tb_user", "tb_role", "tb_user_role")
                )
                .execute();
    }
}

image

新版代码生成器官方文档

原理

配置的装载, FastAutoGenerator本质上就是通过builder注入各种配置,并将它交给代码生成主类:AutoGenerator

public void execute() {
    new AutoGenerator(this.dataSourceConfigBuilder.build())
        // 全局配置
        .global(this.globalConfigBuilder.build())
        // 包配置
        .packageInfo(this.packageConfigBuilder.build())
        // 策略配置
        .strategy(this.strategyConfigBuilder.build())
        // 注入配置
        .injection(this.injectionConfigBuilder.build())
        // 模板配置
        .template(this.templateConfigBuilder.build())
        // 执行
        .execute(this.templateEngine);
}

AutoGenerator中execute方法,包括初始化配置和模板引擎(默认是Velocity),然后将配置交给模板引擎初始化执行文件输出

/**
  * 生成代码
  *
  * @param templateEngine 模板引擎
  */
public void execute(AbstractTemplateEngine templateEngine) {
    logger.debug("==========================准备生成文件...==========================");
    // 初始化配置
    if (null == config) {
        config = new ConfigBuilder(packageInfo, dataSource, strategy, template, globalConfig, injection);
    }
    if (null == templateEngine) {
        // 为了兼容之前逻辑,采用 Velocity 引擎 【 默认 】
        templateEngine = new VelocityTemplateEngine();
    }
    templateEngine.setConfigBuilder(config);
    // 模板引擎初始化执行文件输出
    templateEngine.init(config).batchOutput().open();
    logger.debug("==========================文件生成完成!!!==========================");
}

模板引擎中batchOuput方法中,包含获取表的信息并根据模板来生成类文件。

/**
  * 批量输出 java xml 文件
  */
@NotNull
public AbstractTemplateEngine batchOutput() {
    try {
        ConfigBuilder config = this.getConfigBuilder();
        List<TableInfo> tableInfoList = config.getTableInfoList();
        tableInfoList.forEach(tableInfo -> {
            Map<String, Object> objectMap = this.getObjectMap(config, tableInfo);
            Optional.ofNullable(config.getInjectionConfig()).ifPresent(t -> {
                t.beforeOutputFile(tableInfo, objectMap);
                // 输出自定义文件
                outputCustomFile(t.getCustomFile(), tableInfo, objectMap);
            });
            // entity
            outputEntity(tableInfo, objectMap);
            // mapper and xml
            outputMapper(tableInfo, objectMap);
            // service
            outputService(tableInfo, objectMap);
            // controller
            outputController(tableInfo, objectMap);
        });
    } catch (Exception e) {
        throw new RuntimeException("无法创建文件,请检查配置信息!", e);
    }
    return this;
}

获取表的列表,由ConfigBuilder完成

public List<TableInfo> getTableInfoList() {
    if (tableInfoList.isEmpty()) {
        // TODO 暂时不开放自定义
        List<TableInfo> tableInfos = new IDatabaseQuery.DefaultDatabaseQuery(this).queryTables();
        if (!tableInfos.isEmpty()) {
            this.tableInfoList.addAll(tableInfos);
        }
    }
    return tableInfoList;
}

然后获取上述单个表(tableInfo)的具体信息(objectMap)

/**
  * 渲染对象 MAP 信息
  *
  * @param config    配置信息
  * @param tableInfo 表信息对象
  * @return ignore
  */
@NotNull
public Map<String, Object> getObjectMap(@NotNull ConfigBuilder config, @NotNull TableInfo tableInfo) {
    StrategyConfig strategyConfig = config.getStrategyConfig();
    Map<String, Object> controllerData = strategyConfig.controller().renderData(tableInfo);
    Map<String, Object> objectMap = new HashMap<>(controllerData);
    Map<String, Object> mapperData = strategyConfig.mapper().renderData(tableInfo);
    objectMap.putAll(mapperData);
    Map<String, Object> serviceData = strategyConfig.service().renderData(tableInfo);
    objectMap.putAll(serviceData);
    Map<String, Object> entityData = strategyConfig.entity().renderData(tableInfo);
    objectMap.putAll(entityData);
    objectMap.put("config", config);
    objectMap.put("package", config.getPackageConfig().getPackageInfo());
    GlobalConfig globalConfig = config.getGlobalConfig();
    objectMap.put("author", globalConfig.getAuthor());
    objectMap.put("kotlin", globalConfig.isKotlin());
    objectMap.put("swagger", globalConfig.isSwagger());
    objectMap.put("date", globalConfig.getCommentDate());
    // 启用 schema 处理逻辑
    String schemaName = "";
    if (strategyConfig.isEnableSchema()) {
        // 存在 schemaName 设置拼接 . 组合表名
        schemaName = config.getDataSourceConfig().getSchemaName();
        if (StringUtils.isNotBlank(schemaName)) {
            schemaName += ".";
            tableInfo.setConvert(true);
        }
    }
    objectMap.put("schemaName", schemaName);
    objectMap.put("table", tableInfo);
    objectMap.put("entity", tableInfo.getEntityName());
    return objectMap;
}

根据TableInfo和objectMap输出类文件,以输出Entity实体类为例

/**
  * 输出实体文件
  *
  * @param tableInfo 表信息
  * @param objectMap 渲染数据
  * @since 3.5.0
  */
protected void outputEntity(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
    String entityName = tableInfo.getEntityName();
    String entityPath = getPathInfo(OutputFile.entity);
    if (StringUtils.isNotBlank(entityName) && StringUtils.isNotBlank(entityPath)) {
        getTemplateFilePath(template -> template.getEntity(getConfigBuilder().getGlobalConfig().isKotlin())).ifPresent((entity) -> {
            String entityFile = String.format((entityPath + File.separator + "%s" + suffixJavaOrKt()), entityName);
            outputFile(new File(entityFile), objectMap, entity, getConfigBuilder().getStrategyConfig().entity().isFileOverride());
        });
    }
}

在outputFile中来确定生成文件的名字和路径

/**
  * 输出文件
  *
  * @param file         文件
  * @param objectMap    渲染信息
  * @param templatePath 模板路径
  * @param fileOverride 是否覆盖已有文件
  * @since 3.5.2
  */
protected void outputFile(@NotNull File file, @NotNull Map<String, Object> objectMap, @NotNull String templatePath, boolean fileOverride) {
    if (isCreate(file, fileOverride)) {
        try {
            // 全局判断【默认】
            boolean exist = file.exists();
            if (!exist) {
                File parentFile = file.getParentFile();
                FileUtils.forceMkdir(parentFile);
            }
            writer(objectMap, templatePath, file);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }
}

最后通过writer方法生成文件

/**
  * 将模板转化成为文件
  *
  * @param objectMap    渲染对象 MAP 信息
  * @param templatePath 模板文件
  * @param outputFile   文件生成的目录
  * @throws Exception 异常
  * @since 3.5.0
  */
public void writer(@NotNull Map<String, Object> objectMap, @NotNull String templatePath, @NotNull File outputFile) throws Exception {
    this.writer(objectMap, templatePath, outputFile.getPath());
    logger.debug("模板:" + templatePath + ";  文件:" + outputFile);
}

本质上就是调用模版引擎来生成.

如何看待MyBatis-Plus生成代码的功能?

简单而言,对于初学者好像能生成代码作用很大,实际情况是很鸡肋!