Skip to content

自定义MybatisPlusGenerator

入口类

java
import cn.hutool.core.util.StrUtil;
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.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

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

/**
 * @author xc
 * @description
 * @date 2023/5/19 09:20
 */
public class MybatisPlusCodeGenerator {

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

    public static void main(String[] args) {
        //====================配置变量区域=====================//
        String author = "storyxc";// 生成文件的作者,可以不填
        String rootPackage = "com.storyxc";// 生成的entity、controller、service等包所在的公共上一级包路径全限定名
        String modelModuleName = "storyxc-model";
        String serviceModuleName = "storyxc-web";
        String controllerModuleName = "storyxc-web";
        // 数据库配置
        String url="jdbc:mysql://127.0.0.1/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
        String driverClassName = "com.mysql.cj.jdbc.Driver";// 或者com.mysql.cj.jdbc.Driver
        String username = "root";
        String password = "root";

        String[] tableNames = new String[]{""};
        String pkgName = "";
        //====================配置变量区域=====================//
        String[] tablePrefix = new String[]{""};
        // 代码生成器
        AutoGenerator generator = new AutoGenerator();
        // 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(projectPath + "/" + modelModuleName + "/src/main/java");// 生成文件的输出目录
        globalConfig.setFileOverride(false);// 是否覆盖已有文件,默认false
        globalConfig.setOpen(false);// 是否打开输出目录
        globalConfig.setAuthor(author);
        globalConfig.setServiceName("%sService");// 去掉service接口的首字母I
        globalConfig.setBaseResultMap(true);// 开启 BaseResultMap
        globalConfig.setDateType(DateType.ONLY_DATE);// 只使用 java.util.date代替
        globalConfig.setIdType(IdType.ASSIGN_ID);// 分配ID (主键类型为number或string)
        generator.setGlobalConfig(globalConfig);

        // 数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl(url);
        dataSourceConfig.setDbType(DbType.MYSQL);// 数据库类型
        dataSourceConfig.setDriverName(driverClassName);
        dataSourceConfig.setUsername(username);
        dataSourceConfig.setPassword(password);
        generator.setDataSource(dataSourceConfig);

        // 包配置
        PackageConfig packageConfig = new PackageConfig();
        //packageConfig.setModuleName(scanner("模块名"));
        packageConfig.setParent(rootPackage);
        packageConfig.setController("controller" + (StrUtil.isNotBlank(pkgName) ? "." + pkgName : ""));
        packageConfig.setService("service" + (StrUtil.isNotBlank(pkgName) ? "." + pkgName : ""));
        packageConfig.setServiceImpl("service" + (StrUtil.isNotBlank(pkgName) ? "." + pkgName + ".impl" : ".impl"));
        packageConfig.setEntity("dao.entity" + (StrUtil.isNotBlank(pkgName) ? "." + pkgName : ""));
        packageConfig.setMapper("dao.mapper" + (StrUtil.isNotBlank(pkgName) ? "." + pkgName : ""));

        //packageConfig.setXml("dao.mapper.xml");
        generator.setPackageInfo(packageConfig);

        // 注意:模板引擎在mybatisplus依赖中的templates目录下,可以依照此默认模板进行自定义

        // 策略配置:配置根据哪张表生成代码
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude(tableNames);// 表名,多个英文逗号分割(与exclude二选一配置)
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        // strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        strategy.setEntityLombokModel(true);// lombok模型,@Accessors(chain = true)setter链式操作
        strategy.setRestControllerStyle(true);// controller生成@RestController
        strategy.setEntityTableFieldAnnotationEnable(true);// 是否生成实体时,生成字段注解
        // strategy.setEntityColumnConstant(true);// 是否生成字段常量(默认 false)
        strategy.setTablePrefix(tablePrefix);// 生成实体时去掉表前缀

        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setController(null);
        templateConfig.setService(null);
        templateConfig.setServiceImpl(null);
        templateConfig.setXml(null);
        templateConfig.setMapper(null);
        templateConfig.setEntity(null);
        generator.setTemplate(templateConfig);


        generator.setStrategy(strategy);
        generator.setTemplateEngine(new FreemarkerTemplateEngine());

        /**
         * 自定义输出路径
         */
        // controller
        List<FileOutConfig> focList = new ArrayList<>();

        // mapper.xml
        focList.add(new FileOutConfig("/templates/story-entity.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/" + modelModuleName + "/src/main/java/" + rootPackage.replace(".", "/") + "/dao/entity/" + pkgName + "/" + tableInfo.getEntityName() + StringPool.DOT_JAVA;
            }
        });

