Mybatis-Plus代码生成器详解及完整代码实现

2023-05-16

意义

1、日常开发过程中,常规后端开发接收到需求后,进行数据库E-R设计后创建对应数据表。无论基于speingmvc还是strtus(同样是一个mvc框架),都需要进行一些固定模板的创建,如:entity、controller、service、impl、mapper等,重复ctrl c + v。
2、公司开发经常会由多个小组或多人进行,统一的代码格式将有利于工作推进(尤其在新手较多的公司)。

前提

本文基于mybatis-plus 3.5.2及以上版本,模板引擎使用freemarker。生成的模板代码符合常规前后端开发模式(springboot + mybatis-plus),符合rest风格,建议创建数据表时写注释,生成的entity代码可读性更强。代码可直接使用,模板可按实际规范调整。

项目结构

1
resource – 配置文件、模板文件
pom.xml – jar包依赖

pom.xml

<dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-freemarker</artifactId>
       </dependency>
    </dependencies>

generatorConf.propertites

建议使用配置文件的方式便于调整,相关配置也可在代码中写死

## dataSource数据库配置
# mysql 数据库类型
dbType=mysql
url=jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=1234567890
## globalConfig全局配置
projectPath=E://gen
module=/camp
author=HS

核心代码

1、配置类

package com.camp.gen.config;

import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.querys.DMQuery;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.function.ConverterFileName;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import com.camp.gen.handler.DmKeyWordsHandler;
import org.apache.ibatis.cache.Cache;
import org.jetbrains.annotations.NotNull;

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

/**
 * @Description 代码生成器核心配置
 * @Author HS
 * @Date 2022/12/5 10:31
 */
public class GeneratorConfig {
    /**
     * 配置文件
     */
    private static ResourceBundle generatorConf;

    static {
        generatorConf = ResourceBundle.getBundle("generatorConf");
    }

    public static DataSourceConfig initDataSourceConfig() {
        String dbType = generatorConf.getString("dbType");
        IDbQuery query;
        IKeyWordsHandler keyWordsHandler;
        switch (dbType){
            case "dm":
                query = new DMQuery();
                keyWordsHandler = new DmKeyWordsHandler();
                break;
            default:
                query = new MySqlQuery();
                keyWordsHandler = new MySqlKeyWordsHandler();
                break;
        }
        DataSourceConfig dataSourceConfig = new DataSourceConfig
                .Builder(generatorConf.getString("url"), generatorConf.getString("username"), generatorConf.getString("password"))
                .dbQuery(query)
                //自定义数据库-java类型转换器,具体类需继承MySqlTypeConvert
                //.typeConvert(new MySqlTypeConvert())
                .keyWordsHandler(keyWordsHandler)
                .build();
        return  dataSourceConfig;
    }

    /**
     * 全局配置
     * @return
     */
    public static GlobalConfig initGlobalConfig(){
        // 全局配置
        GlobalConfig gc = new GlobalConfig.Builder()
                //设置输出文件路径
                .outputDir(generatorConf.getString("projectPath") +generatorConf.getString("module"))
                .author(generatorConf.getString("author"))
                //执行完 是否打开输出的目录,默认true
                .disableOpenDir()
                // 设置日期类型为Date(若不设置时间类型都会变成LocalDateTime部分连接池例如druid是无法识别的)
                .dateType(DateType.ONLY_DATE)
                .build();
        return gc;
    }

    /**
     * 包配置
     * @return
     */
    public static PackageConfig initPackageConfig(){
        // 包配置
        PackageConfig pc = new PackageConfig.Builder()
                //父包
                .parent("com.css.cssbase.modules")
                //自定义实体包名
                .entity("entity")
                //自定义mapper包名
                .mapper("mapper")
                //自定义mapper.xml包名
                .xml("mapper.xmls")
                //自定义service包名
                .service("service")
                //自定义serviceImpl包名
                .serviceImpl("service.impl")
                //自定义controller包名
                .controller("controller")
                //自定义包名
                .other("domain")
                .build();
        return pc;
    }

    /**
     * 模板配置
     * @return
     */
    public static TemplateConfig initTemplateConfig(){
        // 配置模板
        TemplateConfig tc = new TemplateConfig.Builder()
                .entity("vm/java/entity.java")
                .controller("vm/java/controller.java")
                .mapper("vm/java/mapper.java")
                .service("vm/java/service.java")
                .serviceImpl("vm/java/serviceImpl.java")
                .xml("vm/xml/mapper.xml")
                .build();
        return tc;
    }

