基于模板的maven代码生成器

目录

  • 前言
  • 1. 功能简介
  • 2. 快速开始(mvn generator:generate)
    • 2.1 pom.xml插件配置
    • 2.2 生成效果图
  • 3. 目前支持的配置项
    • 3.1 配置项详解
    • 3.2 略复杂配置Demo
  • 4. ftl模板常用变量
  • 附录(测试文件、模板)
    • 源码地址
    • DDL
    • entity.java.ftl
    • constant.java.ftl
    • mapper.java.ftl
    • mapper.xml.ftl
    • sevice.java.ftl
    • seviceImpl.java.ftl
    • controller.java.ftl
    • /src/resources/manager.ftl(扩展模板文件)
  • 结语

前言

该生成器是基于mybatis-plus的基础上根据个人在实际生产中所遇到过的各种设计而进行思考扩展的。为了提供更好地扩展性,使用者只需提供自定义的模板即可生成对应的文件,也可使用默认模板。目前模板语言只支持freemarker,因为作为一个生成工具个人认为无需考虑性能与使用哪种模板语言上的问题也没有对模板这方面进行深究,个人对freemarker也只是略懂(遇到不懂的表达式自己也是百度一下,无需深学),但也足以作为生成所需。项目地址:maven版,依赖类生成版。通过依赖注入生成的版本之后可能会废弃,仅供研究。虽然觉得功能已足够,但还是希望使用者们发现扩展性强的功能可以提一下建议,采纳后会尽快更新版本。该文章可能不会随功能更新而同步更新,所以具体功能更新信息可到版本更新信息查看。

1. 功能简介

目前可选择的生成器很多,个人目前所接触过的有tk、mybatis源生、mybatis-plus、jOOQ的生成器,各个项目基本都是基于持久层框架而选择相应的生成器的,这也使得生成器对应的持久层框架适配性最好。当然,扩展性强的也有,mybatis-plus是个人认为以上几个生成器中扩展性最好的,缺点是需要添加依赖,生成器类无法为每个项目重用,特别是在多模块项目中修改量较大。以下是个人基于mybatis-plus生成器的功能与个人的思考扩展后集成为maven生成器插件的主要功能:

  • 基于数据库字段注释指定样式的常量生成(建议一个entity对应一个constant,这样即便负责不同模块的负责人或接手维护者也可迅速定位一个实体的常量维护类,而无需考虑因开发者因对领域的不同理解划分而增加查找难度,当然仅是个人在开发过程中所遇到的问题)
  • 只生成/不生成表名含指定关键字的service、serviceImpl模板文件(基于服务中的领域耦合可考虑哪些数据表无需生成)
  • 根据自定义的freemarker模板生成文件,设置了(如自定义生成相应的Manager层进行业务下沉,VO、DTO生成)

2. 快速开始(mvn generator:generate)

  • 2.1 pom.xml插件配置

       
           io.github.wilson-he
           generator-maven-plugin
           LATEST
           
               io.github.test
               
                   
                   root
                   tiger
                   MYSQL
               
           
           
               
                   
                       generate
                   
               
           
       
    
  • 2.2 生成效果图

    基于模板的maven代码生成器_第1张图片

3. 目前支持的配置项

  • 3.1 配置项详解

    • outputDirectory: 输出绝对路径,默认生成到当前pom项目模块的target/generate-sources下
    • basePackage: 各层文件生成的基包[required]
    • isCleanBefore(boolean): 文件生成前是否清空当前模块下的target目录,默认false
    • useSwagger(boolean):生成文件是否带swagger注解,默认false
    • superEntityClass:entity父类,完整包路径.类名
    • author:模板author值
    • dataSource: 数据库配置[required]
      • url
      • username
      • password
      • driverType:数据库驱动类型(MYSQL,ORACLE,POSTGRE_SQL)
    • templates: 自定义模板配置、模板生成配置,不配置则使用默认模板配置生成
      • entityPath: resources下的自定义entity模板相对路径
      • constantPath
      • daoPath
      • xmlPath
      • servicePath
      • serviceImplPath
      • controllerPath
      • entityPattern: entity名称样式,如:%sDO将以{tableName}DO命名生成
      • daoPattern
      • xmlPattern
      • servicePattern
      • serviceImplPattern
      • controllerPattern
      • excludeEntity: true/false,是否生成entity模板类
      • excludeXxx: 同excludeEntity
      • excludeController: 默认true,其它层默认false
      • customs: 对象列表,自定义模板
        • layerName: 模板分层名(请勿使用已存在ftl变量)
        • subPackage: 所在子包
        • path: 模板在resources下的相对路径
    • exclusions: 字符串数组,不生成表名含数组内字符串的所有文件,默认空
    • inclusions: 字符串数组,只生成表名含数组内字符串的所有文件,默认空
    • upstreamExclusions: 字符串数组,不生成表名含数组内字符串的自定义模板、service、serviceImpl、controller文件,默认空
    • upstreamInclusions: 字符串数组,只生成表名含数组内字符串的自定义模板、service、serviceImpl、controller文件,默认空
    • logicDeleteFieldName: 全局逻辑删除字段名,默认空
    • tablePrefix: 字符串数组,表名前缀,默认空
  • 3.2 略复杂配置Demo

       
          io.github.wilson-he
          generator-maven-plugin
          LATEST
          
              io.github.test
              
                  
                  root
                  tiger
                  MYSQL
              
              
                  
                  relation
              
              
                  
                  
                  detail
              
              
                  /templates/custom-entity.java.ftl
                  true
                  
                      
                          /templates/manager.ftl
                          
                          manager
                          Manager
                      
                  
                  %sDAO
              
          
          
              
                  
                      generate
                  
              
          
      
    