        focList.add(new FileOutConfig("/templates/story-controller.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/" + controllerModuleName + "/src/main/java/" + rootPackage.replace(".", "/") + "/controller/" + pkgName + "/" + tableInfo.getEntityName() + "Controller" + StringPool.DOT_JAVA;
            }
        });
        // service
        focList.add(new FileOutConfig("/templates/service.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/" + serviceModuleName + "/src/main/java/" + rootPackage.replace(".", "/") + "/service/" + pkgName + "/" +  tableInfo.getEntityName() + "Service" + StringPool.DOT_JAVA;
            }
        });

        // serviceImpl
        focList.add(new FileOutConfig("/templates/story-serviceImpl.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/" + serviceModuleName + "/src/main/java/" + rootPackage.replace(".", "/") + "/service/" + pkgName + "/impl/" + tableInfo.getEntityName() + "ServiceImpl" + StringPool.DOT_JAVA;
            }
        });

        // mapper.java
        // service
        focList.add(new FileOutConfig("/templates/story-mapper.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/" + modelModuleName + "/src/main/java/" + rootPackage.replace(".", "/") + "/dao/mapper/" + pkgName + "/" +  tableInfo.getEntityName() + "Mapper" + StringPool.DOT_JAVA;
            }
        });

        // mapper.xml
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/" + modelModuleName + "/src/main/resources/mapper/" + pkgName + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        InjectionConfig injectionConfig = new InjectionConfig() {
            @Override
            public void initMap() { }
        };
        injectionConfig.setFileOutConfigList(focList);

        generator.setCfg(injectionConfig);
        generator.execute();
    }
}

模板

WARNING

模板不能使用IDE格式化,否则生成的文件缩进会有问题

story-entity.java.ftl

xml
package ${package.Entity};

<#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>
        import io.swagger.v3.oas.annotations.media.Schema;
        import lombok.experimental.FieldNameConstants;

        /**
        * ${table.comment!}
        *
        * @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>
        @FieldNameConstants
<#if superEntityClass??>
        public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
<#elseif activeRecord>
        public class ${entity} extends Model<${entity}> {
<#else>
        public class ${entity} 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>

        @Schema(description = "${field.comment}")
<#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>
        }

story-controller.java.ftl

xml
package ${package.Controller};

        import ${package.Service}.${table.serviceName};
        import org.springframework.web.bind.annotation.RequestMapping;
<#if restControllerStyle>
        import org.springframework.web.bind.annotation.RestController;
<#else>
        import org.springframework.stereotype.Controller;
        </#if>
<#if superControllerClassPackage??>
        import ${superControllerClassPackage};
        </#if>
        import io.swagger.v3.oas.annotations.tags.Tag;
        import lombok.RequiredArgsConstructor;
        import lombok.extern.slf4j.Slf4j;

        /**
        * ${table.comment!} 前端控制器
        *
        * @author ${author}
        * @since ${date}
        */
        @Tag(name = "")
        @Slf4j
        @RequiredArgsConstructor
<#if restControllerStyle>
        @RestController