    /**
     * 策略配置
     * @return
     */
    public static StrategyConfig initStrategyConfig(List<String> tableNames){
        // 策略配置
        StrategyConfig strategy = new StrategyConfig.Builder()
                .addInclude(tableNames)
                //定制实体
                .entityBuilder()
                .enableLombok()
                .naming(NamingStrategy.underline_to_camel)
                .columnNaming(NamingStrategy.underline_to_camel)
                //生成实体时生成数据库字段注解
                .enableTableFieldAnnotation()
                //定制controller
                .controllerBuilder()
                //是否rest模式
                .enableRestStyle()
                //定制service & Impl
                .serviceBuilder()
                //service命名规则
                .convertServiceFileName(new ConverterFileName() {
                    @NotNull
                    @Override
                    public String convert(String entityName) {
                        return entityName + ConstVal.SERVICE;
                    }
                })
                //定制mapper
                .mapperBuilder()
                .enableBaseColumnList()
                .enableBaseResultMap()
                //TODO 需根据实际缓存调整
                .cache(Cache.class)
                .build();
        return strategy;
    }

    /**
     * 注入自定义配置-参数、生成类
     * @return
     */
    public static InjectionConfig initInjectionConfig(Map<String, Object> parameterMap){
        //自定义生成类
        HashMap<String, String> customFileMap = new HashMap<>(4);
        //Vo实体
        customFileMap.put(File.separator+"%sVO.java", "vm/java/vo.java.ftl");
        //DTO实体
        customFileMap.put(File.separator+"%sDTO.java", "vm/java/dto.java.ftl");

        return new InjectionConfig.Builder()
                .customMap(parameterMap)
                .customFile(customFileMap)
                .build();
    }
}

2、自定义模板解析器,不需要可不写(此处用于生成domain下的dto、vo)

package com.camp.gen.handler;

import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.jetbrains.annotations.NotNull;

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

/**
 * @Description 自定义模板解析器
 * @Author HS
 * @Date 2022/11/28 15:24
 */
public class MyFreeMarkerTemplateEngine extends FreemarkerTemplateEngine {
    @Override
    protected void outputCustomFile(@NotNull Map<String, String> customFile, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        //数据库表映射实体名称
        String entityName = tableInfo.getEntityName();

        String otherPath = this.getPathInfo(OutputFile.other);
        //System.out.println(JsonUtils.toJSONString(tableInfo));

        customFile.forEach((key, value) -> {
            String fileName = String.format(otherPath + File.separator +key,entityName);
            this.outputFile(new File(fileName), objectMap, value, false);
        });
    }
}

3、数据库关键字处理类,使用的数据库有相关实现的可不写(官方提供mysql、oracle等常用数据库关键字处理类,此处用户扩展国产数据库)

package com.camp.gen.handler;

import com.baomidou.mybatisplus.generator.keywords.BaseKeyWordsHandler;
import org.jetbrains.annotations.NotNull;

import java.util.*;

/**
 * @Description dm关键字处理类
 * @Author HS
 * @Date 2022/12/5 11:07
 */
public class DmKeyWordsHandler extends BaseKeyWordsHandler {