4. ftl模板常用变量

  • package: 包路径变量,${package.xxx}
    • Entity: entity完整包路径,如io.github.test.entity
    • Mapper
    • Service
    • ServiceImpl
    • Controller
  • table: 表信息变量,${table.xxx}
    • comment: 注释
    • name: 表名
    • entityName: 当前表对应生成的entity文件名,如UserBase.java
    • constantName: 当前表对应生成的constant文件名,如UserBaseConstant.java
    • mapperName: 同上
    • xmlName: 同上
    • serviceName: 同上
    • serviceImplName: 同上
    • controllerName: 同上
    • fields: 字段列表,模板遍历<#list table.fields as field>,以下为field变量
      • table: 表名
      • propertyType: 属性类型
      • propertyName: 属性名
      • name: db字段名
      • comment: 字段注释

附录(测试文件、模板)

  • 源码地址

    • github
    • 码云
  • DDL

    create table user_base
    (
        id          int auto_increment
            primary key,
        username    varchar(45)       null,
        password    varchar(45)       null,
        create_time timestamp         null,
        update_time timestamp         null,
        is_delete   tinyint default 1 not null comment '删除(YES:0-未删除,NO:1-已删除)',
        status      varchar(10)       null comment '状态(ENABLE-启用,DISABLE-禁用)'
    );
    
    create table user_detail
    (
        id          int                                 not null
            primary key,
        sex         char                                null,
        age         tinyint                             null,
        create_time timestamp default CURRENT_TIMESTAMP null,
        update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP,
        is_delete   char      default '0'               not null,
        user_id     int                                 null
    );
    
  • entity.java.ftl

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

    * ${table.comment!} *

    * * @author ${author} * @since ${date} */ <#if entityLombokModel> @Data <#if superEntityClass??> @EqualsAndHashCode(callSuper = true) <#else> @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) <#if table.convert> @TableName("${table.name}") <#if swagger2> @ApiModel("${table.comment!}") <#if superEntityClass??> public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}> { <#elseif activeRecord> public class ${entity} extends Model<${entity}> { <#else> public class ${entity} implements Serializable { <#-- ---------- BEGIN 字段循环遍历 ----------> <#list table.fields as field> <#if field.keyFlag> <#assign keyPropertyName="${field.propertyName}"/> <#if field.comment!?length gt 0> <#if swagger2> @ApiModelProperty("${field.comment}") <#else> /** * ${field.comment} */ <#if field.keyFlag> <#-- 主键 --> <#if field.keyIdentityFlag> @TableId(value = "${field.name}", type = IdType.AUTO) <#elseif idType??> @TableId(value = "${field.name}", type = IdType.${idType}) <#elseif field.convert> @TableId("${field.name}") <#-- 普通字段 --> <#elseif field.fill??> <#-- ----- 存在字段填充设置 -----> <#if field.convert> @TableField(value = "${field.name}", fill = FieldFill.${field.fill}) <#else> @TableField(fill = FieldFill.${field.fill}) <#elseif field.convert> @TableField("${field.name}") <#-- 乐观锁注解 --> <#if (versionFieldName!"") == field.name> @Version <#-- 逻辑删除注解 --> <#if (logicDeleteFieldName!"") == field.name> @TableLogic private ${field.propertyType} ${field.propertyName}; <#------------ END 字段循环遍历 ----------> <#if !entityLombokModel> <#list table.fields as field> <#if field.propertyType == "boolean"> <#assign getprefix="is"/> <#else> <#assign getprefix="get"/> public ${field.propertyType} ${getprefix}${field.capitalName}() { return ${field.propertyName}; } <#if entityBuilderModel> public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) { <#else> public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) { this.${field.propertyName} = ${field.propertyName}; <#if entityBuilderModel> return this; } <#if entityColumnConstant> <#list table.fields as field> public static final String ${field.name?upper_case} = "${field.name}"; <#if activeRecord> @Override protected Serializable pkVal() { <#if keyPropertyName??> return this.${keyPropertyName}; <#else> return null; } <#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} + "}"; } <#list table.fields as field> <#if field.constantField> public Object get${field.propertyName?cap_first}Dict() { return ${entity}Constant.${field.propertyName?cap_first}.MAP.get(this.${field.propertyName}); } }
  • constant.java.ftl

    package ${package.Constant};
    
    import com.google.common.collect.ImmutableMap;
    
    import java.util.Map;
    
    /**
     * ${entity}常量类
     *
     * @author ${author}
     * @since ${date}
     */
    public interface ${entity}Constant {
    
    <#list table.fields as field>
        <#if field.constantField>
        /**
         * ${field.comment}
         */
        interface ${field.propertyName?capFirst} {
        <#list field.fieldEnums as fieldEnum>
            /**
             * ${fieldEnum.comment}
             */
            ${field.columnType.type} ${fieldEnum.key} = ${fieldEnum.value};
        
        <#if field.fieldEnums?size lt 6>
            Map<${field.columnType.type}, String> MAP = ImmutableMap.of(
            <#list field.fieldEnums as fieldEnum>
                <#if fieldEnum_has_next>
                    ${fieldEnum.key}, "${fieldEnum.comment}",
                <#else >
                    ${fieldEnum.key}, "${fieldEnum.comment}");
                
            
        <#else>
            Map MAP = ImmutableMap.builder()
            <#list field.fieldEnums as fieldEnum>
                <#if fieldEnum_has_next>
                    .put(${fieldEnum.key}, "${fieldEnum.comment}")
                
            
                    .build();
        
        }
    
        
    
    }
    
  • mapper.java.ftl

    package ${package.Mapper};
    
    import ${package.Entity}.${entity};
    import ${superMapperClassPackage};
    
    /**
     * 

    * ${table.comment!}Mapper 接口 *

    * * @author ${author} * @since ${date} */ <#if kotlin> interface ${table.mapperName} : ${superMapperClass}<${entity}> <#else> public interface ${table.mapperName} extends ${superMapperClass}<${entity}> { }
  • mapper.xml.ftl

    
    
    
    
        <#if baseResultMap>
        
        
            <#list table.fields as field>
                <#if field.keyFlag><#--生成主键排在第一位-->
            
            
        
        <#list table.commonFields as field><#--生成公共字段 -->
            
        
        <#list table.fields as field>
            <#if !field.keyFlag><#--生成普通字段 -->
            
                
            
        
    
        
            
        
            <#list table.commonFields as field>
                ${field.name},
            
            ${table.fieldNames}
        
    
    
  • sevice.java.ftl

    package ${package.Service};
    
    import ${package.Entity}.${entity};
    
    /**<#if table.comment??>${"\n"} * 

    * ${entity}-${table.comment!}业务接口 *

    * * @author ${author} * @since ${date} */ <#if kotlin> interface ${table.serviceName} : ${superServiceClass}<${entity}> <#else> public interface ${table.serviceName} { }
  • seviceImpl.java.ftl

    package ${package.ServiceImpl};
    
    import ${package.Entity}.${entity};
    import ${package.Mapper}.${table.mapperName};
    import ${package.Service}.${table.serviceName};
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    /**<#if table.comment??>${"\n"} * 

    * ${entity}-${table.comment!}业务接口 *

    * * @author ${author} * @since ${date} */ @Service <#if kotlin> open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} { } <#else> public class ${table.serviceImplName} implements ${table.serviceName}{ @Resource private ${table.mapperName} ${table.mapperName?uncap_first}; }
  • controller.java.ftl

    package ${package.Controller};
    
    
    import io.swagger.annotations.ApiParam;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    
    <#if restControllerStyle>
    import org.springframework.web.bind.annotation.RestController;
    <#else>
    import org.springframework.stereotype.Controller;
    
    <#if superControllerClassPackage??>
    import ${superControllerClassPackage};
    
    
    /**
     * 

    * <#if table.comment??><#if table.comment?ends_with("表")>${table.comment?replace("表","控制器")}<#else>${table.comment} *

    * * @author ${author} * @since ${date} */ @RestController @RequestMapping("<#if package.ModuleName??>/${package.ModuleName}/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}") <#if kotlin> class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}() <#else> <#if superControllerClass??> public class ${table.controllerName} extends ${superControllerClass} { <#else> public class ${table.controllerName} { @PostMapping("/") public Object add(@Validated @RequestBody Object vo){ return null; } @GetMapping("/") public Object get(@ApiParam(name = "id", value = "<#if table.comment??><#if table.comment?ends_with("表")>${table.comment?replace("表","")}<#else>${table.comment}id") @RequestParam String id){ return null; } @GetMapping("/page") public Object page(@ApiParam(name = "page", value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer page, @ApiParam(name = "size", value = "每页返回数", defaultValue = "15") @RequestParam(defaultValue = "15") Integer size){ return null; } @PutMapping("/") public Object update(@Validated @RequestBody Object vo){ return null; } @DeleteMapping("/") public Object delete(@ApiParam(name = "id", value = "<#if table.comment??><#if table.comment?ends_with("表")>${table.comment?replace("表","")}<#else>${table.comment}id") @RequestParam String id){ return null; } }
  • /src/resources/manager.ftl(扩展模板文件)

     package ${package.Manager};
     
     /**<#if table.comment??>${"\n"} * 

    * ${entity}-${table.comment!}业务接口 *

    * * @author ${author} * @since ${date} */ public class ${entity}Manager { }

结语

觉得工具不错的希望可以顺手star一下或donate一下*.*!

你可能感兴趣的:(Maven,MyBatis)