• SpringBoot中几种好用的代码生成器(基于Mybatis-plus生成entity、mapper、xml等)


    前言

    熟悉Spring框架的同学一定都知道MVC开发模式吧,控制器(Controller)、业务类(Service)、持久层(Repository)、数据库映射(Mapper)、各种DO类构成了我们服务端的代码。初学的时候,觉得新鲜手写这些东西不觉得有啥,但是写久了就会觉得很烦。好不容易在数据库中写完了一遍字段,在Java代码又要写一遍,不仅很枯燥,关键是还容易写错!!!

    字段名称写错的痛,只有踩过这坑的人才能体会... ...

    所以,如果有一个工具可以在我们创建完数据库表之后自动帮助我们生成各种类就好了。

    这种工具不仅有,而且有很多,首先推荐一个最最简单的:

    在线版Java代码生成器

    如果有用过bejson在线工具的小伙伴,应该很熟悉,不过这个工具有个缺点:
    开发者需要自己手动创建代码目录和代码文件,然后一个一个将代码复制到文件中

    所以为了让大家更省事一些,下面推荐的2种方法不仅可以生成代码,还可以直接创建好文件夹、代码类。这2种方法的效果差不多,自己看情况选用吧。

    第一种:mybatis-plus-generator配合freemaker引擎

    尝试一下🍓

    SpringBoot项目pom.xml

    
    
        4.0.0
        
            org.springframework.boot
            spring-boot-starter-parent
            2.7.1
             
        
        com.example
        SpringBoot-CodeGenerator
        0.0.1-SNAPSHOT
        SpringBoot-CodeGenerator
        Demo project for Spring Boot
        
            1.8
        
        
            
                org.springframework.boot
                spring-boot-starter-web
            
    
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
    
            
            
                com.baomidou
                mybatis-plus-generator
                3.2.0
            
            
            
                org.freemarker
                freemarker
                2.3.29
            
            
            
                org.projectlombok
                lombok
                true
            
            
            
                mysql
                mysql-connector-java
            
        
    
    
    
    

    resources目录

    controller.java.ftl

    package ${package.Controller};
    
    
    import org.springframework.web.bind.annotation.RequestMapping;
    
    <#if restControllerStyle>
    import org.springframework.web.bind.annotation.RestController;
    <#else>
    import org.springframework.stereotype.Controller;
    
    <#if superControllerClassPackage??>
    import ${superControllerClassPackage};
    
    
    /**
     * @author ${author}
     */
    <#if restControllerStyle>
    @RestController
    <#else>
    @Controller
    
    @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} {
        
    
    }
    
    
    

    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 entityLombokModel>
        import lombok.Data;
        import lombok.EqualsAndHashCode;
        import lombok.experimental.Accessors;
    
    
    /**
    * ${table.comment!}
    *
    * @author ${author}
    */
    <#if entityLombokModel>
        @Data
        <#if superEntityClass??>
            @EqualsAndHashCode(callSuper = true)
        <#else>
            @EqualsAndHashCode(callSuper = false)
        
        @Accessors(chain = true)
    
    <#if table.convert>
        @TableName("${table.name}")
    
    <#if swagger2>
        @ApiModel(value="${entity}对象", description="${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 {
    
    
    private static final long serialVersionUID = 1L;
    <#-- ----------  BEGIN 字段循环遍历  ---------->
    <#list table.fields as field>
        <#if field.keyFlag>
            <#assign keyPropertyName="${field.propertyName}"/>
        
    
        <#if field.comment!?length gt 0>
            <#if swagger2>
                @ApiModelProperty(value = "${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} +
            
        
        "}";
        }
    
    }
    

    mapper.java.ftl

    package ${package.Mapper};
    
    import ${package.Entity}.${entity};
    import ${superMapperClassPackage};
    
    /**
     * @author ${author}
     */
    <#if kotlin>
    interface ${table.mapperName} : ${superMapperClass}<${entity}>
    <#else>
    public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
    
    }
    
    
    

    mapper.xml.ftl

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

    service.java.ftl

    package ${package.Service};
    
    import ${package.Entity}.${entity};
    import ${superServiceClassPackage};
    
    /**
     * @author ${author}
     */
    <#if kotlin>
    interface ${table.serviceName} : ${superServiceClass}<${entity}>
    <#else>
    public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
    
    }
    
    
    
    

    serviceImpl.java.ftl

    package ${package.ServiceImpl};
    
    import ${package.Entity}.${entity};
    import ${package.Mapper}.${table.mapperName};
    import ${package.Service}.${table.serviceName};
    import ${superServiceImplClassPackage};
    import org.springframework.stereotype.Service;
    
    /**
     * @author ${author}
     */
    @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} {
    
    }
    
    
    
    

    上面这些文件直接创建在resources/generator1/templates的目录下,把内容复制进去就行了。这些文件就是你代码生成的格式模板,当然自己也可以修改。

    生成代码

    package com.example.springbootcodegenerator.util;
    
    import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
    import com.baomidou.mybatisplus.generator.AutoGenerator;
    import com.baomidou.mybatisplus.generator.config.*;
    import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
    import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    
    import java.util.Scanner;
    
    /**
     * mybatis plus 提供的代码生成器
     * 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码
     *
     * @link https://mp.baomidou.com/guide/generator.html
     */
    public class CodeGenerator {
    
        // 数据库 URL
        private static final String URL = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
        // 数据库驱动
        private static final String DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
        // 数据库用户名
        private static final String USERNAME = "root";
        // 数据库密码
        private static final String PASSWORD = "123456";
        // @author 值
        private static final String AUTHOR = "sun墨";
        // 包的基础路径
        private static final String BASE_PACKAGE_URL = "com.example.springbootcodegenerator";
        // xml文件路径
        private static final String XML_PACKAGE_URL = "/src/main/resources/mapper/";
        // xml 文件模板
        private static final String XML_MAPPER_TEMPLATE_PATH = "generator1/templates/mapper.xml";
        // mapper 文件模板
        private static final String MAPPER_TEMPLATE_PATH = "generator1/templates/mapper.java";
        // entity 文件模板
        private static final String ENTITY_TEMPLATE_PATH = "generator1/templates/entity.java";
        // service 文件模板
        private static final String SERVICE_TEMPLATE_PATH = "generator1/templates/service.java";
        // serviceImpl 文件模板
        private static final String SERVICE_IMPL_TEMPLATE_PATH = "generator1/templates/serviceImpl.java";
        // controller 文件模板
        private static final String CONTROLLER_TEMPLATE_PATH = "generator1/templates/controller.java";
    
        public static void main(String[] args) {
            AutoGenerator generator = new AutoGenerator();
    
            // 全局配置
            GlobalConfig globalConfig = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            globalConfig.setOutputDir(projectPath + "/src/main/java");
            globalConfig.setAuthor(AUTHOR);
            globalConfig.setOpen(false);
            globalConfig.setFileOverride(false);
            generator.setGlobalConfig(globalConfig);
    
            // 数据源配置
            DataSourceConfig dataSourceConfig = new DataSourceConfig();
            dataSourceConfig.setUrl(URL);
            dataSourceConfig.setDriverName(DRIVER_NAME);
            dataSourceConfig.setUsername(USERNAME);
            dataSourceConfig.setPassword(PASSWORD);
            generator.setDataSource(dataSourceConfig);
    
            // 包配置
            PackageConfig packageConfig = new PackageConfig();
            packageConfig.setModuleName("gen");
            packageConfig.setParent(BASE_PACKAGE_URL);
            generator.setPackageInfo(packageConfig);
    
            // 配置自定义代码模板
            TemplateConfig templateConfig = new TemplateConfig();
            templateConfig.setXml(XML_MAPPER_TEMPLATE_PATH);
            templateConfig.setMapper(MAPPER_TEMPLATE_PATH);
            templateConfig.setEntity(ENTITY_TEMPLATE_PATH);
            templateConfig.setService(SERVICE_TEMPLATE_PATH);
            templateConfig.setServiceImpl(SERVICE_IMPL_TEMPLATE_PATH);
            templateConfig.setController(CONTROLLER_TEMPLATE_PATH);
            generator.setTemplate(templateConfig);
    
            // 策略配置
            StrategyConfig strategy = new StrategyConfig();
            strategy.setNaming(NamingStrategy.underline_to_camel);
            strategy.setColumnNaming(NamingStrategy.underline_to_camel);
            strategy.setEntityLombokModel(true);
            strategy.setRestControllerStyle(true);
            strategy.setInclude(scanner("表名"));
            strategy.setSuperEntityColumns("id");
            strategy.setControllerMappingHyphenStyle(true);
            strategy.setTablePrefix(packageConfig.getModuleName() + "_");
            generator.setStrategy(strategy);
            generator.setTemplateEngine(new FreemarkerTemplateEngine());
            generator.execute();
        }
    
        private static String scanner(String tip) {
            Scanner scanner = new Scanner(System.in);
            System.out.println(("请输入" + tip + ":"));
            if (scanner.hasNext()) {
                String ipt = scanner.next();
                if (null != ipt && !"".equals(ipt)) {
                    return ipt;
                }
            }
            throw new MybatisPlusException("请输入正确的" + tip + "!");
        }
    }
    
    

    效果展示

    运行这个类之后,输入表名

    代码目录如下:

    第二种:tk.mybatis配合maven插件

    尝试一下🍓

    SpringBoot项目pom.xml

    
    
        4.0.0
        
            org.springframework.boot
            spring-boot-starter-parent
            2.7.1
             
        
        com.example
        SpringBoot-CodeGenerator
        0.0.1-SNAPSHOT
        SpringBoot-CodeGenerator
        Demo project for Spring Boot
        
            1.8
        
        
            
                org.springframework.boot
                spring-boot-starter-web
            
    
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
    
            
            
                com.baomidou
                mybatis-plus-generator
                3.2.0
            
            
            
                com.baomidou
                mybatis-plus-boot-starter
                3.2.0
            
            
                javax.persistence
                javax.persistence-api
            
            
            
                org.projectlombok
                lombok
                true
            
            
            
                mysql
                mysql-connector-java
            
        
    
        
            
                
                    org.mybatis.generator
                    mybatis-generator-maven-plugin
                    1.3.6
                    
                        ${basedir}/src/main/resources/generator2/generatorConfiguration.xml
                        
                        true
                        true
                    
                    
                        
                            tk.mybatis
                            mapper
                            4.1.2
                        
                    
                
            
        
    
    
    

    resources目录

    config.properties

    ## 驱动
    jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&useSSL=false
    ## 登录名
    jdbc.user=root
    ## 登录密码
    jdbc.password=123456
    ## 表名
    table.name=t_test
    ## DO
    entity.name=TTestDO
    ## Mapper
    mapper.name=TTestMapper
    
    

    generatorConfiguration.xml

    
    
    
        
    
        
        
            
            
    
            
                
                
                
                
            
    
            
            
    
    
            
    
            
                
            
    
            
            
    
            
            

    上面两个文件配置好之后,如果使用的是idea,且装有maven插件,在maven 的Plugins中会有一个mybatis-generator选项,点击mybatis-generator :generate即可运行

    没有这个插件也不要紧,运行下面这个命令也可以

    mvn mybatis-generator:generate
    

    效果展示

    总结一下

    总体来说,这两种方式的效果都是差不多的。第一种方式可以自己创建任意文件,第二种方式专注于配置。个人喜欢第二种方式,不想写代码而已🤤

    问题总结

    有些同学在使用的时候遇到一些问题,有的是只创建了文件夹,有的是生成的entity不对,如下图:

    问题1、生成的是空目录

    有两种可能,第一种是你们的配置不对,可以详细对照一下我的配置;第二种就是输出路径不对,生成的文件没法输出。

    问题2、第一个方法的模版有问题

    我看了下entity.java.ftl的内容确实不对,估计是当时复制错了,已改正,谢谢提醒。

    文末小彩蛋,自己花一个星期做的小网站,放出来给大家看看,网址如下:http://47.120.49.119:8080

    作者:不若为止
    欢迎任何形式的转载,但请务必注明出处。
    限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

  • 相关阅读:
    怕客户跑单?这套上市制造企业都在使的订单管理方案你一定要看看
    常见的几种排序方式
    Java之IO转换流
    损失函数总结(五):PoissonNLLLoss、GaussianNLLLoss
    松翰SN8P2511 SOP8单片机 可代烧录 提供单片机方案开发 单片机解密
    【无标题】
    ES6模块介绍—module的语法import、export简单介绍及用法
    MySQL进阶实战9,InnoDB和MyISAM的数据分布对比
    C++实现单链表
    Java 将Map转成Json
  • 原文地址:https://www.cnblogs.com/wlovet/p/18163178