    private static final List<String> KEY_WORDS = new ArrayList(Arrays.asList("ACCESSIBLE", "ACCOUNT", "ACTION", "ACTIVE", "ADD", "ADMIN", "AFTER", "AGAINST", "AGGREGATE", "ALGORITHM", "ALL", "ALTER", "ALWAYS", "ANALYSE", "ANALYZE", "AND", "ANY", "ARRAY", "AS", "ASC", "ASCII", "ASENSITIVE", "AT", "ATTRIBUTE", "AUTHENTICATION", "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", "AVG_ROW_LENGTH", "BACKUP", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", "BINLOG", "BIT", "BLOB", "BLOCK", "BOOL", "BOOLEAN", "BOTH", "BTREE", "BUCKETS", "BY", "BYTE", "CACHE", "CALL", "CASCADE", "CASCADED", "CASE", "CATALOG_NAME", "CHAIN", "CHALLENGE_RESPONSE", "CHANGE", "CHANGED", "CHANNEL", "CHAR", "CHARACTER", "CHARSET", "CHECK", "CHECKSUM", "CIPHER", "CLASS_ORIGIN", "CLIENT", "CLONE", "CLOSE", "COALESCE", "CODE", "COLLATE", "COLLATION", "COLUMN", "COLUMNS", "COLUMN_FORMAT", "COLUMN_NAME", "COMMENT", "COMMIT", "COMMITTED", "COMPACT", "COMPLETION", "COMPONENT", "COMPRESSED", "COMPRESSION", "CONCURRENT", "CONDITION", "CONNECTION", "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", "CONTEXT", "CONTINUE", "CONVERT", "CPU", "CREATE", "CROSS", "CUBE", "CUME_DIST", "CURRENT", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "DATA", "DATABASE", "DATABASES", "DATAFILE", "DATE", "DATETIME", "DAY", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DEALLOCATE", "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFAULT_AUTH", "DEFINER", "DEFINITION", "DELAYED", "DELAY_KEY_WRITE", "DELETE", "DENSE_RANK", "DESC", "DESCRIBE", "DESCRIPTION", "DES_KEY_FILE", "DETERMINISTIC", "DIAGNOSTICS", "DIRECTORY", "DISABLE", "DISCARD", "DISK", "DISTINCT", "DISTINCTROW", "DIV", "DO", "DOUBLE", "DROP", "DUAL", "DUMPFILE", "DUPLICATE", "DYNAMIC", "EACH", "ELSE", "ELSEIF", "EMPTY", "ENABLE", "ENCLOSED", "ENCRYPTION", "END", "ENDS", "ENFORCED", "ENGINE", "ENGINE_ATTRIBUTE", "ENGINES", "ENUM", "ERROR", "ERRORS", "ESCAPE", "ESCAPED", "EVENT", "EVENTS", "EVERY", "EXCEPT", "EXCHANGE", "EXCLUDE", "EXECUTE", "EXISTS", "EXIT", "EXPANSION", "EXPIRE", "EXPLAIN", "EXPORT", "EXTENDED", "EXTENT_SIZE", "FACTOR", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FAULTS", "FETCH", "FIELDS", "FILE", "FILE_BLOCK_SIZE", "FILTER", "FINISH", "FIRST", "FIRST_VALUE", "FIXED", "FLOAT", "FLOAT4", "FLOAT8", "FLUSH", "FOLLOWING", "FOLLOWS", "FOR", "FORCE", "FOREIGN", "FORMAT", "FOUND", "FROM", "FULL", "FULLTEXT", "FUNCTION", "GENERAL", "GENERATED", "GEOMCOLLECTION", "GEOMETRY", "GEOMETRYCOLLECTION", "GET", "GET_FORMAT", "GET_MASTER_PUBLIC_KEY", "GET_SOURCE_PUBLIC_KEY", "GLOBAL", "GRANT", "GRANTS", "GROUP", "GROUP_REPLICATION", "GROUPING", "GROUPS", "GTID_ONLY", "HANDLER", "HASH", "HAVING", "HELP", "HIGH_PRIORITY", "HISTOGRAM", "HISTORY", "HOST", "HOSTS", "HOUR", "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", "IF", "IGNORE", "IGNORE_SERVER_IDS", "IMPORT", "IN", "INACTIVE", "INDEX", "INDEXES", "INFILE", "INITIAL", "INITIAL_SIZE", "INITIATE", "INNER", "INOUT", "INSENSITIVE", "INSERT", "INSERT_METHOD", "INSTALL", "INSTANCE", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", "INTEGER", "INTERVAL", "INTO", "INVISIBLE", "INVOKER", "IO", "IO_AFTER_GTIDS", "IO_BEFORE_GTIDS", "IO_THREAD", "IPC", "IS", "ISOLATION", "ISSUER", "ITERATE", "JOIN", "JSON", "JSON_TABLE", "JSON_VALUE", "KEY", "KEYS", "KEY_BLOCK_SIZE", "KEYRING", "KILL", "LAG", "LANGUAGE", "LAST", "LAST_VALUE", "LATERAL", "LEAD", "LEADING", "LEAVE", "LEAVES", "LEFT", "LESS", "LEVEL", "LIKE", "LIMIT", "LINEAR", "LINES", "LINESTRING", "LIST", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCK", "LOCKED", "LOCKS", "LOGFILE", "LOGS", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "MASTER", "MASTER_AUTO_POSITION", "MASTER_BIND", "MASTER_COMPRESSION_ALGORITHMS", "MASTER_CONNECT_RETRY", "MASTER_DELAY", "MASTER_HEARTBEAT_PERIOD", "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", "MASTER_PASSWORD", "MASTER_PORT", "MASTER_PUBLIC_KEY_PATH", "MASTER_RETRY_COUNT", "MASTER_SERVER_ID", "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_CRL", "MASTER_SSL_CRLPATH", "MASTER_SSL_KEY", "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_TLS_CIPHERSUITES", "MASTER_TLS_VERSION", "MASTER_USER", "MASTER_ZSTD_COMPRESSION_LEVEL", "MATCH", "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", "MAX_ROWS", "MAX_SIZE", "MAX_STATEMENT_TIME", "MAX_UPDATES_PER_HOUR", "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MEMBER", "MEMORY", "MERGE", "MESSAGE_TEXT", "MICROSECOND", "MIDDLEINT", "MIGRATE", "MINUTE", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", "MOD", "MODE", "MODIFIES", "MODIFY", "MONTH", "MULTILINESTRING", "MULTIPOINT", "MULTIPOLYGON", "MUTEX", "MYSQL_ERRNO", "NAME", "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NDB", "NDBCLUSTER", "NESTED", "NETWORK_NAMESPACE", "NEVER", "NEW", "NEXT", "NO", "NODEGROUP", "NONBLOCKING", "NONE", "NOT", "NOWAIT", "NO_WAIT", "NO_WRITE_TO_BINLOG", "NTH_VALUE", "NTILE", "NULL", "NULLS", "NUMBER", "NUMERIC", "NVARCHAR", "OF", "OFF", "OFFSET", "OJ", "OLD", "OLD_PASSWORD", "ON", "ONE", "ONLY", "OPEN", "OPTIMIZE", "OPTIMIZER_COSTS", "OPTION", "OPTIONAL", "OPTIONALLY", "OPTIONS", "OR", "ORDER", "ORDINALITY", "ORGANIZATION", "OTHERS", "OUT", "OUTER", "OUTFILE", "OVER", "OWNER", "PACK_KEYS", "PAGE", "PARSER", "PARSE_GCOL_EXPR", "PARTIAL", "PARTITION", "PARTITIONING", "PARTITIONS", "PASSWORD", "PASSWORD_LOCK_TIME", "PATH", "PERCENT_RANK", "PERSIST", "PERSIST_ONLY", "PHASE", "PLUGIN", "PLUGINS", "PLUGIN_DIR", "POINT", "POLYGON", "PORT", "PRECEDES", "PRECEDING", "PRECISION", "PREPARE", "PRESERVE", "PREV", "PRIMARY", "PRIVILEGE_CHECKS_USER", "PRIVILEGES", "PROCEDURE", "PROCESS", "PROCESSLIST", "PROFILE", "PROFILES", "PROXY", "PURGE", "QUARTER", "QUERY", "QUICK", "RANDOM", "RANGE", "RANK", "READ", "READS", "READ_ONLY", "READ_WRITE", "REAL", "REBUILD", "RECOVER", "RECURSIVE", "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", "REFERENCE", "REFERENCES", "REGEXP", "REGISTRATION", "RELAY", "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", "RELAY_THREAD", "RELEASE", "RELOAD", "REMOVE", "RENAME", "REORGANIZE", "REPAIR", "REPEAT", "REPEATABLE", "REPLACE", "REPLICA", "REPLICAS", "REPLICATE_DO_DB", "REPLICATE_DO_TABLE", "REPLICATE_IGNORE_DB", "REPLICATE_IGNORE_TABLE", "REPLICATE_REWRITE_DB", "REPLICATE_WILD_DO_TABLE", "REPLICATE_WILD_IGNORE_TABLE", "REPLICATION", "REQUIRE", "REQUIRE_ROW_FORMAT", "RESET", "RESIGNAL", "RESOURCE", "RESPECT", "RESTART", "RESTORE", "RESTRICT", "RESUME", "RETAIN", "RETURN", "RETURNED_SQLSTATE", "RETURNING", "RETURNS", "REUSE", "REVERSE", "REVOKE", "RIGHT", "RLIKE", "ROLE", "ROLLBACK", "ROLLUP", "ROTATE", "ROUTINE", "ROW", "ROWS", "ROW_COUNT", "ROW_FORMAT", "ROW_NUMBER", "RTREE", "SAVEPOINT", "SCHEDULE", "SCHEMA", "SCHEMAS", "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", "SECONDARY", "SECONDARY_ENGINE", "SECONDARY_ENGINE_ATTRIBUTE", "SECONDARY_LOAD", "SECONDARY_UNLOAD", "SECURITY", "SELECT", "SENSITIVE", "SEPARATOR", "SERIAL", "SERIALIZABLE", "SERVER", "SESSION", "SET", "SHARE", "SHOW", "SHUTDOWN", "SIGNAL", "SIGNED", "SIMPLE", "SKIP", "SLAVE", "SLOW", "SMALLINT", "SNAPSHOT", "SOCKET", "SOME", "SONAME", "SOUNDS", "SOURCE", "SOURCE_AUTO_POSITION", "SOURCE_BIND", "SOURCE_COMPRESSION_ALGORITHMS", "SOURCE_CONNECT_RETRY", "SOURCE_DELAY", "SOURCE_HEARTBEAT_PERIOD", "SOURCE_HOST", "SOURCE_LOG_FILE", "SOURCE_LOG_POS", "SOURCE_PASSWORD", "SOURCE_PORT", "SOURCE_PUBLIC_KEY_PATH", "SOURCE_RETRY_COUNT", "SOURCE_SSL", "SOURCE_SSL_CA", "SOURCE_SSL_CAPATH", "SOURCE_SSL_CERT", "SOURCE_SSL_CIPHER", "SOURCE_SSL_CRL", "SOURCE_SSL_CRLPATH", "SOURCE_SSL_KEY", "SOURCE_SSL_VERIFY_SERVER_CERT", "SOURCE_TLS_CIPHERSUITES", "SOURCE_TLS_VERSION", "SOURCE_USER", "SOURCE_ZSTD_COMPRESSION_LEVEL", "SPATIAL", "SPECIFIC", "SQL", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "SRID", "SQL_AFTER_GTIDS", "SQL_AFTER_MTS_GAPS", "SQL_BEFORE_GTIDS", "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", "SQL_TSI_YEAR", "SSL", "STACKED", "START", "STARTING", "STARTS", "STATS_AUTO_RECALC", "STATS_PERSISTENT", "STATS_SAMPLE_PAGES", "STATUS", "STOP", "STORAGE", "STORED", "STRAIGHT_JOIN", "STREAM", "STRING", "SUBCLASS_ORIGIN", "SUBJECT", "SUBPARTITION", "SUBPARTITIONS", "SUPER", "SUSPEND", "SWAPS", "SWITCHES", "SYSTEM", "TABLE", "TABLES", "TABLESPACE", "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", "TEMPTABLE", "TERMINATED", "TEXT", "THAN", "THEN", "THREAD_PRIORITY", "TIES", "TIME", "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", "TINYBLOB", "TINYINT", "TINYTEXT", "TLS", "TO", "TRAILING", "TRANSACTION", "TRIGGER", "TRIGGERS", "TRUE", "TRUNCATE", "TYPE", "TYPES", "UNBOUNDED", "UNCOMMITTED", "UNDEFINED", "UNDO", "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", "UNINSTALL", "UNION", "UNIQUE", "UNKNOWN", "UNLOCK", "UNREGISTER", "UNSIGNED", "UNTIL", "UPDATE", "UPGRADE", "USAGE", "USE", "USER", "USER_RESOURCES", "USE_FRM", "USING", "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", "VALIDATION", "VALUE", "VALUES", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARIABLES", "VARYING", "VCPU", "VIEW", "VIRTUAL", "VISIBLE", "WAIT", "WARNINGS", "WEEK", "WEIGHT_STRING", "WHEN", "WHERE", "WHILE", "WINDOW", "WITH", "WITHOUT", "WORK", "WRAPPER", "WRITE", "X509", "XA", "XID", "XML", "XOR", "YEAR", "YEAR_MONTH", "ZEROFILL", "ZONE"));

    public DmKeyWordsHandler(){
        super(new HashSet(KEY_WORDS));
    }

    @Override
    public @NotNull String formatStyle() {
        return "%s";
    }

}

4、启动类

package com.camp.gen;

import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.camp.gen.config.GeneratorConfig;
import com.camp.gen.handler.MyFreeMarkerTemplateEngine;
import java.util.*;


/**
 * @Description 代码生成器
 * @Author HS
 * @Date 2022/11/27 16:23
 */
public class MyGenerator {

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator(GeneratorConfig.initDataSourceConfig());
        //自定义参数,全局适用
        HashMap<String, Object> parameterMap = new HashMap<>(4);
        parameterMap.put("workflow", true);
        parameterMap.put("permission", true);
        //需要生成的表名
        List<String> tableLists = Arrays.asList("SW_FORM");
        //全局配置
        mpg.global(GeneratorConfig.initGlobalConfig())
                //包配置
                .packageInfo(GeneratorConfig.initPackageConfig())
                //模板配置
                .template(GeneratorConfig.initTemplateConfig())
                //策略配置
                .strategy(GeneratorConfig.initStrategyConfig(tableLists))
                //自定义配置
                .injection(GeneratorConfig.initInjectionConfig(parameterMap));
        //生成
        mpg.execute(new MyFreeMarkerTemplateEngine());
    }

}

5、模板

目录结构

在这里插入图片描述

5.1 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>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
import ${package.Service}.${table.serviceName};
import com.css.cssbase.base.annotation.OperateLog;
import com.css.cssbase.base.model.ResponseData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.util.CollectionUtils;
<#if permission>
import org.apache.shiro.authz.annotation.RequiresPermissions;
</#if>



/**
 * <p>
 * ${table.comment!}前端控制器
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName!?length gt 0>/${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>

    <#if table.serviceName??>
    @Autowired
    private ${table.serviceName} ${table.serviceName?uncap_first};
    </#if>


 <#---  controller方法  start  --->
    @PostMapping
    <#if permission>
    @RequiresPermissions("${table.entityPath}:add")
    </#if>
    @OperateLog("保存${table.comment!}")
    public ResponseData add${entity}(@RequestBody ${entity}DTO ${entity?uncap_first}DTO){
       return ResponseData.builder().data("data",${table.serviceName?uncap_first}.add${entity}(${entity?uncap_first}DTO)).build();
    }

    @GetMapping("/{id}")
    <#if permission>
    @RequiresPermissions("${table.entityPath}:get")
    </#if>
    @OperateLog("查看${table.comment!}")
    public ResponseData get${entity}(@PathVariable Long id){
        return ResponseData.builder().data("data",${table.serviceName?uncap_first}.get${entity}(id)).build();
    }

    @PutMapping
    <#if permission>
    @RequiresPermissions("${table.entityPath}:update")
    </#if>
    @OperateLog("更新${table.comment!}")
    public ResponseData upd${entity}(@RequestBody ${entity}DTO ${entity?uncap_first}DTO){
        return ResponseData.builder().data("data",${table.serviceName?uncap_first}.upd${entity}(${entity?uncap_first}DTO)).build();
    }

    @DeleteMapping
    <#if permission>
    @RequiresPermissions("${table.entityPath}:delete")
    </#if>
    @OperateLog("删除${table.comment!}")
    public ResponseData del${entity}(@RequestParam List<Long> ids){
        if(!CollectionUtils.isEmpty(ids)){
            ${table.serviceName?uncap_first}.del${entity}(ids);
        }
        return ResponseData.builder().build();
    }

<#---  controller方法  end  --->

}
</#if>

5.2entity.java.ftl

package ${package.Entity};

<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if entityLombokModel>
import lombok.Data;
    <#if chainModel>
import lombok.experimental.Accessors;
    </#if>
</#if>
<#--- 流程相关 -->
<#if workflow>
import com.css.cssbase.moudles.flowbase.model.FlowBase;
</#if>

/**
 * <p>
 * ${table.comment!}
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if entityLombokModel>
@Data
</#if>
<#if table.convert>
@TableName("${table.name}")
</#if>
<#if superEntityClass??>
public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> implements Serializable {
<#elseif activeRecord>
public class ${entity} extends Model<${entity}> implements Serializable {
<#else>
public class ${entity} <#if workflow>extends FlowBase </#if>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>

    <#if field.comment!?length gt 0>
    /**
     * ${field.comment}
     */
    </#if>
    <#if field.keyFlag>
        <#-- 主键 -->
        <#if field.keyIdentityFlag>
    @TableId(value = "${field.columnName}", type = IdType.AUTO)
        <#elseif idType??>
    @TableId(value = "${field.columnName}", type = IdType.${idType})
        <#elseif field.convert>
    @TableId("${field.columnName}")
        </#if>
        <#-- 普通字段 -->
    <#elseif field.fill??>
    <#-- -----   存在字段填充设置   ----->
        <#if field.convert>
    @TableField(value = "${field.columnName}", fill = FieldFill.${field.fill})
        <#else>
    @TableField(fill = FieldFill.${field.fill})
        </#if>
    <#elseif field.convert>
    @TableField("${field.columnName}")
    </#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>
}