<#else>
        @Controller
        </#if>
        @RequestMapping("<#if package.ModuleName?? && package.ModuleName != "">/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
<#if kotlin>
        class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
<#else>
<#if superControllerClass??>
        public class ${table.controllerName} extends ${superControllerClass} {
<#else>
        public class ${table.controllerName} {
        </#if>
        private final ${table.serviceName} ${table.serviceName?uncap_first};

        }
        </#if>

story-serviceImpl.java.ftl

xml
package ${package.ServiceImpl};

        import ${package.Entity}.${entity};
        import ${package.Mapper}.${table.mapperName};
        import ${package.Service}.${table.serviceName};
        import ${superServiceImplClassPackage};
        import org.springframework.stereotype.Service;
        import lombok.RequiredArgsConstructor;
        import lombok.extern.slf4j.Slf4j;

        /**
        * ${table.comment!} 服务实现类
        *
        * @author ${author}
        * @since ${date}
        */
        @Slf4j
        @RequiredArgsConstructor
        @Service
<#if kotlin>
        open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {

        }
<#else>
        public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {

        }
        </#if>

story-mapper.java.ftl

java
package ${package.Mapper};

import ${package.Entity}.${entity};
import ${superMapperClassPackage};
import org.apache.ibatis.annotations.Mapper;

/**
 * <p>
 * ${table.comment!} Mapper 接口
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}>
<#else>
@Mapper
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {

}
</#if>

新版

java
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.Collections;

// 执行 main 方法,控制台输入模块表名,回车自动生成对应项目目录中
public class MybatisPlusCodeGenerator {

    public static void main(String[] args) {
        //====================配置变量区域=====================//
        String author = "xc";// 生成文件的作者,可以不填
        String rootPackage = "com.story.test";// 生成的entity、controller、service等包所在的公共上一级包路径全限定名
        String module = "modules/moduleA";
        String folder = "subFolder";
        // 数据库配置
        String url = "jdbc:mysql://ip:port/database?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
        String username = "";
        String password = "";

        String[] tableNames = new String[]{"tb_table_name"};
        String[] tablePrefix = new String[]{"tb_"};

        FastAutoGenerator.create(
                        // 数据源配置
                        url,
                        username,
                        password)
                // 全局配置
                .globalConfig(builder -> {
                    builder.author(author)
                            .outputDir(System.getProperty("user.dir") + "/" + module + "/src/main/java")
                            .disableOpenDir()
                            .dateType(DateType.ONLY_DATE);
                })
                // 包配置
                .packageConfig(builder -> {
                    builder.parent(rootPackage)
                            .entity("dao.entity" + (StrUtil.isBlank(folder) ? "" : "." + folder))
                            .mapper("dao.mapper" + (StrUtil.isBlank(folder) ? "" : "." + folder))
                            .service("service" + (StrUtil.isBlank(folder) ? "" : "." + folder))
                            .serviceImpl("service.impl" + (StrUtil.isBlank(folder) ? "" : "." + folder))
                            .pathInfo(Collections.singletonMap(
                                    OutputFile.xml, System.getProperty("user.dir") + "/" + module + "/src/main/resources/mapper" + (StrUtil.isBlank(folder) ? "" : "/" + folder)
                            ))
                    ;

                })
                // 模版配置
                .templateConfig(builder -> {
                    builder
                            // .controller("/templates/controller.java")
                            .controller("")
                            .serviceImpl("/templates/serviceImpl.java")
                            // .service("")
                            // .serviceImpl("")
                            .mapper("/templates/mapper.java")
                            .entity("/templates/entity.java");
                })
                // 策略配置
                .strategyConfig(builder -> {
                    builder.addInclude(tableNames)
                            .addTablePrefix(tablePrefix)
                            .controllerBuilder().enableRestStyle()
                            .entityBuilder().enableLombok()
                            .entityBuilder().enableTableFieldAnnotation()
                            .serviceBuilder().formatServiceFileName("%sService")
                            .mapperBuilder().enableBaseResultMap();


                })
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();

    }
}