5.3 service.java.ftl

package ${package.Service};

import ${package.Entity}.${entity};
import ${superServiceClassPackage};

/**
 * <p>
 * ${table.comment!}服务类
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if kotlin>
interface ${table.serviceName} : ${superServiceClass}<${entity}>
<#else>
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {

   /**
    * 保存${table.comment!}
    * @param ${entity}DTO
    */
   ${entity}VO add${entity}(${entity}DTO ${entity?uncap_first}DTO);

   /**
    * 查看${table.comment!}
    * @param id
    */
   ${entity}VO get${entity}(Long id);

   /**
    * 更新${table.comment!}
    * @param ${entity}DTO
    */
   ${entity}VO upd${entity}(${entity}DTO ${entity?uncap_first}DTO);

   /**
    * 删除${table.comment!}
    * @param ids
    */
   void del${entity}(List<Long> ids);

}
</#if>

5.4 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;

/**
 * <p>
 * ${table.comment!}服务实现类
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@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} {

   @Autowired
   private ${table.mapperName} ${table.mapperName?uncap_first}

   /**
    * 保存${table.comment!}
    * @param ${entity}DTO
    */
   @Override
   public ${entity}VO add${entity}(${entity}DTO ${entity?uncap_first}DTO){
      ${entity} ${entity?uncap_first} = new ${entity}();
      BeanUtils.copyProperties(${entity?uncap_first}DTO, ${entity?uncap_first});
      //属性初始化
      //插入操作
      //返回VO
      return new ${entity}VO();
   }

   /**
   * 查看${table.comment!}
   * @param id
   */
   @Override
   public ${entity}VO get${entity}(Long id){

   }

   /**
   * 更新${table.comment!}
   * @param ${entity}DTO
   */
   @Override
   public ${entity}VO upd${entity}(${entity}DTO ${entity?uncap_first}DTO){

   }

   /**
   * 删除${table.comment!}
   * @param ids
   */
   @Override
   public void del${entity}(List<Long> ids){

   }

}
</#if>

5.5 mapper.java.ftl

package ${package.Mapper};

import ${package.Entity}.${entity};
import ${superMapperClassPackage};
import org.springframework.stereotype.Repository;
<#if enableCache>
import org.mybatis.caches.memcached.MemcachedCache;
import org.apache.ibatis.annotations.CacheNamespace;
</#if>
/**
 * <p>
 * ${table.comment!}Mapper接口
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Repository
<#if enableCache>
@CacheNamespace(implementation = MemcachedCache.class)
</#if>
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}>
<#else>
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {

}
</#if>

5.6 mapper.xml.ftl

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${package.Mapper}.${table.mapperName}">
<#if enableCache>
    <!-- 开启二级缓存 -->
    <cache namespace="${package.Mapper}.${table.mapperName}"/>

</#if>
<#if baseResultMap>
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
<#list table.fields as field>
<#if field.keyFlag><#--生成主键排在第一位-->
        <id column="${field.name}" property="${field.propertyName}" />
</#if>
</#list>
<#list table.commonFields as field><#--生成公共字段 -->
        <result column="${field.name}" property="${field.propertyName}" />
</#list>
<#list table.fields as field>
<#if !field.keyFlag><#--生成普通字段 -->
        <result column="${field.name}" property="${field.propertyName}" />
</#if>
</#list>
    </resultMap>

</#if>
<#if baseColumnList>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
<#list table.commonFields as field>
        ${field.columnName},
</#list>
        ${table.fieldNames}
    </sql>

</#if>
</mapper>

5.7 dto.java.ftl

package ${package.Other};

<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if entityLombokModel>
import lombok.Data;
    <#if chainModel>
import lombok.experimental.Accessors;
    </#if>
</#if>

/**
 * <p>
 * ${table.comment!}
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if entityLombokModel>
@Data
</#if>
<#if superEntityClass??>
public class ${entity}DTO extends ${superEntityClass}<#if activeRecord><${entity}></#if> implements Serializable {
<#elseif activeRecord>
public class ${entity}DTO extends Model<${entity}> implements Serializable {
<#else>
public class ${entity}DTO implements Serializable {
</#if>

<#if entitySerialVersionUID>
    private static final long serialVersionUID = 1L;
</#if>

<#-- ----------  BEGIN 字段循环遍历  ---------->
<#list table.fields as field>
    <#if field.comment!?length gt 0>

        /**
        * ${field.comment}
        */
    </#if>
    private ${field.propertyType} ${field.propertyName};
</#list>
<#------------  END 字段循环遍历  ---------->
}

5.8 vo.java.ftl

package ${package.Other};

<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if entityLombokModel>
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
    <#if chainModel>
import lombok.experimental.Accessors;
    </#if>
</#if>

/**
 * <p>
 * ${table.comment!}
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if entityLombokModel>
@Data
@NoArgsConstructor
@AllArgsConstructor
</#if>
<#if superEntityClass??>
public class ${entity}VO extends ${superEntityClass}<#if activeRecord><${entity}></#if> implements Serializable {
<#elseif activeRecord>
public class ${entity}VO extends Model<${entity}> implements Serializable {
<#else>
public class ${entity}VO implements Serializable {
</#if>

<#if entitySerialVersionUID>
    private static final long serialVersionUID = 1L;
</#if>

<#-- ----------  BEGIN 字段循环遍历  ---------->
<#list table.fields as field>
    <#if field.comment!?length gt 0>

    /**
     * ${field.comment}
     */
    </#if>
    private ${field.propertyType} ${field.propertyName};
</#list>
<#------------  END 字段循环遍历  ---------->
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mybatis-Plus代码生成器详解及完整代码实现 的相关文章

随机推荐

  • 51单片机定时器初值计算问题

    最近在看51单片机的定时器与中断 xff0c 作为51单片机比较重点的内容 xff0c 很多人也花费了很长时间在这上面 xff0c 有些问题网上的资料方法各不相同 xff0c 也看得云里雾里 xff0c 比如定时器的初值计算问题 xff0c
  • Go 在 Windows 上用户图形界面 GUI 解决方案 Go-WinGUI 国产(使用cef 内核)

    Go 在 Windows 上用户图形界面 GUI 解决方案 Go WinGUI 国产 xff08 使用cef 内核 xff09 参考文章 xff1a xff08 1 xff09 Go 在 Windows 上用户图形界面 GUI 解决方案 G
  • MXNet 中文文档

    MXNet 中文文档 MXNet 中文文档 MXNet设计和实现简介编程接口 Symbol 声明式的符号表达式NDArray命令式的张量计算KVStore 多设备间的数据交互读入数据模块训练模块 系统实现 计算图 计算图优化内存申请 引擎数
  • mybatis-plus整合springboot自动生成文件

    mybatis plus整合springboot自动生成dao层 导入依赖 span class token tag span class token tag span class token punctuation lt span dep
  • c++实现——TT的神秘礼物

    题意 TT 是一位重度爱猫人士 xff0c 每日沉溺于 B 站上的猫咪频道 有一天 xff0c TT 的好友 ZJM 决定交给 TT 一个难题 xff0c 如果 TT 能够解决这个难题 xff0c ZJM 就会买一只可爱猫咪送给 TT 任务
  • 简单差分方法的应用

    题意 Thanks to everyone s help last week TT finally got a cute cat But what TT didn t expect is that this is a magic cat O
  • 咕咕东的奇妙序列 --找规律

    题目描述 咕咕东 正在上可怕的复变函数 xff0c 但对于稳拿A Plus的 咕咕东 来说 xff0c 她早已不再听课 xff0c 此时她在睡梦中突然想到了一个奇怪的无限序列 xff1a 112123123412345 这个序列由连续正整数
  • HRZ学英语

    思路 xff1a 这道题的要求很简单 第一个出现的26字母序列 xff0c 其字典序改成最小的即可 解释一下 1 给定序列 gt 61 26个 从左向右每26个字母为一组 xff0c 如果这组的 变成字母后满足26字母即可 xff0c 搜索
  • ZJM 与纸条

    ZJM 的女朋友是一个书法家 xff0c 喜欢写一些好看的英文书法 有一天 ZJM 拿到了她写的纸条 xff0c 纸条上的字暗示了 ZJM 的女朋友 想给 ZJM 送生日礼物 ZJM 想知道自己收到的礼物是不是就是她送的 xff0c 于是想
  • TT数鸭子

    题目描述 这一天 xff0c TT因为疫情在家憋得难受 xff0c 在云吸猫一小时后 xff0c TT决定去附近自家的山头游玩 TT来到一个小湖边 xff0c 看到了许多在湖边嬉戏的鸭子 xff0c TT顿生羡慕 此时他发现每一只鸭子都不
  • 中级软件设计师备考---软件工程2

    目录 软件测试分类和要求 测试用例设计 测试阶段 McCabe复杂度 软件维护 软件过程改进 CMMI CMM英文版 CMM中文版 CMMI 软件测试分类和要求 分类 灰盒测试 多用于集成测试阶段 不仅关注输出 输入的正确性 同时也关注程序
  • 数据库复习——第三章

    3 1 SQL概述 SQL支持关系数据库三级模式结构 SQL语言的功能 SQL功能动词数据查询SELECT数据定义CREATE DROP ALTER数据操纵INSERT UPDATE DELETE数据控制GRANT REVOKE Drop
  • 【ubuntu】ubuntu 安装软件的时候,执行add-apt-repository失败,update-ca-certificates

    在使用 ubuntu18 安装GCC 10 0的时候 xff0c 需要先执行add apt repository xff0c 结果报错了ERROR ubuntu toolchain r user or team does not exist
  • SQL语句练习(Student,Course,SC表)

    Create table Student 主码 xff0c 姓名 xff08 唯一 xff09 xff0c 性别 xff08 男 女 xff09 xff0c 年龄 xff08 18 25 xff09 span class token key
  • b站视频排行榜爬取

    bilibili排行榜爬取 众所周知 xff0c B站学习软件 哈哈哈哈 xff0c 今天我们就爬取B站的排行榜 废话不多说了 xff0c 直接开始了 分析 xff1a 我们看图一可以发现每个是视频的info都在li的标签里 xff0c 我
  • STM32F103笔记(二)——GPIO原理

    GPIO的工作原理与两个实验实例 一 STM32F103 GPIO说明1 stm32 GPIO引脚的主要功能2 GPIO相关配置寄存器的简介3 STM32F103 GPIO的8种工作方式4种输入模式4种输出模式 二 点亮LED实例 xff0
  • WSL2使用xrdp实现Liunx图形化桌面

    由于使用wsl跑代码时需要 pyplot 把数据可视化一下 xff0c 但是发现 import matplotlib pyplot as plt other code plt show 在 plt show 之后并没有图像被画出来 xff0
  • CentOS 8 安装图形界面GUI

    在安装CentOS8的桌面之前 xff0c 需要确保两点已做 xff1a xff08 1 xff09 在安装的时候 xff0c 勾选了安装Centos的GUI xff1b xff08 2 xff09 确保网络是联通的 xff0c ping一
  • 基于深度学习的目标跟踪的方法与实现 1、实现基于深度学习的目标跟踪方法 2、yolo v5目标检测模型预训练 3、行人检测模型

    摘要 目标检测支持许多视觉任务 如实例分割 姿态估计 跟踪和动作识别 这些计算机视觉任务在监控 自动驾驶和视觉答疑等领域有着广泛的应用 随着这种广泛的实际应用 目标检测自然成为一个活跃的研究领域 目标检测是一种计算机视觉技术 它允许我们识别
  • Mybatis-Plus代码生成器详解及完整代码实现

    意义 1 日常开发过程中 xff0c 常规后端开发接收到需求后 xff0c 进行数据库E R设计后创建对应数据表 无论基于speingmvc还是strtus xff08 同样是一个mvc框架 xff09 xff0c 都需要进行一些固定模板的