Toning преди 2 години
родител
ревизия
8757ac5b85
променени са 47 файла, в които са добавени 4371 реда и са изтрити 0 реда
  1. 2 0
      .gitignore
  2. 67 0
      pom.xml
  3. 269 0
      src/main/java/com/zkthink/ceres/generator/CodeGenerator.java
  4. 330 0
      src/main/java/com/zkthink/ceres/generator/ProjectGenerator.java
  5. 253 0
      src/main/java/com/zkthink/ceres/generator/config/CodeGeneratorConfig.java
  6. 235 0
      src/main/java/com/zkthink/ceres/generator/config/FileCreateConfig.java
  7. 192 0
      src/main/java/com/zkthink/ceres/generator/ext/FileOutConfigExt.java
  8. 426 0
      src/main/java/com/zkthink/ceres/generator/ext/FreemarkerTemplateEngineExt.java
  9. 16 0
      src/main/java/com/zkthink/ceres/generator/ext/MySqlQueryExt.java
  10. 32 0
      src/main/java/com/zkthink/ceres/generator/ext/OracleQueryExt.java
  11. 140 0
      src/main/java/com/zkthink/ceres/generator/model/GenTableColumn.java
  12. 76 0
      src/main/java/com/zkthink/ceres/generator/type/EntityFiledType.java
  13. 53 0
      src/main/java/com/zkthink/ceres/generator/type/EntityType.java
  14. 43 0
      src/main/java/com/zkthink/ceres/generator/type/GenerateType.java
  15. 26 0
      src/main/java/com/zkthink/ceres/generator/type/HtmlType.java
  16. 42 0
      src/main/java/com/zkthink/ceres/generator/type/SuperClass.java
  17. 55 0
      src/main/resources/init/java/Application.java.ftl
  18. 123 0
      src/main/resources/init/java/DatabaseAutoConfiguration.java.ftl
  19. 20 0
      src/main/resources/init/java/ExceptionConfiguration.java.ftl
  20. 43 0
      src/main/resources/init/java/MybatisAutoConfiguration.java.ftl
  21. 30 0
      src/main/resources/init/java/WebConfiguration.java.ftl
  22. 46 0
      src/main/resources/init/pom/api.java.ftl
  23. 61 0
      src/main/resources/init/pom/biz.java.ftl
  24. 42 0
      src/main/resources/init/pom/controller.java.ftl
  25. 41 0
      src/main/resources/init/pom/entity.java.ftl
  26. 46 0
      src/main/resources/init/pom/pom.java.ftl
  27. 127 0
      src/main/resources/init/pom/server.java.ftl
  28. 12 0
      src/main/resources/init/resources/application.java.ftl
  29. 10 0
      src/main/resources/init/resources/banner.java.ftl
  30. 50 0
      src/main/resources/init/resources/bootstrap.java.ftl
  31. 26 0
      src/main/resources/init/resources/logback-spring.java.ftl
  32. 21 0
      src/main/resources/init/resources/spy.java.ftl
  33. 16 0
      src/main/resources/logback.xml
  34. 32 0
      src/main/resources/templates/constant.java.ftl
  35. 81 0
      src/main/resources/templates/controller.java.ftl
  36. 198 0
      src/main/resources/templates/controller_bak.java.ftl
  37. 55 0
      src/main/resources/templates/dto.java.ftl
  38. 240 0
      src/main/resources/templates/entity.java.ftl
  39. 83 0
      src/main/resources/templates/enum.java.ftl
  40. 20 0
      src/main/resources/templates/mapper.java.ftl
  41. 98 0
      src/main/resources/templates/mapper.xml.ftl
  42. 148 0
      src/main/resources/templates/pageDto.java.ftl
  43. 147 0
      src/main/resources/templates/saveDto.java.ftl
  44. 25 0
      src/main/resources/templates/service.java.ftl
  45. 58 0
      src/main/resources/templates/serviceImpl.java.ftl
  46. 162 0
      src/main/resources/templates/updateDto.java.ftl
  47. 53 0
      src/test/java/CommonGenerator.java

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+.idea
+/target

+ 67 - 0
pom.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.2.6.RELEASE</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.zkthink</groupId>
+    <artifactId>ceres-generator</artifactId>
+    <version>1.0</version>
+
+    <properties>
+        <mybatisplus.version>3.3.1</mybatisplus.version>
+        <lombok.version>1.18.12</lombok.version>
+        <mysql.version>8.0.19</mysql.version>
+        <commons.lang3.version>3.9</commons.lang3.version>
+        <hutool.version>5.3.1</hutool.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>${mybatisplus.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>${lombok.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+
+
+        <!--  在这个项目运行test类,生成代码,需要将这个注释打开 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>6.0.6</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 269 - 0
src/main/java/com/zkthink/ceres/generator/CodeGenerator.java

@@ -0,0 +1,269 @@
+package com.zkthink.ceres.generator;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.querys.*;
+import com.baomidou.mybatisplus.generator.config.rules.DateType;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.zkthink.ceres.generator.config.CodeGeneratorConfig;
+import com.zkthink.ceres.generator.ext.FileOutConfigExt;
+import com.zkthink.ceres.generator.ext.FreemarkerTemplateEngineExt;
+import com.zkthink.ceres.generator.ext.MySqlQueryExt;
+import com.zkthink.ceres.generator.ext.OracleQueryExt;
+import com.zkthink.ceres.generator.type.GenerateType;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 代码生成
+ *
+ * @author ceres
+ * @date 2019/05/25
+ */
+public class CodeGenerator {
+
+    public static final String QUERY_PATH = "Query";
+    //    public static final String API_PATH = "Api";
+    public static final String ENUM_PATH = "Enum";
+    public static final String CONSTANT_PATH = "Constant";
+    public static final String SAVE_DTO_PATH = "SaveDTO";
+    public static final String UPDATE_DTO_PATH = "UpdateDTO";
+    public static final String PAGE_DTO_PATH = "PageDTO";
+
+    public static final String SRC_MAIN_JAVA = "src" + File.separator + "main" + File.separator + "java";
+    public static final String SRC_MAIN_RESOURCE = "src" + File.separator + "main" + File.separator + "resources";
+
+    public static void run(final CodeGeneratorConfig config) {
+        // 代码生成器
+        AutoGenerator mpg = new AutoGenerator();
+        //项目的根路径
+        String projectRootPath = config.getProjectRootPath();
+
+        //全局配置
+        GlobalConfig gc = globalConfig(config, projectRootPath);
+        mpg.setGlobalConfig(gc);
+
+        // 数据源配置
+        DataSourceConfig dsc = dataSourceConfig(config);
+        mpg.setDataSource(dsc);
+
+        PackageConfig pc = packageConfig(config);
+        mpg.setPackageInfo(pc);
+
+        // 配置模板
+        TemplateConfig templateConfig = new TemplateConfig();
+        // 不生成下列文件
+        templateConfig.setController(null);
+        templateConfig.setServiceImpl(null);
+        templateConfig.setService(null);
+        templateConfig.setMapper(null);
+        templateConfig.setXml(null);
+        templateConfig.setEntity(null);
+        mpg.setTemplate(templateConfig);
+
+        // 自定义配置
+        InjectionConfig cfg = injectionConfig(config, projectRootPath, pc);
+        mpg.setCfg(cfg);
+
+        // 策略配置
+        StrategyConfig strategy = strategyConfig(config);
+        mpg.setStrategy(strategy);
+        mpg.setTemplateEngine(new FreemarkerTemplateEngineExt(config));
+//        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
+
+        mpg.execute();
+    }
+
+    /**
+     * 全局配置
+     *
+     * @param config      参数
+     * @param projectPath 项目根路径
+     * @return
+     */
+    private static GlobalConfig globalConfig(final CodeGeneratorConfig config, String projectPath) {
+        GlobalConfig gc = new GlobalConfig();
+        gc.setOutputDir(String.format("%s/%s", projectPath, SRC_MAIN_JAVA));
+        gc.setAuthor(config.getAuthor());
+        gc.setOpen(false);
+        gc.setServiceName("%sService");
+        gc.setFileOverride(true);
+        gc.setBaseResultMap(true);
+        gc.setBaseColumnList(true);
+        gc.setDateType(DateType.TIME_PACK);
+        gc.setIdType(IdType.INPUT);
+        // 实体属性 Swagger2 注解
+        gc.setSwagger2(true);
+        return gc;
+    }
+
+    /**
+     * 数据库设置
+     *
+     * @param config
+     * @return
+     */
+    private static DataSourceConfig dataSourceConfig(CodeGeneratorConfig config) {
+        DataSourceConfig dsc = new DataSourceConfig();
+        dsc.setUrl(config.getUrl());
+        dsc.setDriverName(config.getDriverName());
+        dsc.setUsername(config.getUsername());
+        dsc.setPassword(config.getPassword());
+        if (dsc.getDbType() == DbType.MYSQL) {
+            dsc.setDbQuery(new MySqlQueryExt());
+        }
+        // oracle 没完全测试
+        else if (dsc.getDbType() == DbType.ORACLE) {
+            dsc.setDbQuery(new OracleQueryExt());
+        }
+        // 以下的都没测试过
+        else if (dsc.getDbType() == DbType.DB2) {
+            dsc.setDbQuery(new DB2Query());
+        } else if (dsc.getDbType() == DbType.DM) {
+            dsc.setDbQuery(new DMQuery());
+        } else if (dsc.getDbType() == DbType.H2) {
+            dsc.setDbQuery(new H2Query());
+        } else if (dsc.getDbType() == DbType.MARIADB) {
+            dsc.setDbQuery(new MariadbQuery());
+        } else if (dsc.getDbType() == DbType.POSTGRE_SQL) {
+            dsc.setDbQuery(new PostgreSqlQuery());
+        } else if (dsc.getDbType() == DbType.SQLITE) {
+            dsc.setDbQuery(new SqliteQuery());
+        } else if (dsc.getDbType() == DbType.SQL_SERVER) {
+            dsc.setDbQuery(new SqlServerQuery());
+        }
+        return dsc;
+    }
+
+
+    private static PackageConfig packageConfig(final CodeGeneratorConfig config) {
+        PackageConfig pc = new PackageConfig();
+//        pc.setModuleName(config.getChildPackageName());
+        pc.setParent(config.getPackageBase());
+        pc.setMapper("dao");
+        if (StringUtils.isNotEmpty(config.getChildPackageName())) {
+            pc.setMapper(config.getCurrentModule() + StringPool.DOT + pc.getMapper() + StringPool.DOT + config.getChildPackageName());
+            pc.setEntity("commons.domain" + StringPool.DOT + config.getChildPackageName());
+            pc.setService(config.getCurrentModule() + StringPool.DOT + pc.getService() + StringPool.DOT + config.getChildPackageName());
+            pc.setServiceImpl(pc.getService() + StringPool.DOT + "impl");
+            pc.setController(config.getCurrentModule() + StringPool.DOT + pc.getController() + StringPool.DOT + config.getChildPackageName());
+        }
+//        pc.setPathInfo(pathInfo(config));
+        return pc;
+    }
+
+    private static StrategyConfig strategyConfig(CodeGeneratorConfig pc) {
+        StrategyConfig strategy = new StrategyConfig();
+        strategy.setNaming(NamingStrategy.underline_to_camel);
+        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+        strategy.setEntityTableFieldAnnotationEnable(true);
+        strategy.setEntityLombokModel(true);
+        strategy.setEntityBuilderModel(false);
+        strategy.setInclude(pc.getTableInclude());
+        strategy.setExclude(pc.getTableExclude());
+        strategy.setTablePrefix(pc.getTablePrefix());
+        strategy.setFieldPrefix(pc.getFieldPrefix());
+        strategy.setEntityColumnConstant(GenerateType.IGNORE.neq(pc.getFileCreateConfig().getGenerateConstant()));
+        strategy.setRestControllerStyle(true);
+        strategy.setSuperEntityClass(pc.getSuperEntity().getVal());
+        strategy.setSuperServiceClass(pc.getSuperServiceClass());
+        strategy.setSuperServiceImplClass(pc.getSuperServiceImplClass());
+        strategy.setSuperMapperClass(pc.getSuperMapperClass());
+        //strategy.setSuperControllerClass(pc.getSuperControllerClass());
+
+        strategy.setSuperEntityColumns(pc.getSuperEntity().getColumns());
+        return strategy;
+    }
+
+    /**
+     * InjectionConfig   自定义配置   这里可以进行包路径的配置,自定义的代码生成器的接入配置。这里定义了xmlmapper 及query两个文件的自动生成配置
+     */
+    private static InjectionConfig injectionConfig(final CodeGeneratorConfig config, String projectRootPath, PackageConfig pc) {
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                Map<String, Object> map = initImportPackageInfo(config.getPackageBase(), config.getChildPackageName());
+                this.setMap(map);
+            }
+        };
+        cfg.setFileCreate(config.getFileCreateConfig());
+
+        // 自定义输出配置
+        cfg.setFileOutConfigList(getFileConfig(config));
+        return cfg;
+    }
+
+    /**
+     * 配置包信息    配置规则是:   parentPackage + "层" + "模块"
+     */
+    public static Map<String, Object> initImportPackageInfo(String parentPackage, String childPackageName) {
+        Map<String, Object> packageMap = new HashMap<>();
+        if (childPackageName != null && !"".equals(childPackageName.trim())) {
+            childPackageName = "." + childPackageName;
+        }
+
+//        packageMap.put(API_PATH, parentPackage + ".api" + childPackageName);
+//        packageMap.put(ConstVal.CONTROLLER, parentPackage + ".controller" + childPackageName);
+
+//        packageMap.put(ConstVal.SERVICE, parentPackage + ".service" + childPackageName);
+//        packageMap.put(ConstVal.SERVICE_IMPL, parentPackage + ".service" + childPackageName + ".impl");
+
+//        packageMap.put(ConstVal.MAPPER, parentPackage + ".dao" + childPackageName);
+        packageMap.put(QUERY_PATH, parentPackage + ".query" + childPackageName);
+//        packageMap.put(ConstVal.ENTITY, parentPackage + ".entity" + childPackageName);
+
+        packageMap.put(ENUM_PATH, parentPackage + ".entity" + childPackageName);
+        packageMap.put(CONSTANT_PATH, parentPackage + ".constant" + childPackageName);
+        packageMap.put("constantSuffix", "Constant");
+//        packageMap.put(DTO_PATH, parentPackage + ".dto" + childPackageName);
+        packageMap.put(SAVE_DTO_PATH, parentPackage + ".dto" + childPackageName);
+        packageMap.put(UPDATE_DTO_PATH, parentPackage + ".dto" + childPackageName);
+        packageMap.put(PAGE_DTO_PATH, parentPackage + ".dto" + childPackageName);
+
+        return packageMap;
+    }
+
+    private static List<FileOutConfig> getFileConfig(CodeGeneratorConfig config) {
+        List<FileOutConfig> focList = new ArrayList<>();
+
+        String projectRootPath = config.getProjectRootPath();
+        if (!projectRootPath.endsWith(File.separator)) {
+            projectRootPath += File.separator;
+        }
+        String packageBase = config.getPackageBase().replace(".", File.separator);
+
+        StringBuilder basePathSb = new StringBuilder(projectRootPath).append("%s");
+        basePathSb.append(SRC_MAIN_JAVA).append(File.separator)
+                .append(packageBase)
+                .toString();
+
+        final String basePath = basePathSb.toString();
+
+        focList.add(new FileOutConfigExt(basePath, ConstVal.CONTROLLER, config));
+        focList.add(new FileOutConfigExt(basePath, ConstVal.SERVICE, config));
+        focList.add(new FileOutConfigExt(basePath, ConstVal.SERVICE_IMPL, config));
+        focList.add(new FileOutConfigExt(basePath, ConstVal.MAPPER, config));
+        focList.add(new FileOutConfigExt(basePath, ConstVal.XML, config));
+
+        focList.add(new FileOutConfigExt(basePath, QUERY_PATH, config));
+        focList.add(new FileOutConfigExt(basePath, CONSTANT_PATH, config));
+
+        //focList.add(new FileOutConfigExt(basePath, DTO_PATH, config));
+        //focList.add(new FileOutConfigExt(basePath, SAVE_DTO_PATH, config));
+        //focList.add(new FileOutConfigExt(basePath, UPDATE_DTO_PATH, config));
+        //focList.add(new FileOutConfigExt(basePath, PAGE_DTO_PATH, config));
+
+        return focList;
+    }
+
+
+}

+ 330 - 0
src/main/java/com/zkthink/ceres/generator/ProjectGenerator.java

@@ -0,0 +1,330 @@
+package com.zkthink.ceres.generator;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+import com.zkthink.ceres.generator.config.CodeGeneratorConfig;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 项目生成工具
+ *
+ * @author ceres
+ * @date 2019/05/25
+ */
+@Slf4j
+public class ProjectGenerator {
+    /**
+     * 项目模块名称
+     */
+    private final static String API = "api";
+    private final static String ENTITY = "entity";
+    private final static String BIZ = "biz";
+    private final static String CONTROLLER = "controller";
+    private final static String SERVER = "server";
+
+
+    private final static String[] ALL_MODULAR_LIST = new String[]{
+            API, ENTITY, BIZ, CONTROLLER, SERVER,
+    };
+    private final static String[] CHILD_MODULAR_LIST = new String[]{
+            BIZ, CONTROLLER
+    };
+
+    /**
+     * 模板路径
+     */
+    private static final String INIT_JAVA_FTL = "init/java/%s.java.ftl";
+    private static final String INIT_RESOURCES_FTL = "init/resources/%s.java.ftl";
+    private static final String INIT_FTL = "init/pom/%s.java.ftl";
+
+    private final static String SRC_MAIN_JAVA = "src/main/java";
+    private final static String SRC_MAIN_RESOURCES = "src/main/resources";
+    private final static String[] MAVEN_PATH = new String[]{
+            SRC_MAIN_JAVA, SRC_MAIN_RESOURCES, "src/test/java", "src/test/resources"
+    };
+
+    private Configuration configuration;
+    private CodeGeneratorConfig config;
+
+    public ProjectGenerator(CodeGeneratorConfig config) {
+        this.init();
+        this.config = config;
+    }
+
+
+    private void init() {
+        this.configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
+        this.configuration.setDefaultEncoding(ConstVal.UTF8);
+        this.configuration.setClassForTemplateLoading(FreemarkerTemplateEngine.class, StringPool.SLASH);
+    }
+
+    public void build() {
+        boolean isChildModule = !this.config.getServiceName().equalsIgnoreCase(this.config.getChildModuleName());
+
+        // 创建项目跟文件夹
+        File parentPath = new File(this.config.getProjectRootPath());
+        if (!parentPath.exists()) {
+            parentPath.mkdirs();
+        }
+
+        //创建服务文件夹
+        String serviceName = this.config.getProjectPrefix() + this.config.getServiceName();
+        log.info("服务名:{}", serviceName);
+        String servicePath = Paths.get(this.config.getProjectRootPath(), serviceName).toString();
+        Map<String, Object> objectMap = this.getObjectMap(this.config);
+
+        String[] modularList = ALL_MODULAR_LIST;
+        if (isChildModule) {
+            modularList = CHILD_MODULAR_LIST;
+        }
+        for (String modular : modularList) {
+            //创建模块文件夹
+            String modularPath = this.mkModular(servicePath, serviceName, modular, isChildModule);
+
+            this.mkMaven(modularPath);
+            this.mkBasePackage(modularPath);
+
+            this.generatorPom(objectMap, String.format(INIT_FTL, modular), modularPath);
+        }
+
+        if (!isChildModule) {
+            //根 pom
+            this.writer(objectMap, String.format(INIT_FTL, "pom"), Paths.get(servicePath, "pom.xml").toString());
+
+            // api 模块 生成在 ceres-api 模块下
+//            this.generatorApiModular(serviceName, objectMap);
+
+            // server 模块
+            String serverApplicationPath = this.mkServer(servicePath, serviceName);
+            this.generatorServerJava(objectMap, serverApplicationPath);
+
+            String modularName = serviceName + "-" + SERVER;
+            String serverResourcePath = Paths.get(servicePath, modularName, SRC_MAIN_RESOURCES).toString();
+            this.generatorServerResources(objectMap, serverResourcePath);
+        } else {
+            String modulerName = this.config.getProjectPrefix() + this.config.getChildModuleName();
+            System.err.println("------------------------------------------");
+            System.err.println(String.format("生成完毕,请将以下配置手工加入:%s/pom.xml", serviceName));
+            System.err.println(String.format(
+                    "            <dependency>\n" +
+                            "                <groupId>%s</groupId>\n" +
+                            "                <artifactId>%s-biz</artifactId>\n" +
+                            "                <version>${project.version}</version>\n" +
+                            "            </dependency>", config.getGroupId(), modulerName));
+            System.err.println(String.format(
+                    "            <dependency>\n" +
+                            "                <groupId>%s</groupId>\n" +
+                            "                <artifactId>%s-controller</artifactId>\n" +
+                            "                <version>${project.version}</version>\n" +
+                            "            </dependency>", config.getGroupId(), modulerName));
+            System.err.println("");
+            System.err.println(String.format(
+                    "        <module>%s-biz</module>\n" +
+                            "        <module>%s-controller</module>", modulerName, modulerName));
+
+            System.err.println("------------------------------------------");
+            System.err.println(String.format("生成完毕,请将以下配置手工加入:%s/%s/pom.xml", serviceName, serviceName + "-server"));
+
+            System.err.println(String.format(
+                    "            <dependency>\n" +
+                            "                <groupId>%s</groupId>\n" +
+                            "                <artifactId>%s-controller</artifactId>\n" +
+                            "            </dependency>", config.getGroupId(), modulerName));
+        }
+
+        System.err.println("生成完毕,但请手动完成以下操作:");
+        System.err.println("------------------------------------------");
+        System.err.println(String.format("将以下配置手工加入:%s/pom.xml", this.config.getProjectPrefix() + "admin-cloud"));
+        System.err.println(String.format("        <module>%s</module>", serviceName));
+
+        System.err.println("------------------------------------------");
+        String projectName = serviceName + "-server";
+        String nacosProject = serviceName + "-server.yml";
+        System.err.println(String.format("在nacos中新建一个名为: %s 的配置文件,并将: %s/src/main/resources/%s 配置文件的内容移动过去", nacosProject, projectName, nacosProject));
+
+        System.err.println("------------------------------------------");
+        System.err.println("将下面的配置手动加入nacos中 ceres-zuul-server.yml");
+        System.err.println(String.format("    %s:\n" +
+                "      path: /%s/**\n" +
+                "      serviceId: %s-server", config.getServiceName(), config.getServiceName(), serviceName));
+
+        System.err.println("------------------------------------------");
+        System.err.println("将下面的配置手动加入nacos中 ceres-gateway-server.yml");
+        System.err.println(String.format("        - id: %s\n" +
+                "          uri: lb://%s-server\n" +
+                "          predicates:\n" +
+                "            - Path=/%s/**\n" +
+                "          filters:\n" +
+                "            - StripPrefix=1\n" +
+                "            - name: Hystrix\n" +
+                "              args:\n" +
+                "                name: default\n" +
+                "                fallbackUri: 'forward:/fallback'", config.getServiceName(), serviceName, config.getServiceName()));
+
+    }
+
+    private void generatorApiModular(String serviceName, Map<String, Object> objectMap) {
+        String apiName = this.config.getProjectPrefix() + "api";
+        String apiModularName = serviceName + "-api";
+        log.info("已经生成模块:{}", apiModularName);
+        String apiPath = Paths.get(this.config.getProjectRootPath(), apiName, apiModularName).toString();
+        File apiPathFile = new File(apiPath);
+        if (!apiPathFile.exists()) {
+            apiPathFile.mkdirs();
+        }
+        this.mkMaven(apiPath);
+        this.generatorPom(objectMap, String.format(INIT_FTL, "api"), apiPath);
+    }
+
+    private void generatorServerResources(Map<String, Object> objectMap, String serverResourcePath) {
+        this.writer(objectMap, String.format(INIT_RESOURCES_FTL, "banner"), Paths.get(serverResourcePath, "banner.txt").toString());
+        this.writer(objectMap, String.format(INIT_RESOURCES_FTL, "bootstrap"), Paths.get(serverResourcePath, "bootstrap.yml").toString());
+        this.writer(objectMap, String.format(INIT_RESOURCES_FTL, "logback-spring"), Paths.get(serverResourcePath, "logback-spring.xml").toString());
+        this.writer(objectMap, String.format(INIT_RESOURCES_FTL, "spy"), Paths.get(serverResourcePath, "spy.properties").toString());
+
+        //dev 废除
+//        String serviceNameDev = this.config.getProjectPrefix() + this.config.getServiceName() + "-server-dev.yml";
+//        this.writer(objectMap, String.format(INIT_RESOURCES_FTL, "application-dev"), Paths.get(serverResourcePath, serviceNameDev).toString());
+        String serviceName = this.config.getProjectPrefix() + this.config.getServiceName() + "-server.yml";
+        this.writer(objectMap, String.format(INIT_RESOURCES_FTL, "application"), Paths.get(serverResourcePath, serviceName).toString());
+    }
+
+    /**
+     * 生成 server项目下的jar代码
+     *
+     * @param objectMap
+     * @param serverApplicationPath
+     */
+    private void generatorServerJava(Map<String, Object> objectMap, String serverApplicationPath) {
+        Object service = objectMap.get("service");
+
+        String serverApplicationParentPath = StrUtil.subPre(serverApplicationPath, serverApplicationPath.lastIndexOf(File.separator));
+        //启动类
+        this.writer(objectMap, String.format(INIT_JAVA_FTL, "Application"), Paths.get(serverApplicationParentPath, service + "ServerApplication.java").toString());
+        // 通用控制器
+//        this.writer(objectMap, String.format(INIT_JAVA_FTL, "GeneralController"), Paths.get(serverApplicationParentPath, "general", "controller", service + "GeneralController.java").toString());
+
+        String serverConfigPath = Paths.get(serverApplicationPath, "config").toString();
+        // 全局异常
+        this.writer(objectMap, String.format(INIT_JAVA_FTL, "ExceptionConfiguration"), Paths.get(serverConfigPath, service + "ExceptionConfiguration.java").toString());
+        //Web
+        this.writer(objectMap, String.format(INIT_JAVA_FTL, "WebConfiguration"), Paths.get(serverConfigPath, service + "WebConfiguration.java").toString());
+        //数据源
+        this.writer(objectMap, String.format(INIT_JAVA_FTL, "DatabaseAutoConfiguration"), Paths.get(serverConfigPath, "datasource", service + "DatabaseAutoConfiguration.java").toString());
+        this.writer(objectMap, String.format(INIT_JAVA_FTL, "MybatisAutoConfiguration"), Paths.get(serverConfigPath, "datasource", service + "MybatisAutoConfiguration.java").toString());
+    }
+
+    private String mkServer(String servicePath, String serviceName) {
+        String modularName = serviceName + "-" + SERVER;
+        String packageBase = this.config.getPackageBase().replace(".", File.separator);
+
+        String serverApplicationPath = Paths.get(servicePath, modularName, SRC_MAIN_JAVA, packageBase).toString();
+        String modularConfigPath = Paths.get(serverApplicationPath, "config").toString();
+        File modularConfigFile = new File(modularConfigPath);
+        if (!modularConfigFile.exists()) {
+            modularConfigFile.mkdirs();
+        }
+        return serverApplicationPath;
+    }
+
+
+    private Map<String, Object> getObjectMap(CodeGeneratorConfig globalConfig) {
+        boolean isChildModule = !this.config.getServiceName().equalsIgnoreCase(this.config.getChildModuleName());
+        Map<String, Object> objectMap = new HashMap<>();
+        objectMap.put("author", globalConfig.getAuthor());
+        objectMap.put("serviceName", globalConfig.getServiceName());
+        objectMap.put("isChildModule", isChildModule);
+        objectMap.put("childModuleName", globalConfig.getChildModuleName());
+        objectMap.put("packageBase", globalConfig.getPackageBase());
+        objectMap.put("projectPrefix", globalConfig.getProjectPrefix());
+        objectMap.put("service", StrUtil.upperFirst(globalConfig.getServiceName()));
+        objectMap.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
+        objectMap.put("version", globalConfig.getVersion());
+        objectMap.put("packageBaseParent", globalConfig.getPackageBaseParent());
+        objectMap.put("serverPort", globalConfig.getServerPort());
+        objectMap.put("groupId", globalConfig.getGroupId());
+        objectMap.put("description", globalConfig.getDescription());
+        return objectMap;
+    }
+
+
+    private void writer(Map<String, Object> objectMap, String templatePath, String outputFile) {
+        File file = new File(outputFile);
+        if (!file.getParentFile().exists()) {
+            file.getParentFile().mkdirs();
+        }
+        try {
+            Template template = this.configuration.getTemplate(templatePath);
+            try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
+                template.process(objectMap, new OutputStreamWriter(fileOutputStream, ConstVal.UTF8));
+            }
+        } catch (Exception e) {
+            log.error("生成失败", e);
+        }
+    }
+
+    /**
+     * 生成pom
+     *
+     * @param templatePath
+     */
+    private void generatorPom(Map<String, Object> objectMap, String templatePath, String outputFile) {
+        this.writer(objectMap, templatePath, Paths.get(outputFile, "pom.xml").toString());
+    }
+
+
+    private String mkModular(String servicePath, String serviceName, String modular, boolean isChildModule) {
+        //String modularName = serviceName + "-" + modular;
+        String modularName = modular;
+        if (isChildModule) {
+            String childModuleName = this.config.getProjectPrefix() + this.config.getChildModuleName();
+            modularName = childModuleName + "-" + modular;
+        }
+        log.info("已经生成模块:{}", modularName);
+        String modularPath = Paths.get(servicePath, modularName).toString();
+        File modularPathFile = new File(modularPath);
+        if (!modularPathFile.exists()) {
+            modularPathFile.mkdirs();
+        }
+        return modularPath;
+    }
+
+
+    /**
+     * 创建 maven 目录文件夹
+     *
+     * @param modularPath
+     */
+    private void mkMaven(String modularPath) {
+        for (String maven : MAVEN_PATH) {
+            String mavenPath = Paths.get(modularPath, maven).toString();
+            File mavenPathFile = new File(mavenPath);
+            if (!mavenPathFile.exists()) {
+                mavenPathFile.mkdirs();
+            }
+        }
+    }
+
+    private void mkBasePackage(String modularPath) {
+        String basePackage = Paths.get(modularPath, SRC_MAIN_JAVA, StrUtil.replace(config.getPackageBase(), ".", File.separator)).toString();
+        File mavenPathFile = new File(basePackage);
+        if (!mavenPathFile.exists()) {
+            mavenPathFile.mkdirs();
+        }
+
+
+    }
+}

+ 253 - 0
src/main/java/com/zkthink/ceres/generator/config/CodeGeneratorConfig.java

@@ -0,0 +1,253 @@
+package com.zkthink.ceres.generator.config;
+
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.zkthink.ceres.generator.model.GenTableColumn;
+import com.zkthink.ceres.generator.type.EntityFiledType;
+import com.zkthink.ceres.generator.type.EntityType;
+import com.zkthink.ceres.generator.type.SuperClass;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * 代码生成配置
+ * <p>
+ * 微服务项目默认会创建4个项目,
+ * cloud-authority-api、cloud-authority-rest、cloud-authority-entity、cloud-authority-repository
+ * 匹配符为:${projectPrefix}${serviceName}-${apiSuffix}
+ * <p>
+ * 然后在每个项目的src/main/java下创建包:
+ * ${packageBase}.api.${childModuleName}
+ * ${packageBase}.rest.${childModuleName}
+ * ${packageBase}.entity.${childModuleName}
+ * ${packageBase}.enumeration.${childModuleName}
+ * ${packageBase}.constant.${childModuleName}
+ * ${packageBase}.dto.${childModuleName}
+ * ${packageBase}.service.${childModuleName}
+ * ${packageBase}.service.${childModuleName}.impl
+ * ${packageBase}.dao.${childModuleName}
+ * ${projectPrefix}${serviceName}-${serviceSuffix}项目的src/main/resource下创建包:
+ * mapper_${serviceName}.base.${childModuleName}
+ *
+ * @author ceres
+ * @date 2019年05月25日20:59:57
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+public class CodeGeneratorConfig {
+
+    /**
+     * 项目跟路径
+     */
+    String projectRootPath = System.getProperty("user.dir");
+    /**
+     * 服务名
+     * 如消息服务 (用于创建cloud-%s-api、cloud-%s-entity等项目)
+     */
+    String serviceName = "";
+    /**
+     * 子模块名称
+     * 如消息服务(cloud-msgs-new)包含消息、短信、邮件3个模块
+     * 则分别填入 msgs、sms、email
+     * (用于创建cloud-%s-rest、cloud-%s-repository等项目)
+     */
+    String childModuleName = "";
+    /**
+     * 基础包   所有的代码都放置在这个包之下
+     */
+    String packageBase = "com.zkthink.authority";
+
+    /**
+     * common包 用于存放基础类
+     */
+    String packageCommon = "com.shop.cereshop.commons";
+
+    /**
+     * 子包名称
+     * 会在api、controller、service、serviceImpl、dao、entity等包下面创建子包
+     */
+    String childPackageName = "";
+    /**
+     * 作者
+     */
+    String author = "ceres";
+
+    /**
+     * 是否需要生成admin包的内容
+     */
+    boolean needAdmin = true;
+
+    /**
+     * 是否需要生成app包的内容
+     */
+    boolean needApp = true;
+
+    /**
+     * 是否需要生成business包的内容
+     */
+    boolean needBusiness = true;
+
+    /**
+     * 项目统一前缀  比如:  cloud-
+     */
+    private String projectPrefix = "cereshop";
+
+    private String apiSuffix = "-api";
+    private String entitySuffix = "-commons";
+    private String adminSuffix = "-admin";
+    private String appSuffix = "-app";
+    private String businessSuffix = "-business";
+    private String serviceSuffix = "-biz";
+    private String controllerSuffix = "-controller";
+    /**
+     * 版本
+     */
+    String version = "1.0-SNAPSHOT";
+    /**
+     * 端口号
+     */
+    String serverPort = "8080";
+    String groupId = "com.zkthin";
+    String description = "服务";
+//    private String serverSuffix = "-server";
+
+    public String getPackageBaseParent() {
+        return StrUtil.subPre(this.packageBase, this.packageBase.lastIndexOf("."));
+    }
+
+    /**
+     * entity的父类
+     */
+    private EntityType superEntity = EntityType.ENTITY;
+    /**
+     * controller的父类
+     */
+    private String superControllerClass = SuperClass.SUPER_CLASS.getController();
+
+    /**
+     * 自定义继承的Mapper类全称,带包名
+     */
+    private String superMapperClass = SuperClass.SUPER_CLASS.getMapper();
+    /**
+     * 自定义继承的Service类全称,带包名
+     */
+    private String superServiceClass = SuperClass.SUPER_CLASS.getService();
+    /**
+     * 自定义继承的ServiceImpl类全称,带包名
+     */
+    private String superServiceImplClass = SuperClass.SUPER_CLASS.getServiceImpl();
+    /**
+     * 表前缀
+     */
+    private String tablePrefix = "";
+    /**
+     * 字段前缀
+     */
+    private String fieldPrefix = "";
+    /**
+     * 需要包含的表名,允许正则表达式;用来自动生成代码
+     */
+    private String[] tableInclude = {"c_user"};
+    /**
+     * 基础的xml路径
+     */
+//    private String xmlPath = "";
+    private String[] tableExclude = {};
+    /**
+     * 驱动连接的URL
+     */
+    private String url = "jdbc:mysql://127.0.0.1:3306/ceres_base_0000?serverTimezone=CTT&characterEncoding=utf8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull";
+    /**
+     * 驱动名称
+     */
+    private String driverName = "com.mysql.cj.jdbc.Driver";
+    /**
+     * 数据库连接用户名
+     */
+    private String username = "root";
+    /**
+     * 数据库连接密码
+     */
+    private String password = "root";
+    /**
+     * 仅仅在微服务架构下面才进行分包
+     */
+    private boolean enableMicroService = true;
+
+    private FileCreateConfig fileCreateConfig = new FileCreateConfig();
+    /**
+     * 需要制定生成路径的枚举类列表
+     */
+    private Set<EntityFiledType> filedTypes = new HashSet<>();
+
+    /**
+     * 当前处理的模块
+     */
+    private String currentModule = null;
+
+    /**
+     *
+     */
+    public final static String[] CERESHOP_MODULAR_LIST = new String[]{
+            "admin", "app", "business"
+    };
+
+    private Vue vue = new Vue();
+
+    @Data
+    public static class Vue {
+        private String viewsPath = "views" + File.separator + "ceres";
+
+        /**
+         * 表名 - <字段名 - 字段信息>
+         */
+        private Map<String, Map<String, GenTableColumn>> tableFieldMap = new HashMap<>();
+    }
+
+    /**
+     * 必填项 构造器
+     *
+     * @param serviceName     服务名
+     *                        eg: msgs
+     * @param childModuleName 子模块名
+     *                        eg: sms、emial
+     * @param author          作者
+     * @param tablePrefix     表前缀
+     * @param tableInclude    生成的表 支持通配符
+     *                        eg: msgs_.* 会生成msgs_开头的所有表
+     * @return
+     */
+    public static CodeGeneratorConfig build(String serviceName, String childModuleName, String author, String tablePrefix, List<String> tableInclude) {
+        CodeGeneratorConfig config = new CodeGeneratorConfig();
+        config.setServiceName(serviceName).setAuthor(author).setTablePrefix(tablePrefix)
+                .setTableInclude(tableInclude.stream().toArray(String[]::new))
+                .setChildModuleName(childModuleName == null ? "" : childModuleName);
+        config.setPackageBase("com.zkthink." + config.getChildModuleName());
+        return config;
+    }
+
+
+    public static CodeGeneratorConfig buildVue(String serviceName, String tablePrefix, List<String> tableInclude) {
+        CodeGeneratorConfig config = new CodeGeneratorConfig();
+        config.setServiceName(serviceName).setTablePrefix(tablePrefix)
+                .setTableInclude(tableInclude.stream().toArray(String[]::new))
+                .setChildModuleName("");
+        config.setPackageBase("com.zkthink." + config.getChildModuleName());
+        return config;
+    }
+
+    public String getChildModuleName() {
+        if (StringUtils.isBlank(this.childModuleName)) {
+            this.childModuleName = this.serviceName;
+        }
+        return this.childModuleName;
+    }
+}

+ 235 - 0
src/main/java/com/zkthink/ceres/generator/config/FileCreateConfig.java

@@ -0,0 +1,235 @@
+package com.zkthink.ceres.generator.config;
+
+import com.baomidou.mybatisplus.generator.config.IFileCreate;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+import com.baomidou.mybatisplus.generator.config.rules.FileType;
+import com.zkthink.ceres.generator.ext.FileOutConfigExt;
+import com.zkthink.ceres.generator.type.GenerateType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.File;
+
+/**
+ * 文件创建配置类
+ *
+ * @author ceres
+ * @date 2019-05-25
+ */
+@Data
+@Accessors(chain = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FileCreateConfig implements IFileCreate {
+
+    private GenerateType generate;
+    private GenerateType generateEnum = GenerateType.OVERRIDE;
+    private GenerateType generateEntity = GenerateType.OVERRIDE;
+    private GenerateType generateConstant = GenerateType.IGNORE;
+    private GenerateType generateDao = GenerateType.IGNORE;
+    private GenerateType generateXml = GenerateType.IGNORE;
+    private GenerateType generateService = GenerateType.IGNORE;
+    private GenerateType generateServiceImpl = GenerateType.IGNORE;
+    private GenerateType generateController = GenerateType.IGNORE;
+
+    private GenerateType generateDto = GenerateType.IGNORE;
+    private GenerateType generateQuery = GenerateType.IGNORE;
+
+    private GenerateType generateApi = GenerateType.IGNORE;
+    private GenerateType generatePageIndex = GenerateType.IGNORE;
+    private GenerateType generateTreeIndex = GenerateType.IGNORE;
+    private GenerateType generateEdit = GenerateType.IGNORE;
+    private Boolean isVue = false;
+
+    /**
+     * 指定了generate后, 会覆盖 controller、service、dao等生成策略
+     *
+     * @param generate
+     */
+    public FileCreateConfig(GenerateType generate) {
+        this.generate = generate;
+        if (generate != null) {
+            this.generateEntity = generate;
+            this.generateDao = generate;
+            this.generateXml = generate;
+            this.generateService = generate;
+            this.generateServiceImpl = generate;
+            this.generateController = generate;
+            this.generateEnum = generate;
+            this.generateDto = generate;
+        }
+        this.generateConstant = GenerateType.IGNORE;
+        this.generateQuery = GenerateType.IGNORE;
+        this.generateApi = GenerateType.IGNORE;
+    }
+
+    public FileCreateConfig(GenerateType generate, boolean isVue) {
+        this.generate = generate;
+        this.isVue = isVue;
+        if (isVue) {
+            this.generateEntity = GenerateType.IGNORE;
+            this.generateDao = GenerateType.IGNORE;
+            this.generateXml = GenerateType.IGNORE;
+            this.generateService = GenerateType.IGNORE;
+            this.generateServiceImpl = GenerateType.IGNORE;
+            this.generateController = GenerateType.IGNORE;
+            this.generateEnum = GenerateType.IGNORE;
+            this.generateDto = GenerateType.IGNORE;
+
+            //index 和 Tree 只能生成一种
+            if (GenerateType.OVERRIDE.eq(this.generatePageIndex)) {
+                this.generateTreeIndex = GenerateType.IGNORE;
+            } else if (GenerateType.OVERRIDE.eq(this.generateTreeIndex)) {
+                this.generatePageIndex = GenerateType.IGNORE;
+                this.generateEdit = GenerateType.IGNORE;
+            }
+
+            if (generate != null) {
+                this.generateApi = generate;
+                this.generatePageIndex = generate;
+                this.generateTreeIndex = GenerateType.IGNORE;
+                this.generateEdit = generate;
+            }
+        } else {
+            this.generateConstant = GenerateType.IGNORE;
+            this.generateQuery = GenerateType.IGNORE;
+            if (generate != null) {
+                this.generateEntity = generate;
+                this.generateDao = generate;
+                this.generateXml = generate;
+                this.generateService = generate;
+                this.generateServiceImpl = generate;
+                this.generateController = generate;
+                this.generateEnum = generate;
+                this.generateDto = generate;
+            }
+        }
+
+    }
+
+    /**
+     * 判断文件是否存在
+     *
+     * @param path 路径
+     */
+    public static boolean isExists(String path) {
+        File file = new File(path);
+        return file.exists();
+    }
+
+    @Override
+    public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
+        File file = new File(filePath);
+        if (this.generate != null) {
+            if (filePath.contains(File.separator + "constant" + File.separator)) {
+                return isCreate(generateConstant, file);
+            }
+            if (filePath.contains(File.separator + "query" + File.separator)) {
+                return isCreate(generateQuery, file);
+            }
+
+            // api.js
+            if (filePath.contains(File.separator + "api" + File.separator)) {
+                return isCreate(generateApi, file);
+            }
+            //edit.vue
+            if (filePath.endsWith("Edit" + FileOutConfigExt.DOT_VUE)) {
+                return isCreate(generateEdit, file);
+            }
+            //Index.vue
+            if (filePath.endsWith("Index" + FileOutConfigExt.DOT_VUE)) {
+                return isCreate(generatePageIndex, file);
+            }
+            //Tree.vue
+            if (filePath.endsWith("Tree" + FileOutConfigExt.DOT_VUE)) {
+                return isCreate(generateTreeIndex, file);
+            }
+
+            return isCreate(generate, file);
+        }
+        //实体
+        if (FileType.ENTITY == fileType) {
+            return isCreate(generateEntity, file);
+            //控制器
+        } else if (FileType.CONTROLLER == fileType) {
+            return isCreate(generateController, file);
+            //dao
+        } else if (FileType.XML == fileType) {
+            return isCreate(generateXml, file);
+        } else if (FileType.MAPPER == fileType) {
+            return isCreate(generateDao, file);
+            //service
+        } else if (FileType.SERVICE == fileType) {
+            return isCreate(generateService, file);
+        } else if (FileType.SERVICE_IMPL == fileType) {
+            return isCreate(generateServiceImpl, file);
+        } else if (FileType.OTHER == fileType) {
+            if (filePath.contains(File.separator + "enumeration" + File.separator)) {
+                return isCreate(generateEnum, file);
+            }
+            if (filePath.contains(File.separator + "constant" + File.separator)) {
+                return isCreate(generateConstant, file);
+            }
+            if (filePath.contains(File.separator + "query" + File.separator)) {
+                return isCreate(generateQuery, file);
+            }
+            if (filePath.contains(File.separator + "entity" + File.separator)) {
+                return isCreate(generateEntity, file);
+            }
+            if (filePath.contains(File.separator + "dto" + File.separator)) {
+                return isCreate(generateDto, file);
+            }
+            //控制器
+            if (filePath.contains(File.separator + "controller" + File.separator)) {
+                return isCreate(generateController, file);
+            }
+            //dao
+            if (filePath.contains(File.separator + "mapper_")) {
+                return isCreate(generateXml, file);
+            }
+            if (filePath.contains(File.separator + "dao" + File.separator)) {
+                return isCreate(generateDao, file);
+            }
+            if (filePath.contains(File.separator + "service" + File.separator)) {
+                return isCreate(generateService, file);
+            }
+            if (filePath.contains(File.separator + "impl" + File.separator)) {
+                return isCreate(generateServiceImpl, file);
+            }
+
+            // api.js
+            if (filePath.contains(File.separator + "api" + File.separator)) {
+                return isCreate(generateApi, file);
+            }
+            //edit.vue
+            if (filePath.endsWith("Edit" + FileOutConfigExt.DOT_VUE)) {
+                return isCreate(generateEdit, file);
+            }
+            //Index.vue
+            if (filePath.endsWith("Index" + FileOutConfigExt.DOT_VUE)) {
+                return isCreate(generatePageIndex, file);
+            }
+            //Tree.vue
+            if (filePath.endsWith("Tree" + FileOutConfigExt.DOT_VUE)) {
+                return isCreate(generateTreeIndex, file);
+            }
+
+        }
+        return true;
+    }
+
+    private boolean isCreate(GenerateType gen, File file) {
+        if (GenerateType.IGNORE.eq(gen)) {
+            return false;
+        }
+        if (!file.exists()) {
+            file.getParentFile().mkdirs();
+        }
+        return true;
+    }
+
+}

+ 192 - 0
src/main/java/com/zkthink/ceres/generator/ext/FileOutConfigExt.java

@@ -0,0 +1,192 @@
+package com.zkthink.ceres.generator.ext;
+
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.generator.config.FileOutConfig;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.zkthink.ceres.generator.CodeGenerator;
+import com.zkthink.ceres.generator.config.CodeGeneratorConfig;
+import com.zkthink.ceres.generator.config.FileCreateConfig;
+import com.zkthink.ceres.generator.type.GenerateType;
+
+import java.io.File;
+import java.nio.file.Paths;
+
+/**
+ * 文件输出扩展
+ *
+ * @author ceres
+ * @date 2019/05/26
+ */
+public class FileOutConfigExt extends FileOutConfig {
+    public static final String DOT_VUE = ".vue";
+    public static final String DOT_JS = ".js";
+    String innerBasePath;
+
+    String projectSuffix;
+    String modularSuffix;
+    GenerateType generateType;
+    CodeGeneratorConfig config;
+
+    public FileOutConfigExt(String innerBasePath, String modularSuffix, CodeGeneratorConfig config) {
+        this.innerBasePath = innerBasePath;
+        this.modularSuffix = modularSuffix;
+        this.projectSuffix = "-" + config.getCurrentModule();
+        this.config = config;
+        FileCreateConfig fileCreateConfig = config.getFileCreateConfig();
+        switch (modularSuffix) {
+            case CodeGenerator.ENUM_PATH:
+                this.setTemplatePath("/templates/enum.java.ftl");
+                this.generateType = fileCreateConfig.getGenerateEnum();
+                break;
+            case CodeGenerator.SAVE_DTO_PATH:
+                this.setTemplatePath("/templates/saveDto.java.ftl");
+                this.generateType = fileCreateConfig.getGenerateDto();
+                break;
+            case CodeGenerator.PAGE_DTO_PATH:
+                this.setTemplatePath("/templates/pageDto.java.ftl");
+                this.generateType = fileCreateConfig.getGenerateDto();
+                break;
+            case CodeGenerator.UPDATE_DTO_PATH:
+                this.setTemplatePath("/templates/updateDto.java.ftl");
+                this.generateType = fileCreateConfig.getGenerateDto();
+                break;
+            case CodeGenerator.CONSTANT_PATH:
+                this.setTemplatePath("/templates/constant.java.ftl");
+                this.generateType = fileCreateConfig.getGenerateConstant();
+                break;
+            case CodeGenerator.QUERY_PATH:
+                this.setTemplatePath("/templates/query.java.ftl");
+                this.generateType = fileCreateConfig.getGenerateQuery();
+                break;
+            case ConstVal.ENTITY:
+                this.setTemplatePath(ConstVal.TEMPLATE_ENTITY_JAVA + ".ftl");
+                this.generateType = fileCreateConfig.getGenerateEntity();
+                break;
+            case ConstVal.SERVICE:
+                this.setTemplatePath(ConstVal.TEMPLATE_SERVICE + ".ftl");
+                this.generateType = fileCreateConfig.getGenerateService();
+                break;
+            case ConstVal.SERVICE_IMPL:
+                this.setTemplatePath(ConstVal.TEMPLATE_SERVICE_IMPL + ".ftl");
+                this.generateType = fileCreateConfig.getGenerateServiceImpl();
+                break;
+            case ConstVal.MAPPER:
+                this.setTemplatePath(ConstVal.TEMPLATE_MAPPER + ".ftl");
+                this.generateType = fileCreateConfig.getGenerateDao();
+                break;
+            case ConstVal.XML:
+                this.setTemplatePath(ConstVal.TEMPLATE_XML + ".ftl");
+                this.generateType = fileCreateConfig.getGenerateXml();
+                break;
+            case ConstVal.CONTROLLER:
+                this.setTemplatePath(ConstVal.TEMPLATE_CONTROLLER + ".ftl");
+                this.generateType = fileCreateConfig.getGenerateController();
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public String outputFile(TableInfo tableInfo) {
+
+        if (ConstVal.XML.equals(modularSuffix)) {
+            String projectRootPath = config.getProjectRootPath();
+            if (!projectRootPath.endsWith(File.separator)) {
+                projectRootPath += File.separator;
+            }
+
+            StringBuilder basePathSb = new StringBuilder(projectRootPath);
+            if (config.isEnableMicroService()) {
+                basePathSb.append(config.getProjectPrefix());
+                basePathSb.append(config.getChildModuleName());
+                basePathSb.append(projectSuffix)
+                        .append(File.separator);
+            }
+            basePathSb.append(CodeGenerator.SRC_MAIN_RESOURCE)
+                    .append(File.separator)
+                    .append("mybatis")
+                    .append(File.separator)
+                    .append("mapper");
+                    //.append(config.getChildModuleName())
+                    //.append(File.separator)
+                    //.append(config.getCurrentModule());
+            if (StringUtils.isNotEmpty(config.getChildPackageName())) {
+                basePathSb.append(File.separator).append(config.getChildPackageName());
+            }
+
+            //basePath = basePath + File.separator + tableInfo.getEntityName() + modularSuffix + StringPool.DOT_JAVA;
+            basePathSb.append(File.separator)
+                    .append(tableInfo.getEntityName())
+                    .append("DAO")
+                    .append(StringPool.DOT_XML);
+
+            if (GenerateType.ADD.eq(generateType) && FileCreateConfig.isExists(basePathSb.toString())) {
+                basePathSb.append(".new");
+            }
+            return basePathSb.toString();
+        }
+
+        // 根路径 + 项目名 + SRC_MAIN_JAVA + 基础包 + service + 子模块 + EntityName+后缀
+
+        String projectName = "";
+        if (config.isEnableMicroService()) {
+            if (CodeGenerator.ENUM_PATH.equals(modularSuffix)
+                    || CodeGenerator.SAVE_DTO_PATH.equals(modularSuffix)
+                    || CodeGenerator.UPDATE_DTO_PATH.equals(modularSuffix)
+                    || CodeGenerator.PAGE_DTO_PATH.equals(modularSuffix)
+                    || CodeGenerator.CONSTANT_PATH.equals(modularSuffix)
+                    || CodeGenerator.QUERY_PATH.equals(modularSuffix)
+                    || ConstVal.ENTITY.equals(modularSuffix)) {
+                projectName = config.getProjectPrefix() + config.getServiceName() + projectSuffix + File.separator;
+            } else {
+                projectName = config.getProjectPrefix() + config.getChildModuleName() + projectSuffix + File.separator;
+            }
+        }
+        String basePath = String.format(innerBasePath, projectName);
+
+        String innerModularSuffix = modularSuffix;
+        if (ConstVal.SERVICE_IMPL.equals(innerModularSuffix)) {
+            innerModularSuffix = "service";
+        } else if (CodeGenerator.SAVE_DTO_PATH.equals(innerModularSuffix)) {
+            innerModularSuffix = "domain";
+        } else if (CodeGenerator.UPDATE_DTO_PATH.equals(innerModularSuffix)) {
+            innerModularSuffix = "domain";
+        } else if (CodeGenerator.PAGE_DTO_PATH.equals(innerModularSuffix)) {
+            innerModularSuffix = "domain";
+        } else if (ConstVal.MAPPER.equals(innerModularSuffix)) {
+            innerModularSuffix = "dao";
+        } else if (ConstVal.ENTITY.equals(innerModularSuffix)) {
+            innerModularSuffix = "domain";
+        } else {
+            innerModularSuffix = StringUtils.firstCharToLower(modularSuffix);
+        }
+
+        basePath = basePath + File.separator + projectSuffix.substring(1) + File.separator + innerModularSuffix;
+        if (StringUtils.isNotEmpty(config.getChildPackageName())) {
+            basePath = basePath + File.separator + config.getChildPackageName();
+        }
+        if (ConstVal.SERVICE_IMPL.equals(modularSuffix)) {
+            basePath = basePath + File.separator + "impl";
+        }
+
+        if (ConstVal.ENTITY.equals(modularSuffix)) {
+            basePath = basePath + File.separator + tableInfo.getEntityName() + StringPool.DOT_JAVA;
+        } else if (ConstVal.XML.equals(modularSuffix)) {
+            basePath = basePath + File.separator + tableInfo.getEntityName() + "DAO" + StringPool.DOT_JAVA;
+        } else if (ConstVal.MAPPER.equals(modularSuffix)) {
+            basePath = basePath + File.separator + tableInfo.getEntityName() + "DAO" + StringPool.DOT_JAVA;
+        } else if (CodeGenerator.QUERY_PATH.equals(modularSuffix)) {
+            basePath = basePath + File.separator + tableInfo.getEntityName() + "Wrapper" + StringPool.DOT_JAVA;
+        } else {
+            basePath = basePath + File.separator + tableInfo.getEntityName() + modularSuffix + StringPool.DOT_JAVA;
+        }
+
+        if (GenerateType.ADD.eq(generateType) && FileCreateConfig.isExists(basePath)) {
+            basePath += ".new";
+        }
+        return basePath;
+    }
+}

+ 426 - 0
src/main/java/com/zkthink/ceres/generator/ext/FreemarkerTemplateEngineExt.java

@@ -0,0 +1,426 @@
+package com.zkthink.ceres.generator.ext;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.generator.config.FileOutConfig;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+import com.baomidou.mybatisplus.generator.config.po.TableField;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.FileType;
+import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
+import com.baomidou.mybatisplus.generator.engine.BeetlTemplateEngine;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+import com.zkthink.ceres.generator.CodeGenerator;
+import com.zkthink.ceres.generator.config.CodeGeneratorConfig;
+import com.zkthink.ceres.generator.config.FileCreateConfig;
+import com.zkthink.ceres.generator.model.GenTableColumn;
+import com.zkthink.ceres.generator.type.EntityFiledType;
+import com.zkthink.ceres.generator.type.GenerateType;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+
+/**
+ * 扩展 {@link BeetlTemplateEngine}
+ * 便于我们加入我们自己的模板
+ *
+ * @author ceres
+ */
+public class FreemarkerTemplateEngineExt extends FreemarkerTemplateEngine {
+
+    /**
+     * 注入字段 正则
+     * 匹配: @InjectionField(api="", method="") RemoteData<Long, Org>
+     * 匹配: @InjectionField(api="", method="" beanClass=Xxx.class)
+     * 匹配: @InjectionField(api="orgApi", method="findXx" beanClass=Org.class) RemoteData<Long, com.xx.xx.Org>
+     * 匹配: @InjectionField(feign=OrgApi.class, method="findXx" beanClass=Org.class) RemoteData<Long, com.xx.xx.Org>
+     */
+    private final static Pattern INJECTION_FIELD_PATTERN = Pattern.compile("([@]InjectionField[(](api|feign)? *= *([a-zA-Z0-9\"._]+), method *= *([a-zA-Z0-9\"._]+)(, *beanClass *= *[a-zA-Z0-9._]+)?[)]){1}( *RemoteData(<[a-zA-Z0-9.]+,( *[a-zA-Z0-9.]+)>)?)*");
+
+    /**
+     * 枚举类 正则
+     * 匹配: #{xxxx} 形式的注释
+     */
+    public final static String REG_EX_VAL = "#(.*?\\{(.*?)?\\})";
+    /**
+     * 枚举类型 正则
+     * 匹配 xx:xx; 形式的注释
+     */
+    public final static String REG_EX_KEY = "([A-Za-z1-9_-]+):(.*?)?;";
+
+    private CodeGeneratorConfig config;
+
+    public FreemarkerTemplateEngineExt(CodeGeneratorConfig config) {
+        this.config = config;
+    }
+
+
+    /**
+     * 扩展父类    增加生成enum的代码。
+     */
+    @Override
+    public AbstractTemplateEngine batchOutput() {
+        ConfigBuilder cb = getConfigBuilder();
+
+        //生成枚举
+        try {
+            List<TableInfo> tableInfoList = getConfigBuilder().getTableInfoList();
+            for (TableInfo tableInfo : tableInfoList) {
+                tableInfo.getFields().forEach(filed -> {
+                    try {
+                        generateEnum(tableInfo, filed);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                });
+            }
+        } catch (Exception e) {
+            logger.error("无法创建文件,请检查配置信息!", e);
+        }
+        List<TableInfo> tableList = cb.getTableInfoList();
+
+
+        CodeGeneratorConfig.Vue vue = config.getVue();
+        Map<String, Map<String, GenTableColumn>> tableFieldMap = vue.getTableFieldMap();
+        //构造实体中的枚举类型字段
+        tableList.forEach(t -> {
+            t.getFields().forEach(field -> {
+                Map<String, Object> customMap = field.getCustomMap();
+                if (customMap == null) {
+                    customMap = new HashMap<>();
+                }
+                Map<String, GenTableColumn> fieldMap = tableFieldMap.get(t.getName());
+                if (CollUtil.isNotEmpty(fieldMap)) {
+                    GenTableColumn genFiled = fieldMap.get(field.getName());
+                    if(genFiled!= null) {
+                        customMap.put("info", genFiled);
+                    }
+                }
+                field.setCustomMap(customMap);
+
+                build(t, field);
+                buildInjectionField(t, field);
+            });
+        });
+
+
+        //生成实体
+        List<FileOutConfig> focList = new ArrayList<>();
+        if (!config.getFileCreateConfig().getIsVue()) {
+            StringBuilder basePathSb = getBasePath();
+            String packageBase = config.getPackageBase().replace(".", File.separator);
+            basePathSb.append(File.separator).append(packageBase);
+            config.setCurrentModule("commons");
+            focList.add(new FileOutConfigExt(basePathSb.toString(), ConstVal.ENTITY, config));
+        }
+
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                Map<String, Object> map = CodeGenerator.initImportPackageInfo(config.getPackageBase(), config.getChildPackageName());
+
+                //这里必须 在entity生成后,赋值
+                map.put("filedTypes", config.getFiledTypes());
+                this.setMap(map);
+            }
+
+            @Override
+            public void initTableMap(TableInfo tableInfo) {
+                this.initMap();
+            }
+        };
+
+        cfg.setFileCreate(cb.getInjectionConfig().getFileCreate());
+        if (cb.getInjectionConfig().getFileOutConfigList() != null
+                && !cb.getInjectionConfig().getFileOutConfigList().isEmpty()) {
+            cb.getInjectionConfig().getFileOutConfigList().addAll(focList);
+            cfg.setFileOutConfigList(cb.getInjectionConfig().getFileOutConfigList());
+        } else {
+            cfg.setFileOutConfigList(focList);
+        }
+        cfg.setConfig(cb.getInjectionConfig().getConfig());
+
+        cb.setInjectionConfig(cfg);
+
+
+        //执行mybatis plus的代码生成器
+        super.batchOutput();
+
+        return this;
+    }
+
+
+    private static String trim(String val) {
+        return val == null ? StringPool.EMPTY : val.trim();
+    }
+
+
+    public static void main(String[] args) {
+        String comment = "@InjectionField(api=\"xxxx\", method=\"bbbbb\", beanClass=1) RemoteData<Long, Org>";
+//        String comment = "@InjectionField(feign=FreemarkerTemplateEngineExt.class, method=\"bbbbb\"   beanClass=  Xxx.class) RemoteData<Long, Org>";
+        Matcher matcher = INJECTION_FIELD_PATTERN.matcher(comment);
+        if (matcher.find()) {
+            String annotation = trim(matcher.group(1)); //@InjectionField(api="xxxx", method="bbbbb")
+            String api = trim(matcher.group(3)); //xxxx
+            String method = trim(matcher.group(4));  //bbbbb
+            String type = trim(matcher.group(6)); //RemoteData<Long, Org>
+            // 5 <Long, Org>
+            String typePackage = trim(matcher.group(8)); //Org
+            System.out.println(111);
+        }
+    }
+
+
+    /**
+     * 生成 需要注入 类型的字段
+     *
+     * @param table
+     * @param field
+     */
+    private void buildInjectionField(TableInfo table, TableField field) {
+        //注释
+        String comment = field.getComment();
+        if (comment == null) {
+            return;
+        }
+        Set<String> importPackages = table.getImportPackages();
+        importPackages.remove("com.zkthink.base.entity.Entity");
+        Matcher matcher = INJECTION_FIELD_PATTERN.matcher(comment);
+        if (matcher.find()) {
+            String annotation = trim(matcher.group(1));
+            String api = trim(matcher.group(3));
+            String method = trim(matcher.group(4));
+            String type = trim(matcher.group(6));
+            String typePackage = trim(matcher.group(8));
+
+            if (StrUtil.isNotEmpty(type) && StrUtil.contains(typePackage, ".")) {
+                String data = StrUtil.subAfter(typePackage, ".", true);
+                if (StrUtil.isNotEmpty(data)) {
+                    type = StrUtil.replace(type, typePackage, data);
+                }
+            }
+
+            field.getCustomMap().put("annotation", annotation);
+//            field.getCustomMap().put("api", api);
+//            field.getCustomMap().put("method", method);
+            field.getCustomMap().put("type", type);
+//            field.getCustomMap().put("type", type);
+
+            if (!api.contains("\"")) {
+                if (api.contains(".")) {
+                    if (api.endsWith("class")) {
+                        // 导入feign class
+                        importPackages.add(StrUtil.subBefore(api, ".", true));
+
+
+                    } else {
+                        importPackages.add("com.zkthink.common.constant.InjectionFieldConstants");
+                    }
+                } else {
+                    importPackages.add(String.format("static com.zkthink.common.constant.InjectionFieldConstants.%s", api));
+                }
+            }
+            if (!method.contains("\"")) {
+                if (method.contains(".")) {
+                    importPackages.add("com.zkthink.common.constant.InjectionFieldConstants");
+                } else {
+                    importPackages.add(String.format("static com.zkthink.common.constant.InjectionFieldConstants.%s", method));
+                }
+            }
+            if (typePackage.contains(".")) {
+                importPackages.add(typePackage);
+            }
+            importPackages.add("com.zkthink.injection.annonation.InjectionField");
+            importPackages.add("com.zkthink.model.RemoteData");
+        }
+    }
+
+    /**
+     * 生成枚举类型类
+     *
+     * @throws Exception
+     */
+    private void generateEnum(TableInfo tableInfo, TableField field) throws Exception {
+        String comment = field.getComment();
+        if (StringUtils.isBlank(comment) || !comment.contains("{") || !comment.contains("}") || !comment.contains(";")) {
+            return;
+        }
+        // 排除boolean类型值
+        if (Boolean.class.getSimpleName().equals(field.getColumnType().getType())) {
+            return;
+        }
+        String propertyName = field.getPropertyName();
+        Set<EntityFiledType> filedTypes = config.getFiledTypes();
+
+        Map<String, Object> objectMap = getObjectMap(tableInfo);
+        Map<String, String> packageInfo = (Map) objectMap.get("package");
+        String entityPackage = packageInfo.get("Entity");
+
+        String defEnumPackage = entityPackage.replaceAll("entity", "enumeration");
+
+        String enumName = comment.substring(comment.indexOf(StringPool.HASH) + 1, comment.indexOf(StringPool.LEFT_BRACE));
+        if ("".equals(enumName)) {
+            enumName = tableInfo.getEntityName() + (Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1)) + "Enum";
+        }
+        String finalEnumName = enumName;
+        List<EntityFiledType> collect = filedTypes.stream().filter((filed) -> filed.getType().equals(finalEnumName)).collect(Collectors.toList());
+        EntityFiledType entityFiledType = EntityFiledType.builder()
+                .name(field.getPropertyName()).packagePath(defEnumPackage + "." + enumName).gen(GenerateType.OVERRIDE)
+                .build();
+        if (!collect.isEmpty()) {
+            entityFiledType = collect.get(0);
+        }
+
+        String firstTypeNumber = "true";
+        Map<String, List<String>> allFields = new LinkedHashMap<>();
+        if (comment.contains(StringPool.HASH) && comment.contains(StringPool.RIGHT_BRACE)) {
+            String enumComment = comment.substring(comment.indexOf(StringPool.HASH), comment.indexOf(StringPool.RIGHT_BRACE) + 1);
+            // 编译正则表达式
+            Pattern pattern = Pattern.compile(REG_EX_VAL);
+            Matcher matcher = pattern.matcher(enumComment);
+            while (matcher.find()) {
+                String val = matcher.group(2);
+                if (!val.endsWith(";")) {
+                    val += ";";
+                }
+
+                Pattern keyPattern = Pattern.compile(REG_EX_KEY);
+                Matcher keyMatcher = keyPattern.matcher(val);
+
+                while (keyMatcher.find()) {
+                    String key = keyMatcher.group(1);
+                    String value = keyMatcher.group(2);
+
+                    List<String> subList = new ArrayList<>();
+                    if (value.contains(",")) {
+                        String[] split = value.split(StringPool.COMMA);
+                        subList = Arrays.asList(split);
+                        try {
+                            Integer.valueOf(split[0]);
+                        } catch (Exception e) {
+                            //字符串
+                            firstTypeNumber = "false";
+                        }
+
+                    } else {
+                        try {
+                            Integer.valueOf(value);
+                        } catch (Exception e) {
+                            //字符串
+                            firstTypeNumber = "false";
+                        }
+                        subList.add(value);
+                    }
+
+                    allFields.put(key, subList);
+                }
+
+            }
+        }
+
+
+        Map<String, Object> enumCustom = new HashMap<>();
+        enumCustom.put("package", entityFiledType);
+        enumCustom.put("enumName", enumName);
+
+        enumCustom.put("comment", StringUtils.substring(comment, 0, comment.indexOf("\n")).trim());
+        enumCustom.put("firstTypeNumber", firstTypeNumber);
+        enumCustom.put("list", allFields);
+        enumCustom.put("filedTypes", filedTypes);
+
+        objectMap.put("enumCustom", enumCustom);
+
+        field.getCustomMap().put("enumCustom", enumCustom);
+
+        StringBuilder basePathSb = getBasePath();
+        System.out.println("basePathSb: " + basePathSb);
+        basePathSb.append(File.separator).append(entityFiledType.getPath())
+                .append(".java");
+
+
+        Map<String, Object> customMap = field.getCustomMap();
+        if (customMap == null) {
+            customMap = new HashMap<>();
+        }
+        customMap.put("isEnum", "1");
+        field.setCustomMap(customMap);
+
+        FileCreateConfig fileCreateConfig = config.getFileCreateConfig();
+        if (GenerateType.ADD.eq(fileCreateConfig.getGenerateEnum())
+                && FileCreateConfig.isExists(basePathSb.toString())) {
+            basePathSb.append(".new");
+        }
+
+        if (isCreate(FileType.OTHER, basePathSb.toString()) && GenerateType.IGNORE.neq(entityFiledType.getGen())) {
+            writer(objectMap, templateFilePath("/templates/enum.java"), basePathSb.toString());
+        }
+
+    }
+
+
+    private StringBuilder getBasePath() {
+        String projectRootPath = config.getProjectRootPath();
+        if (!projectRootPath.endsWith(File.separator)) {
+            projectRootPath += File.separator;
+        }
+
+        StringBuilder basePathSb = new StringBuilder(projectRootPath);
+        basePathSb.append(config.getProjectPrefix()).append(config.getServiceName())
+                .append(config.getEntitySuffix()).append(File.separator)
+                .append(CodeGenerator.SRC_MAIN_JAVA);
+
+
+        return basePathSb;
+    }
+
+
+    /**
+     * 生成实体类中字段的 枚举类型
+     *
+     * @param tableInfo
+     * @param field
+     */
+    private void build(TableInfo tableInfo, TableField field) {
+        String comment = field.getComment();
+        String entityName = tableInfo.getEntityName();
+        String propertyName = field.getPropertyName();
+        if (StringUtils.isBlank(comment) || !comment.contains(StringPool.LEFT_BRACE)
+                || !comment.contains(StringPool.RIGHT_BRACE) || !comment.contains(StringPool.SEMICOLON)) {
+            return;
+        }
+        // 排除boolean类型值
+        if (Boolean.class.getSimpleName().equals(field.getColumnType().getType())) {
+            return;
+        }
+
+        String enumName = comment.substring(comment.indexOf(StringPool.HASH) + 1, comment.indexOf(StringPool.LEFT_BRACE));
+        if (StringPool.EMPTY.equals(enumName)) {
+            enumName = entityName + (Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1)) + "Enum";
+        }
+
+        Set<EntityFiledType> filedTypes = config.getFiledTypes();
+
+        EntityFiledType cur = EntityFiledType.builder().name(propertyName).table(tableInfo.getName()).build();
+        if (!filedTypes.contains(cur)) {
+            ConfigBuilder configBuilder = getConfigBuilder();
+            Map<String, String> packageInfo = configBuilder.getPackageInfo();
+            String entityPackage = packageInfo.get("Entity");
+            String defEnumPackage = entityPackage.replaceAll("entity", "enumeration");
+
+            filedTypes.add(EntityFiledType.builder()
+                    .name(propertyName)
+                    .packagePath(defEnumPackage + "." + enumName)
+                    .table(tableInfo.getName())
+                    .gen(config.getFileCreateConfig().getGenerateEnum())
+                    .build());
+        }
+    }
+}

+ 16 - 0
src/main/java/com/zkthink/ceres/generator/ext/MySqlQueryExt.java

@@ -0,0 +1,16 @@
+package com.zkthink.ceres.generator.ext;
+
+import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
+
+/**
+ * 扩展 {@link MySqlQuery}  方便加入sql查询表元数据信息 增加自定义列,辅助我们的检验器的自动生成
+ *
+ * @author ceres
+ */
+public class MySqlQueryExt extends MySqlQuery {
+
+    @Override
+    public String[] fieldCustom() {
+        return new String[]{"Null", "Default", "Collation"};
+    }
+}

+ 32 - 0
src/main/java/com/zkthink/ceres/generator/ext/OracleQueryExt.java

@@ -0,0 +1,32 @@
+package com.zkthink.ceres.generator.ext;
+
+import com.baomidou.mybatisplus.generator.config.querys.OracleQuery;
+
+/**
+ * 扩展 {@link OracleQuery}  方便加入sql查询表元数据信息 增加自定义列,辅助我们的检验器的自动生成
+ *
+ * @author ceres
+ * @date 2020年01月19日10:23:23
+ */
+public class OracleQueryExt extends OracleQuery {
+
+    @Override
+    public String[] fieldCustom() {
+        return new String[]{"NULLABLE", "DATA_SCALE"};
+    }
+
+    @Override
+    public String tableFieldsSql() {
+        return "SELECT A.COLUMN_NAME, CASE WHEN A.DATA_TYPE='NUMBER' THEN "
+                + "(CASE WHEN A.DATA_PRECISION IS NULL THEN A.DATA_TYPE "
+                + "WHEN NVL(A.DATA_SCALE, 0) > 0 THEN A.DATA_TYPE||'('||A.DATA_PRECISION||','||A.DATA_SCALE||')' "
+                + "ELSE A.DATA_TYPE||'('||A.DATA_PRECISION||')' END) "
+                + "ELSE A.DATA_TYPE END DATA_TYPE, B.COMMENTS,DECODE(C.POSITION, '1', 'PRI') KEY "
+                + ", A.NULLABLE, A.DATA_SCALE "
+                + "FROM ALL_TAB_COLUMNS A "
+                + " INNER JOIN ALL_COL_COMMENTS B ON A.TABLE_NAME = B.TABLE_NAME AND A.COLUMN_NAME = B.COLUMN_NAME AND B.OWNER = '#schema'"
+                + " LEFT JOIN ALL_CONSTRAINTS D ON D.TABLE_NAME = A.TABLE_NAME AND D.CONSTRAINT_TYPE = 'P' AND D.OWNER = '#schema'"
+                + " LEFT JOIN ALL_CONS_COLUMNS C ON C.CONSTRAINT_NAME = D.CONSTRAINT_NAME AND C.COLUMN_NAME=A.COLUMN_NAME AND C.OWNER = '#schema'"
+                + "WHERE A.OWNER = '#schema' AND A.TABLE_NAME = '%s' ORDER BY A.COLUMN_ID ";
+    }
+}

+ 140 - 0
src/main/java/com/zkthink/ceres/generator/model/GenTableColumn.java

@@ -0,0 +1,140 @@
+package com.zkthink.ceres.generator.model;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+/**
+ * 代码生成业务字段表
+ *
+ * @author ceres
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@ToString
+@Accessors(chain = true)
+public class GenTableColumn {
+    public static final String YES = "1";
+    public static final String NO = "0";
+    private static final long serialVersionUID = 1L;
+    /**
+     * 归属表 自动计算
+     */
+    private String tableName;
+
+    /**
+     * 列名称 自动计算
+     */
+    private String name;
+
+    /**
+     * 列描述 自动计算
+     */
+    private String columnComment;
+
+    /**
+     * 列类型 自动计算
+     */
+    private String type;
+
+    /**
+     * JAVA类型 自动计算
+     */
+    private String propertyType;
+
+    /**
+     * JAVA字段名 自动计算
+     */
+    private String javaField;
+    /**
+     * Index页面 Table 的列宽度
+     *
+     * @since 2.0 支持
+     */
+    private String width;
+
+    /**
+     * 是否必填(1是) 为空时自动计算 暂时不支持
+     */
+    private String isRequired;
+
+    /**
+     * 是否为插入字段(1是) 为空时自动计算
+     *
+     * @since 2.0 支持
+     */
+    private String isInsert;
+
+    /**
+     * 是否编辑字段(1是) 为空时自动计算
+     *
+     * @since 2.0 支持
+     */
+    private String isEdit;
+
+    /**
+     * 是否列表字段(1是)为空时自动计算
+     *
+     * @since 2.0 支持
+     */
+    private String isList;
+
+    /**
+     * 是否查询字段(1是) 为空时自动计算
+     *
+     * @since 2.0 支持
+     */
+    private String isQuery;
+
+    /**
+     * 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围)  暂时不支持
+     */
+    private String queryType;
+
+    /**
+     * 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件) 为空时自动计算
+     *
+     * @since 2.0 支持
+     */
+    private String htmlType;
+
+    /**
+     * 字典类型
+     *
+     * @since 2.0 支持
+     */
+    private String dictType;
+    /**
+     * 枚举类型
+     *
+     * @since 2.0 支持
+     */
+    private String enumType;
+
+    public GenTableColumn() {
+    }
+
+    /**
+     * 因为前段新增和报错共用一个页面,所以目前 isInsert 和 isEdit 必须都为0才不会显示在编辑页面
+     *
+     * @param name     字段名
+     * @param isInsert 是否显示在新增页面 1/0 空字符串就自动计算
+     * @param isEdit   是否显示在修改页面 1/0 空字符串就自动计算
+     * @param isList   是否显示在分页列表 1/0 空字符串就自动计算
+     * @param isQuery  是否显示在分页查询条件 1/0 空字符串就自动计算
+     * @param htmlType 输入框的类型   见: HtmlType
+     */
+    public GenTableColumn(String name, String isInsert, String isEdit, String isList, String isQuery, String htmlType) {
+        this.name = name;
+        this.isInsert = isInsert;
+        this.isEdit = isEdit;
+        this.isList = isList;
+        this.isQuery = isQuery;
+        this.htmlType = htmlType;
+    }
+
+}

+ 76 - 0
src/main/java/com/zkthink/ceres/generator/type/EntityFiledType.java

@@ -0,0 +1,76 @@
+package com.zkthink.ceres.generator.type;
+
+
+import java.io.File;
+
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 实体字段类型
+ *
+ * @author ceres
+ * @date 2019/05/14
+ */
+@Data
+@Builder
+@ToString
+@EqualsAndHashCode(of = {"name", "table"})
+public class EntityFiledType {
+    /**
+     * 枚举类型的字段名(不是数据库字段哦!!!)
+     */
+    private String name;
+    /**
+     * 枚举类型的完整包路径 eg: com.xx.xx.Type
+     */
+    private String packagePath = "";
+    /**
+     * 表名
+     */
+    private String table = "";
+
+    /**
+     * 是否生成
+     */
+    private GenerateType gen = GenerateType.OVERRIDE;
+
+    /**
+     * 枚举类型的完整路径,会根据 packagePath 自动解析
+     */
+    private String path;
+    /**
+     * 导包
+     */
+    private String importPackage;
+    /**
+     * 枚举类型: 会根据 packagePath 自动解析
+     */
+    private String type;
+
+    public String getPath() {
+        if (packagePath != null && !"".equals(packagePath)) {
+            this.path = packagePath.replace(".", File.separator);
+        }
+        return path;
+    }
+
+    public String getType() {
+        if (packagePath != null && !"".equals(packagePath)) {
+            this.type = packagePath.substring(packagePath.lastIndexOf(".") + 1);
+        }
+        return type;
+    }
+
+    public String getImportPackage() {
+        if (this.importPackage == null || "".equals(this.importPackage)) {
+            this.importPackage = StringUtils.substring(packagePath, 0, packagePath.lastIndexOf("."));
+        }
+        return this.importPackage;
+    }
+
+}
+

+ 53 - 0
src/main/java/com/zkthink/ceres/generator/type/EntityType.java

@@ -0,0 +1,53 @@
+package com.zkthink.ceres.generator.type;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 父类实体类型
+ *
+ * @author ceres
+ * @date 2019/05/14
+ */
+@Getter
+@AllArgsConstructor
+public enum EntityType {
+    /**
+     * 只有id
+     */
+    SUPER_ENTITY("com.zkthink.base.entity.SuperEntity", new String[]{"id", "tenant_code", "create_time", "create_user"}),
+    /**
+     * 有创建人创建时间等
+     */
+    ENTITY("com.zkthink.base.entity.Entity", new String[]{}),
+
+    /**
+     * 树形实体
+     */
+    TREE_ENTITY("com.zkthink.base.entity.TreeEntity", new String[]{"id", "tenant_code", "create_time", "create_user", "update_time", "update_user", "label", "parent_id", "sort_value"}),
+
+    /**
+     * 不继承任何实体
+     */
+    NONE("", new String[]{""}),
+    ;
+
+    private String val;
+    private String[] columns;
+
+
+    public boolean eq(String val) {
+        if (this.name().equals(val)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean eq(EntityType val) {
+        if (val == null) {
+            return false;
+        }
+        return eq(val.name());
+    }
+
+}

+ 43 - 0
src/main/java/com/zkthink/ceres/generator/type/GenerateType.java

@@ -0,0 +1,43 @@
+package com.zkthink.ceres.generator.type;
+
+/**
+ * 生成策略
+ *
+ * @author ceres
+ * @date 2019/05/14
+ */
+public enum GenerateType {
+    /**
+     * 覆盖
+     */
+    OVERRIDE,
+    /**
+     * 新增
+     */
+    ADD,
+    /**
+     * 存在则忽略
+     */
+    IGNORE,
+    ;
+
+
+    public boolean eq(String val) {
+        if (this.name().equals(val)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean eq(GenerateType val) {
+        if (val == null) {
+            return false;
+        }
+        return eq(val.name());
+    }
+
+    public boolean neq(GenerateType val) {
+        return !eq(val);
+    }
+
+}

+ 26 - 0
src/main/java/com/zkthink/ceres/generator/type/HtmlType.java

@@ -0,0 +1,26 @@
+package com.zkthink.ceres.generator.type;
+
+public class HtmlType {
+    public static final String INPUT = "input";
+    public static final String TEXTAREA = "textarea";
+    public static final String SELECT = "select";
+    /**
+     * 不支持
+     *
+     * @since 2.0 不支持
+     */
+    public static final String SELECT_USER = "select_user";
+    /**
+     * 不支持
+     *
+     * @since 2.0 不支持
+     */
+    public static final String SELECT_ORG = "select_org";
+    public static final String RADIO = "radio";
+    public static final String RADIO_BUTTON = "radio-button";
+    public static final String SWITCH = "switch";
+    public static final String CHECKBOX = "checkbox";
+    public static final String CHECKBOX_BUTTON = "checkbox-button";
+    public static final String DATE_PICKER = "date-picker";
+    public static final String DATE_TIME_PICKER = "datetime-picker";
+}

+ 42 - 0
src/main/java/com/zkthink/ceres/generator/type/SuperClass.java

@@ -0,0 +1,42 @@
+package com.zkthink.ceres.generator.type;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public enum SuperClass {
+
+    SUPER_CLASS("com.zkthink.base.controller.SuperController", "com.zkthink.base.service.SuperService",
+            "com.zkthink.base.service.SuperServiceImpl", "com.baomidou.mybatisplus.core.mapper.BaseMapper"),
+    SUPER_CACHE_CLASS("com.zkthink.base.controller.SuperCacheController", "com.zkthink.base.service.SuperCacheService",
+            "com.zkthink.base.service.SuperCacheServiceImpl", "com.baomidou.mybatisplus.core.mapper.BaseMapper"),
+    NONE("", "", "", "");
+
+    private String controller;
+    private String service;
+    private String serviceImpl;
+    private String mapper;
+
+    public SuperClass setController(String controller) {
+        this.controller = controller;
+        return this;
+    }
+
+    public SuperClass setService(String service) {
+        this.service = service;
+        return this;
+    }
+
+    public SuperClass setMapper(String mapper) {
+        this.mapper = mapper;
+        return this;
+    }
+
+    public SuperClass setServiceImpl(String serviceImpl) {
+        this.serviceImpl = serviceImpl;
+        return this;
+    }
+}

+ 55 - 0
src/main/resources/init/java/Application.java.ftl

@@ -0,0 +1,55 @@
+package ${packageBaseParent};
+
+import com.zkthink.security.annotation.EnableLoginArgResolver;
+import com.zkthink.validator.config.EnableFormValidator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+<#if packageBaseParent != "com.zkthink">
+import org.springframework.context.annotation.ComponentScan;
+</#if>
+import org.springframework.core.env.Environment;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * ${description}启动类
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@SpringBootApplication
+@EnableDiscoveryClient
+@Configuration
+<#if packageBaseParent != "com.zkthink">
+@EnableFeignClients(value = { "${packageBaseParent}", "com.zkthink" })
+@ComponentScan(basePackages = {"${packageBaseParent}", "com.zkthink"})
+<#else>
+@EnableFeignClients(value = { "${packageBaseParent}" })
+</#if>
+@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
+@Slf4j
+@EnableLoginArgResolver
+@EnableFormValidator
+public class ${service}ServerApplication {
+    public static void main(String[] args) throws UnknownHostException {
+        ConfigurableApplicationContext application = SpringApplication.run(${service}ServerApplication.class, args);
+        Environment env = application.getEnvironment();
+        log.info("\n----------------------------------------------------------\n\t" +
+                        "应用 '{}' 启动成功! 访问连接:\n\t" +
+                        "Swagger文档: \t\thttp://{}:{}/doc.html\n\t" +
+                        "数据库监控: \t\thttp://{}:{}/druid\n" +
+                        "----------------------------------------------------------",
+                env.getProperty("spring.application.name"),
+                InetAddress.getLocalHost().getHostAddress(),
+                env.getProperty("server.port"),
+                "127.0.0.1",
+                env.getProperty("server.port"));
+    }
+}

+ 123 - 0
src/main/resources/init/java/DatabaseAutoConfiguration.java.ftl

@@ -0,0 +1,123 @@
+package ${packageBase}.config.datasource;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
+import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
+import com.zkthink.database.datasource.BaseDatabaseConfiguration;
+import com.zkthink.database.properties.DatabaseProperties;
+import com.p6spy.engine.spy.P6DataSource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.mapping.DatabaseIdProvider;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.scripting.LanguageDriver;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.type.TypeHandler;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.stereotype.Repository;
+
+import javax.sql.DataSource;
+import java.util.List;
+
+/**
+ * ceres.database.multiTenantType != DATASOURCE 时,该类启用.
+ * 此时,项目的多租户模式切换成:${r"${ceres.database.multiTenantType}"}。
+ * <p>
+ * NONE("非租户模式"): 不存在租户的概念
+ * COLUMN("字段模式"): 在sql中拼接 tenant_code 字段
+ * SCHEMA("独立schema模式"): 在sql中拼接 数据库 schema
+ * <p>
+ * COLUMN和SCHEMA模式的实现 参考下面的 @see 中的3个类
+ *
+ * @author ${author}
+ * @date ${date}
+ * 断点查看原理:👇👇👇
+ * @see com.zkthink.database.datasource.BaseMybatisConfiguration#paginationInterceptor()
+ * @see com.zkthink.database.servlet.TenantContextHandlerInterceptor
+ * @see com.zkthink.database.parsers.DynamicTableNameParser
+*/
+@Configuration
+@Slf4j
+@MapperScan(
+        basePackages = { "${packageBaseParent}", <#if packageBaseParent != "com.zkthink">"com.zkthink"</#if>}, annotationClass = Repository.class,
+        sqlSessionFactoryRef = ${service}DatabaseAutoConfiguration.DATABASE_PREFIX + "SqlSessionFactory")
+@EnableConfigurationProperties({MybatisPlusProperties.class})
+@ConditionalOnExpression("!'DATASOURCE'.equals('${r"${ceres.database.multiTenantType}"}')")
+public class ${service}DatabaseAutoConfiguration extends BaseDatabaseConfiguration {
+    /**
+     * 每个数据源配置不同即可
+     */
+    final static String DATABASE_PREFIX = "master";
+
+    public ${service}DatabaseAutoConfiguration(MybatisPlusProperties properties,
+                                              DatabaseProperties databaseProperties,
+                                              ObjectProvider${r"<Interceptor[]>"} interceptorsProvider,
+                                              ObjectProvider${r"<TypeHandler[]>"} typeHandlersProvider,
+                                              ObjectProvider${r"<LanguageDriver[]>"} languageDriversProvider,
+                                              ResourceLoader resourceLoader,
+                                              ObjectProvider${r"<DatabaseIdProvider>"} databaseIdProvider,
+                                              ObjectProvider${r"<List<ConfigurationCustomizer>>"} configurationCustomizersProvider,
+                                              ObjectProvider${r"<List<MybatisPlusPropertiesCustomizer>>"} mybatisPlusPropertiesCustomizerProvider,
+                                              ApplicationContext applicationContext) {
+        super(properties, databaseProperties, interceptorsProvider, typeHandlersProvider,
+                languageDriversProvider, resourceLoader, databaseIdProvider,
+                configurationCustomizersProvider, mybatisPlusPropertiesCustomizerProvider, applicationContext);
+        log.debug("检测到 ceres.database.multiTenantType!=DATASOURCE,加载了 ${service}DatabaseAutoConfiguration");
+    }
+
+    @Bean(DATABASE_PREFIX + "SqlSessionTemplate")
+    public SqlSessionTemplate getSqlSessionTemplate(@Qualifier(DATABASE_PREFIX + "SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
+        ExecutorType executorType = this.properties.getExecutorType();
+        if (executorType != null) {
+            return new SqlSessionTemplate(sqlSessionFactory, executorType);
+        } else {
+            return new SqlSessionTemplate(sqlSessionFactory);
+        }
+    }
+
+    /**
+     * 数据源信息
+     *
+     * @return
+     */
+    @Primary
+    @Bean(name = DATABASE_PREFIX + "DruidDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.druid")
+    public DataSource druidDataSource() {
+        return DruidDataSourceBuilder.create().build();
+    }
+
+    @Bean(name = DATABASE_PREFIX + "DataSource")
+    public DataSource dataSource(@Qualifier(DATABASE_PREFIX + "DruidDataSource") DataSource dataSource) {
+        if (ArrayUtil.contains(DEV_PROFILES, this.profiles)) {
+            return new P6DataSource(dataSource);
+        } else {
+            return dataSource;
+        }
+    }
+
+    /**
+     * mybatis Sql Session 工厂
+     *
+     * @return
+     * @throws Exception
+     */
+    @Bean(DATABASE_PREFIX + "SqlSessionFactory")
+    public SqlSessionFactory getSqlSessionFactory(@Qualifier(DATABASE_PREFIX + "DataSource") DataSource dataSource) throws Exception {
+        return super.sqlSessionFactory(dataSource);
+    }
+
+}

+ 20 - 0
src/main/resources/init/java/ExceptionConfiguration.java.ftl

@@ -0,0 +1,20 @@
+package ${packageBase}.config;
+
+import com.zkthink.boot.handler.DefaultGlobalExceptionHandler;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * ${description}-全局异常处理
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Configuration
+@ControllerAdvice(annotations = {RestController.class, Controller.class})
+@ResponseBody
+public class ${service}ExceptionConfiguration extends DefaultGlobalExceptionHandler {
+}

+ 43 - 0
src/main/resources/init/java/MybatisAutoConfiguration.java.ftl

@@ -0,0 +1,43 @@
+package ${packageBase}.config.datasource;
+
+
+import com.zkthink.oauth.api.UserApi;
+import com.zkthink.database.datasource.BaseMybatisConfiguration;
+import com.zkthink.database.mybatis.auth.DataScopeInterceptor;
+import com.zkthink.database.properties.DatabaseProperties;
+import com.zkthink.utils.SpringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+
+/**
+ * ${description}-Mybatis 常用重用拦截器
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Configuration
+@Slf4j
+@EnableConfigurationProperties({DatabaseProperties.class})
+public class ${service}MybatisAutoConfiguration extends BaseMybatisConfiguration {
+
+    public ${service}MybatisAutoConfiguration(DatabaseProperties databaseProperties) {
+        super(databaseProperties);
+    }
+
+    /**
+     * 数据权限插件
+     *
+     * @return DataScopeInterceptor
+     */
+    @Order(10)
+    @Bean
+    @ConditionalOnProperty(prefix = DatabaseProperties.PREFIX, name = "isDataScope", havingValue = "true", matchIfMissing = true)
+    public DataScopeInterceptor dataScopeInterceptor() {
+        return new DataScopeInterceptor((userId) -> SpringUtils.getBean(UserApi.class).getDataScopeById(userId));
+    }
+
+}

+ 30 - 0
src/main/resources/init/java/WebConfiguration.java.ftl

@@ -0,0 +1,30 @@
+package ${packageBase}.config;
+
+import com.zkthink.boot.config.BaseConfig;
+import org.springframework.context.annotation.Configuration;
+import com.zkthink.oauth.api.LogApi;
+import com.zkthink.log.event.SysLogListener;
+import org.springframework.context.annotation.Bean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+
+/**
+ * ${description}-Web配置
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Configuration
+public class ${service}WebConfiguration extends BaseConfig {
+
+    /**
+    * ceres.log.enabled = true 并且 ceres.log.type=DB时实例该类
+    *
+    * @param optLogService
+    * @return
+    */
+    @Bean
+    @ConditionalOnExpression("${r'${'}ceres.log.enabled:true${r'}'} && 'DB'.equals('${r'${'}ceres.log.type:LOGGER${r'}'}')")
+    public SysLogListener sysLogListener(LogApi logApi) {
+        return new SysLogListener((log) -> logApi.save(log));
+    }
+}

+ 46 - 0
src/main/resources/init/pom/api.java.ftl

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>${projectPrefix}${serviceName}</artifactId>
+        <groupId>${groupId}</groupId>
+        <version>${version}</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>${projectPrefix}${serviceName}-api</artifactId>
+    <name>${r"${"}project.artifactId${r"}"}</name>
+    <description>${description}-FeignApi模块</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <artifactId>${projectPrefix}${serviceName}-entity</artifactId>
+            <version>${r"${"}ceres-project.version${r"}"}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+    </dependencies>
+</project>

+ 61 - 0
src/main/resources/init/pom/biz.java.ftl

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>${projectPrefix}${serviceName}</artifactId>
+        <groupId>${groupId}</groupId>
+        <version>${version}</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <#if isChildModule>
+    <artifactId>${projectPrefix}${childModuleName}-biz</artifactId>
+    <#else>
+    <artifactId>${projectPrefix}${serviceName}-biz</artifactId>
+    </#if>
+    <name>${r"${"}project.artifactId${r"}"}</name>
+    <description>${description}-业务模块</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <artifactId>${projectPrefix}${serviceName}-entity</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <artifactId>${projectPrefix}oauth-api</artifactId>
+            <version>${r"${"}ceres-project.version${r"}"}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-databases</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-dozer-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-j2cache-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-boot</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 42 - 0
src/main/resources/init/pom/controller.java.ftl

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>${projectPrefix}${serviceName}</artifactId>
+        <groupId>${groupId}</groupId>
+        <version>${version}</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <#if isChildModule>
+    <artifactId>${projectPrefix}${childModuleName}-controller</artifactId>
+    <#else>
+    <artifactId>${projectPrefix}${serviceName}-controller</artifactId>
+    </#if>
+    <name>${r"${"}project.artifactId${r"}"}</name>
+    <description>${description}-控制器模块</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <#if isChildModule>
+            <artifactId>${projectPrefix}${childModuleName}-biz</artifactId>
+            <#else>
+            <artifactId>${projectPrefix}${serviceName}-biz</artifactId>
+            </#if>
+        </dependency>
+
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-security-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-log-starter</artifactId>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 41 - 0
src/main/resources/init/pom/entity.java.ftl

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>${projectPrefix}${serviceName}</artifactId>
+        <groupId>${groupId}</groupId>
+        <version>${version}</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>${projectPrefix}${serviceName}-entity</artifactId>
+    <name>${r"${"}project.artifactId${r"}"}</name>
+    <description>${description}-实体模块</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-common</artifactId>
+            <version>${r"${"}ceres-project.version${r"}"}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-injection-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-annotation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.afterturn</groupId>
+            <artifactId>easypoi-annotation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.afterturn</groupId>
+            <artifactId>easypoi-base</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 46 - 0
src/main/resources/init/pom/pom.java.ftl

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>${groupId}</groupId>
+        <artifactId>${projectPrefix}admin-cloud</artifactId>
+        <version>${version}</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>${projectPrefix}${serviceName}</artifactId>
+    <name>${r"${"}project.artifactId${r"}"}</name>
+    <description>${description}服务</description>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>${projectPrefix}${serviceName}-api</module>
+        <module>${projectPrefix}${serviceName}-entity</module>
+        <module>${projectPrefix}${serviceName}-biz</module>
+        <module>${projectPrefix}${serviceName}-controller</module>
+        <module>${projectPrefix}${serviceName}-server</module>
+    </modules>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>${groupId}</groupId>
+                <artifactId>${projectPrefix}${serviceName}-entity</artifactId>
+                <version>${r"${"}ceres-project.version${r"}"}</version>
+            </dependency>
+            <dependency>
+                <groupId>${groupId}</groupId>
+                <artifactId>${projectPrefix}${serviceName}-biz</artifactId>
+                <version>${r"${"}ceres-project.version${r"}"}</version>
+            </dependency>
+            <dependency>
+                <groupId>${groupId}</groupId>
+                <artifactId>${projectPrefix}${serviceName}-controller</artifactId>
+                <version>${r"${"}ceres-project.version${r"}"}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+</project>

+ 127 - 0
src/main/resources/init/pom/server.java.ftl

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>${projectPrefix}${serviceName}</artifactId>
+        <groupId>${groupId}</groupId>
+        <version>${version}</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>${projectPrefix}${serviceName}-server</artifactId>
+    <name>${r"${"}project.artifactId${r"}"}</name>
+    <description>${description}-启动模块</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <artifactId>${projectPrefix}${serviceName}-controller</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-scan-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-swagger2-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-validator-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-xss-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-j2cache-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-cloud-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.zkthink</groupId>
+            <artifactId>ceres-zipkin-client-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.tomcat.embed</groupId>
+                    <artifactId>tomcat-embed-websocket</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.afterturn</groupId>
+            <artifactId>easypoi-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <filters>
+            <filter>../../src/main/filters/config-${r"${"}profile.active${r"}"}.properties</filter>
+        </filters>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- docker打包插件 -->
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>dockerfile-maven-plugin</artifactId>
+                <version>${r"${"}dockerfile-maven-plugin.version${r"}"}</version>
+                <configuration>
+                    <repository>${r"${"}docker.image.prefix${r"}"}/${r"${"}project.artifactId${r"}"}</repository>
+                    <tag>${r"${"}ceres-project.version${r"}"}</tag>
+                    <buildArgs>
+                        <JAR_FILE>target/${r"${"}project.build.finalName${r"}"}.jar</JAR_FILE>
+                    </buildArgs>
+                </configuration>
+            </plugin>
+
+        </plugins>
+    </build>
+</project>

+ 12 - 0
src/main/resources/init/resources/application.java.ftl

@@ -0,0 +1,12 @@
+ceres:
+  swagger:
+    docket:
+      ${serviceName}:
+        title: ${description}服务
+        base-package: ${packageBase}.controller
+server:
+  port: ${serverPort}
+
+
+## 请在nacos中新建一个名为: ${projectPrefix}${serviceName}-server.yml 的配置文件,并将: ${projectPrefix}${serviceName}-server/src/main/resources/${projectPrefix}${serviceName}-server.yml 配置文件的内容移动过去
+## 然后删除此文件!!!

+ 10 - 0
src/main/resources/init/resources/banner.java.ftl

@@ -0,0 +1,10 @@
+${r"${"}AnsiColor.BRIGHT_YELLOW${r"}"}
+             .__.__                                       .___      .__                        .__                   .___
+__________ __|__|  |__   ____  __ __          _____     __| _/_____ |__| ____             ____ |  |   ____  __ __  __| _/
+\___   /  |  \  |  |  \ /  _ \|  |  \  ______ \__  \   / __ |/     \|  |/    \   ______ _/ ___\|  |  /  _ \|  |  \/ __ |
+ /    /|  |  /  |   Y  (  ${r"<_>"} )  |  / /_____/  / __ \_/ /_/ |  Y Y  \  |   |  \ /_____/ \  \___|  |_(  ${r"<_>"} )  |  / /_/ |
+/_____ \____/|__|___|  /\____/|____/          (____  /\____ |__|_|  /__|___|  /          \___  >____/\____/|____/\____ |
+      \/             \/                            \/      \/     \/        \/               \/                       \/
+Application Version: @project.description@ - @project.version@
+Spring Boot Version: ${r"${"}spring-boot.version${r"}"}${r"${"}spring-boot.formatted-version${r"}"}
+${r"${"}AnsiColor.DEFAULT${r"}"}

+ 50 - 0
src/main/resources/init/resources/bootstrap.java.ftl

@@ -0,0 +1,50 @@
+# @xxx@ 从pom.xml中取值, 所以 @xx@ 标注的值,都不能从nacos中获取
+ceres:
+  nacos:
+    ip: ${r"${"}NACOS_IP:@nacos.ip@${r"}"}
+    port: ${r"${"}NACOS_PORT:@nacos.port@${r"}"}
+    namespace: ${r"${"}NACOS_ID:@nacos.namespace@${r"}"}
+
+spring:
+  main:
+    allow-bean-definition-overriding: true
+  application:
+    name: @project.artifactId@
+  profiles:
+    active: @profile.active@
+  cloud:
+    nacos:
+      config:
+        server-addr: ${r"${"}ceres.nacos.ip${r"}"}:${r"${"}ceres.nacos.port${r"}"}
+        file-extension: yml
+        namespace: ${r"${"}ceres.nacos.namespace${r"}"}
+        shared-configs:
+          - dataId: common.yml
+            refresh: true
+          - dataId: redis.yml
+            refresh: false
+          - dataId: mysql.yml
+            refresh: true
+          - dataId: rabbitmq.yml
+            refresh: false
+        enabled: true
+      discovery:
+        server-addr: ${r"${"}ceres.nacos.ip}:${r"${"}ceres.nacos.port${r"}"}
+        namespace: ${r"${"}ceres.nacos.namespace${r"}"}
+        metadata: # 元数据,用于权限服务实时获取各个服务的所有接口
+          management.context-path: ${r"${"}server.servlet.context-path:${r"}"}${r"${"}spring.mvc.servlet.path:${r"}"}${r"${"}management.endpoints.web.base-path:${r"}"}
+
+# 只能配置在bootstrap.yml ,否则会生成 log.path_IS_UNDEFINED 文件夹
+# window会自动在 代码所在盘 根目录下自动创建文件夹,  如: D:/data/projects/logs
+logging:
+  file:
+    path: @logging.file.path@
+    name: ${r"${"}logging.file.path${r"}"}/${r"${"}spring.application.name}/root.log
+
+# 用于/actuator/info
+info:
+  name: '@project.name@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '${r"${spring.boot.version}"}'
+  spring-cloud-version: '@spring.cloud.version@'

+ 26 - 0
src/main/resources/init/resources/logback-spring.java.ftl

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+    <include resource="com/zkthink/ceres/log/logback/ceres-defaults.xml"/>
+
+    <springProfile name="test,docker,prod">
+        <logger name="${packageBase}.controller" additivity="true" level="${r"${"}log.level.controller${r"}"}">
+            <appender-ref ref="ASYNC_CONTROLLER_APPENDER"/>
+        </logger>
+        <logger name="${packageBase}.service" additivity="true" level="${r"${"}log.level.service${r"}"}">
+            <appender-ref ref="ASYNC_SERVICE_APPENDER"/>
+        </logger>
+        <logger name="${packageBase}.dao" additivity="false" level="${r"${"}log.level.dao${r"}"}">
+            <appender-ref ref="ASYNC_DAO_APPENDER"/>
+        </logger>
+    </springProfile>
+
+    <springProfile name="dev">
+        <logger name="${packageBase}.controller" additivity="true" level="${r"${"}log.level.controller${r"}"}">
+            <appender-ref ref="CONTROLLER_APPENDER"/>
+        </logger>
+        <logger name="${packageBase}.service" additivity="true" level="${r"${"}log.level.service${r"}"}">
+            <appender-ref ref="SERVICE_APPENDER"/>
+        </logger>
+    </springProfile>
+</configuration>

+ 21 - 0
src/main/resources/init/resources/spy.java.ftl

@@ -0,0 +1,21 @@
+module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
+# \u81EA\u5B9A\u4E49\u65E5\u5FD7\u6253\u5370
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#\u65E5\u5FD7\u8F93\u51FA\u5230\u63A7\u5236\u53F0
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# \u4F7F\u7528\u65E5\u5FD7\u7CFB\u7EDF\u8BB0\u5F55 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# \u8BBE\u7F6E p6spy driver \u4EE3\u7406
+deregisterdrivers=true
+# \u53D6\u6D88JDBC URL\u524D\u7F00
+useprefix=true
+# \u914D\u7F6E\u8BB0\u5F55 Log \u4F8B\u5916,\u53EF\u53BB\u6389\u7684\u7ED3\u679C\u96C6\u6709error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# \u65E5\u671F\u683C\u5F0F
+dateformat=yyyy-MM-dd HH:mm:ss
+# \u5B9E\u9645\u9A71\u52A8\u53EF\u591A\u4E2A
+driverlist=com.mysql.cj.jdbc.Driver
+# \u662F\u5426\u5F00\u542F\u6162SQL\u8BB0\u5F55
+outagedetection=true
+# \u6162SQL\u8BB0\u5F55\u6807\u51C6 2 \u79D2
+outagedetectioninterval=2

+ 16 - 0
src/main/resources/logback.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+    <logger name="org.apache.http" level="INFO"/>
+
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="debug">
+        <appender-ref ref="console"/>
+    </root>
+
+</configuration>

+ 32 - 0
src/main/resources/templates/constant.java.ftl

@@ -0,0 +1,32 @@
+package ${cfg.Constant};
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 数据库常量
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+public class ${entity}${cfg.constantSuffix} implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private ${entity}${cfg.constantSuffix}(){
+        super();
+    }
+
+<#-- 字段常量 -->
+<#if entityColumnConstant>
+    /**
+     * 字段常量
+     */
+    <#list table.fields as field>
+    public static final String ${field.name?upper_case} = "${field.name}";
+    </#list>
+</#if>
+
+}

+ 81 - 0
src/main/resources/templates/controller.java.ftl

@@ -0,0 +1,81 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${package.Controller};
+
+<#if superControllerClass??>
+import ${package.Entity}.${entity};
+import ${cfg.SaveDTO}.${entity}SaveDTO;
+import ${cfg.SaveDTO}.${entity}UpdateDTO;
+import ${cfg.SaveDTO}.${entity}PageDTO;
+import ${package.Service}.${table.serviceName};
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+</#if>
+<#if superControllerClassPackage??>
+import ${superControllerClassPackage};
+</#if>
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+<#if restControllerStyle>
+import org.springframework.web.bind.annotation.RestController;
+<#else>
+import org.springframework.stereotype.Controller;
+</#if>
+
+
+<#assign tableComment = "${table.comment!''}"/>
+<#if table.comment?? && table.comment!?contains('\n')>
+    <#assign tableComment = "${table.comment!?substring(0,table.comment?index_of('\n'))?trim}"/>
+</#if>
+/**
+ * <p>
+ * 前端控制器
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Slf4j
+<#if restControllerStyle>
+@RestController
+<#else>
+@Controller
+</#if>
+@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
+<#if swagger2>
+@Api(value = "${entity}", tags = "${tableComment}")
+</#if>
+<#if kotlin>
+    class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
+<#else>
+    <#if superControllerClass??>
+public class ${table.controllerName} extends ${superControllerClass}<${table.serviceName}, <#list table.commonFields as field><#if field.keyFlag>${field.propertyType}</#if></#list><#list table.fields as field><#if field.keyFlag>${field.propertyType}</#if></#list>, ${entity}, ${entity}PageDTO, ${entity}SaveDTO, ${entity}UpdateDTO> {
+    <#else>
+public class ${table.controllerName} {
+    </#if>
+
+<#if superControllerClass??>
+    /**
+     * Excel导入后的操作
+     *
+     * @param list
+     */
+    @Override
+    public R<Boolean> handlerImport(List<Map<String, String>> list){
+        List<${entity}> ${entity?uncap_first}List = list.stream().map((map) -> {
+            ${entity} ${entity?uncap_first} = ${entity}.builder().build();
+            //TODO 请在这里完成转换
+            return ${entity?uncap_first};
+        }).collect(Collectors.toList());
+
+        return R.success(baseService.saveBatch(${entity?uncap_first}List));
+    }
+</#if>
+}
+</#if>

+ 198 - 0
src/main/resources/templates/controller_bak.java.ftl

@@ -0,0 +1,198 @@
+package ${package.Controller};
+
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.zkthink.base.R;
+import com.zkthink.log.annotation.SysLog;
+import com.zkthink.database.mybatis.conditions.query.LbqWrapper;
+import com.zkthink.database.mybatis.conditions.Wraps;
+import ${package.Entity}.${entity};
+import ${cfg.SaveDTO}.${entity}SaveDTO;
+import ${cfg.SaveDTO}.${entity}UpdateDTO;
+import ${cfg.SaveDTO}.${entity}PageDTO;
+import ${package.Service}.${table.serviceName};
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import com.zkthink.base.entity.SuperEntity;
+import com.zkthink.model.RemoteData;
+import com.zkthink.utils.BeanPlusUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+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>
+
+<#assign tableComment = "${table.comment!''}"/>
+<#if table.comment?? && table.comment!?contains('\n')>
+    <#assign tableComment = "${table.comment!?substring(0,table.comment?index_of('\n'))?trim}"/>
+</#if>
+/**
+ * <p>
+ * 前端控制器
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Slf4j
+@Validated
+<#if restControllerStyle>
+@RestController
+<#else>
+@Controller
+</#if>
+@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
+<#if swagger2>
+@Api(value = "${entity}", tags = "${tableComment}")
+</#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>
+
+    @Autowired
+    private ${table.serviceName} ${table.serviceName?uncap_first};
+
+    /**
+     * 分页查询${tableComment}
+     *
+     * @param data 分页查询对象
+     * @return 查询结果
+     */
+    @ApiOperation(value = "分页查询${tableComment}", notes = "分页查询${tableComment}")
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "current", value = "当前页", dataType = "long", paramType = "query", defaultValue = "1"),
+        @ApiImplicitParam(name = "size", value = "每页显示几条", dataType = "long", paramType = "query", defaultValue = "10"),
+    })
+    @GetMapping("/page")
+    @SysLog("分页查询${tableComment}")
+    public R<IPage<${entity}>> page(${entity}PageDTO data) {
+        ${entity} ${entity?uncap_first} = BeanPlusUtil.toBean(data, ${entity}.class);
+        <#list table.fields as field>
+        <#-- 自动注入注解 -->
+        <#if field.customMap.annotation??>
+        <#assign myPropertyName="${field.propertyName}"/>
+        <#assign capPropertyName="${field.propertyName?cap_first}"/>
+        <#assign entityCapPropertyName="${field.propertyName?cap_first}"/>
+        <#if entityCapPropertyName?ends_with("Id")>
+            <#assign entityCapPropertyName="${entityCapPropertyName!?substring(0,field.propertyName?index_of('Id'))}"/>
+        </#if>
+
+        if (data != null && data.get${capPropertyName}() != null) {
+            ${entity?uncap_first}.set${entityCapPropertyName}(new RemoteData<>(data.get${capPropertyName}()));
+        }
+        </#if>
+        </#list>
+
+        IPage<${entity}> page = getPage();
+        // 构建值不为null的查询条件
+        LbqWrapper<${entity}> query = Wraps.<${entity}>lbQ(${entity?uncap_first})
+            .geHeader(${entity}::getCreateTime, data.getStartCreateTime())
+            .leFooter(${entity}::getCreateTime, data.getEndCreateTime())
+            .orderByDesc(${entity}::getCreateTime);
+        ${table.serviceName?uncap_first}.page(page, query);
+        return success(page);
+    }
+
+    /**
+     * 查询${tableComment}
+     *
+     * @param id 主键id
+     * @return 查询结果
+     */
+    @ApiOperation(value = "查询${tableComment}", notes = "查询${tableComment}")
+    @GetMapping("/{id}")
+    @SysLog("查询${tableComment}")
+    public R<${entity}> get(@PathVariable <#list table.commonFields as field><#if field.keyFlag>${field.propertyType}</#if></#list><#list table.fields as field><#if field.keyFlag>${field.propertyType}</#if></#list> id) {
+        return success(${table.serviceName?uncap_first}.getById(id));
+    }
+
+    /**
+     * 新增${tableComment}
+     *
+     * @param data 新增对象
+     * @return 新增结果
+     */
+    @ApiOperation(value = "新增${tableComment}", notes = "新增${tableComment}不为空的字段")
+    @PostMapping
+    @SysLog("新增${tableComment}")
+    public R<${entity}> save(@RequestBody @Validated ${entity}SaveDTO data) {
+        ${entity} ${entity?uncap_first} = BeanPlusUtil.toBean(data, ${entity}.class);
+        ${table.serviceName?uncap_first}.save(${entity?uncap_first});
+        return success(${entity?uncap_first});
+    }
+
+    /**
+     * 修改${tableComment}
+     *
+     * @param data 修改对象
+     * @return 修改结果
+     */
+    @ApiOperation(value = "修改${tableComment}", notes = "修改${tableComment}不为空的字段")
+    @PutMapping
+    @SysLog("修改${tableComment}")
+    public R<${entity}> update(@RequestBody @Validated(SuperEntity.Update.class) ${entity}UpdateDTO data) {
+        ${entity} ${entity?uncap_first} = BeanPlusUtil.toBean(data, ${entity}.class);
+        ${table.serviceName?uncap_first}.updateById(${entity?uncap_first});
+        return success(${entity?uncap_first});
+    }
+
+    /**
+     * 删除${tableComment}
+     *
+     * @param ids 主键id
+     * @return 删除结果
+     */
+    @ApiOperation(value = "删除${tableComment}", notes = "根据id物理删除${tableComment}")
+    @DeleteMapping
+    @SysLog("删除${tableComment}")
+    public R<Boolean> delete(@RequestParam("ids[]") <#list table.commonFields as field><#if field.keyFlag>List<${field.propertyType}></#if></#list><#list table.fields as field><#if field.keyFlag>List<${field.propertyType}></#if></#list> ids) {
+        ${table.serviceName?uncap_first}.removeByIds(ids);
+        return success(true);
+    }
+
+    <#if superEntityClass?? && superEntityClass=="TreeEntity">
+    /**
+     * 级联查询${tableComment}
+     *
+     * @param data 参数
+     * @return 查询结果
+     */
+    @ApiOperation(value = "级联查询${tableComment}", notes = "级联查询${tableComment}")
+    @GetMapping
+    @SysLog("级联查询${tableComment}")
+    public R<List<${entity}>> list(${entity} data) {
+        if (data == null) {
+            data = new ${entity}();
+        }
+        if (data.getParentId() == null) {
+            data.setParentId(0L);
+        }
+        LbqWrapper<${entity}> wrapper = Wraps.lbQ(data).orderByAsc(${entity}::getSortValue);
+        return success(${entity?uncap_first}Service.list(wrapper));
+    }
+    </#if>
+}
+</#if>

+ 55 - 0
src/main/resources/templates/dto.java.ftl

@@ -0,0 +1,55 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${cfg.DTO};
+
+<#list table.importPackages as pkg>
+import ${pkg};
+</#list>
+<#if swagger2>
+import io.swagger.annotations.ApiModel;
+</#if>
+import ${package.Entity}.${entity};
+<#if entityLombokModel>
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+</#if>
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 实体类
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+<#if entityLombokModel>
+@Data
+@NoArgsConstructor
+@Accessors(chain = true)
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = false)
+</#if>
+<#if swagger2>
+    @ApiModel(value = "${entity}DTO", description = "${table.comment!?replace("\r\n"," ")?replace("\r"," ")?replace("\n"," ")}")
+</#if>
+public class ${entity}DTO extends ${entity} implements Serializable {
+
+    /**
+     * 在DTO中新增并自定义字段,需要覆盖验证的字段,请新建DTO。Entity中的验证规则可以自行修改,但下次生成代码时,记得同步代码!!
+     */
+    private static final long serialVersionUID = 1L;
+
+    public static ${entity}DTO build() {
+        return new ${entity}DTO();
+    }
+
+}

+ 240 - 0
src/main/resources/templates/entity.java.ftl

@@ -0,0 +1,240 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${package.Entity};
+
+<#list table.importPackages as pkg>
+import ${pkg};
+</#list>
+<#if swagger2>
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+</#if>
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+import java.time.LocalDateTime;
+<#if entityLombokModel>
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+</#if>
+<#if cfg.filedTypes??>
+<#list cfg.filedTypes as fieldType>
+    <#list table.fields as field>
+        <#if field.propertyName == fieldType.name && table.name==fieldType.table && field.propertyType=="String">
+import ${fieldType.packagePath};
+            <#break>
+        </#if>
+    </#list>
+</#list>
+</#if>
+
+import static com.baomidou.mybatisplus.annotation.SqlCondition.LIKE;
+
+<#assign tableComment = "${table.comment!''}"/>
+<#if table.comment?? && table.comment!?contains('\n')>
+    <#assign tableComment = "${table.comment!?substring(0,table.comment?index_of('\n'))?trim}"/>
+</#if>
+/**
+ * <p>
+ * 实体类
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @since ${date}
+ */
+<#if entityLombokModel>
+@Data
+@NoArgsConstructor
+@ToString(callSuper = true)
+</#if>
+<#if table.convert>
+@TableName("${table.name}")
+</#if>
+<#if swagger2>
+@ApiModel(value = "${entity}", description = "${tableComment}")
+</#if>
+<#if superEntityClass??>
+@AllArgsConstructor
+<#assign hasCustomAnno="0"/>
+<#if superEntityClass?? && superEntityClass=="TreeEntity">
+    <#assign hasCustomAnno="1"/>
+</#if>
+public class ${entity} {
+<#elseif activeRecord>
+@AllArgsConstructor
+public class ${entity} extends Model<${entity}> {
+<#else>
+public class ${entity} implements Serializable {
+</#if>
+
+    private static final long serialVersionUID = 1L;
+
+<#setting number_format="0">
+<#-- ----------  BEGIN 字段循环遍历  ---------->
+<#list table.fields as field>
+    <#if field.keyFlag>
+        <#assign keyPropertyName="${field.propertyName}"/>
+    </#if>
+    <#assign fieldComment="${field.comment!}"/>
+    <#if field.comment!?length gt 0>
+    /**
+     * ${field.comment!?replace("\n","\n     * ")}
+     */
+    <#if field.comment!?contains("\n") >
+        <#assign fieldComment="${field.comment!?substring(0,field.comment?index_of('\n'))?replace('\r\n','')?replace('\r','')?replace('\n','')?trim}"/>
+    </#if>
+    </#if>
+    <#if swagger2>
+    @ApiModelProperty(value = "${fieldComment}")
+    </#if>
+    <#assign myPropertyType="${field.propertyType}"/>
+    <#assign isEnumType="1"/>
+    <#list cfg.filedTypes as fieldType>
+        <#if fieldType.name == field.propertyName && table.name==fieldType.table && field.propertyType=="String">
+            <#assign myPropertyType="${fieldType.type}"/>
+            <#assign isEnumType="2"/>
+        </#if>
+    </#list>
+    <#if field.customMap.Null == "NO" >
+        <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+    @NotEmpty(message = "${fieldComment}不能为空")
+        <#else>
+    @NotNull(message = "${fieldComment}不能为空")
+        </#if>
+    </#if>
+    <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+        <#assign max = 255/>
+        <#if field.type?starts_with("varchar") || field.type?starts_with("char")>
+            <#if field.type?contains("(")>
+                <#assign max = field.type?substring(field.type?index_of("(") + 1, field.type?index_of(")"))/>
+            </#if>
+    @Length(max = ${max}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("text")>
+        <#assign max = 65535/>
+    @Length(max = ${max}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("mediumtext")>
+        <#assign max = 16777215/>
+    @Length(max = ${max}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("longtext")>
+
+        </#if>
+    <#else>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Byte")>
+    @Range(min = Byte.MIN_VALUE, max = Byte.MAX_VALUE, message = "${fieldComment}长度不能超过"+Byte.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+    </#if>
+    <#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}")
+        </#if>
+    <#-- 普通字段 -->
+    <#elseif field.fill??>
+    <#-- -----   存在字段填充设置   ----->
+        <#if field.convert>
+    @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
+        <#else>
+    @TableField(fill = FieldFill.${field.fill})
+        </#if>
+    <#elseif field.convert>
+        <#if (field.type?starts_with("varchar") || field.type?starts_with("char")) && myPropertyType == "String">
+    @TableField(value = "${field.name}", condition = LIKE)
+        <#else>
+    @TableField("${field.name}")
+        </#if>
+    </#if>
+    <#-- 乐观锁注解 -->
+    <#if (versionFieldName!"") == field.name>
+    @Version
+    </#if>
+    <#-- 逻辑删除注解 -->
+    <#if (logicDeleteFieldName!"") == field.name>
+    @TableLogic
+    </#if>
+    <#assign myPropertyName="${field.propertyName}"/>
+    <#-- 自动注入注解 -->
+    <#if field.customMap.annotation??>
+    ${field.customMap.annotation}
+    @ExcelEntity(name = "")
+        <#assign myPropertyType="${field.customMap.type}"/>
+        <#if field.propertyName?ends_with("Id")>
+            <#assign myPropertyName="${field.propertyName!?substring(0,field.propertyName?index_of('Id'))}"/>
+        </#if>
+    </#if>
+    private ${myPropertyType} ${myPropertyName};
+
+
+</#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 entityBuilderModel>
+    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 entityBuilderModel>
+        return this;
+        </#if>
+    }
+    </#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>
+
+}

+ 83 - 0
src/main/resources/templates/enum.java.ftl

@@ -0,0 +1,83 @@
+package ${enumCustom.package.importPackage};
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.zkthink.base.BaseEnum;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+import lombok.Getter;
+
+<#assign tableComment="${table.comment!}"/>
+<#if table.comment!?length gt 0>
+    <#if table.comment!?contains("\n") >
+        <#assign tableComment="${table.comment!?substring(0,table.comment?index_of('\n'))?trim}"/>
+    </#if>
+</#if>
+/**
+ * <p>
+ * 实体注释中生成的类型枚举
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@ApiModel(value = "${enumCustom.enumName}", description = "${enumCustom.comment}-枚举")
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum ${enumCustom.enumName} implements BaseEnum {
+
+    <#list enumCustom.list?keys as key>
+    /**
+     * ${key?upper_case}=<#list enumCustom.list[key] as des><#if enumCustom.firstTypeNumber=="false">"${des?trim}"<#else >${des?trim}</#if></#list>
+     */
+    ${key?upper_case}(<#list enumCustom.list[key] as des><#if des_index == 0 && enumCustom.firstTypeNumber=="true">${des?trim}<#else>"${des?trim}"</#if><#if des_has_next>,</#if></#list>),
+    </#list>
+    ;
+
+<#list enumCustom.list?keys as key>
+<#list enumCustom.list[key] as des>
+    <#if des_index == 0>
+    @ApiModelProperty(value = "描述")
+    </#if>
+    private <#if des_index == 0 && enumCustom.firstTypeNumber=="true">int<#else >String</#if> <#if des_index == 0 && (enumCustom.list[key]?size == 1)>desc<#elseif des_index == 0 && (enumCustom.list[key]?size > 1)>val<#elseif des_index == 1 >desc<#else>other${enumCustom.list?size}</#if>;
+
+</#list>
+<#break>
+</#list>
+
+    public static ${enumCustom.enumName} match(String val, ${enumCustom.enumName} def) {
+        for (${enumCustom.enumName} enm : ${enumCustom.enumName}.values()) {
+            if (enm.name().equalsIgnoreCase(val)) {
+                return enm;
+            }
+        }
+        return def;
+    }
+
+    public static ${enumCustom.enumName} get(String val) {
+        return match(val, null);
+    }
+
+    public boolean eq(String val) {
+        return this.name().equalsIgnoreCase(val);
+    }
+
+    public boolean eq(${enumCustom.enumName} val) {
+        if (val == null) {
+            return false;
+        }
+        return eq(val.name());
+    }
+
+    @Override
+    @ApiModelProperty(value = "编码", allowableValues = "<#list enumCustom.list?keys as key>${key?upper_case}<#if key_has_next>,</#if></#list>", example = "${enumCustom.list?keys[0]?upper_case}")
+    public String getCode() {
+        return this.name();
+    }
+
+}

+ 20 - 0
src/main/resources/templates/mapper.java.ftl

@@ -0,0 +1,20 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${package.Mapper};
+
+import ${superMapperClassPackage};
+import ${package.Entity}.${entity};
+
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+<#if kotlin>
+interface ${table.mapperName} : ${superMapperClass}<${entity}>
+<#else>
+public interface ${entity}DAO extends ${superMapperClass}<${entity}> {
+
+}
+</#if>

+ 98 - 0
src/main/resources/templates/mapper.xml.ftl

@@ -0,0 +1,98 @@
+<?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}.${entity}DAO">
+
+<#if enableCache>
+    <!-- 开启二级缓存 -->
+    <cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
+
+</#if>
+<#if baseResultMap>
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
+<#list table.fields as field>
+<#if field.keyFlag><#--生成主键排在第一位-->
+    <#if field.type?starts_with("int")>
+        <id column="${field.name}" jdbcType="INTEGER" property="${field.propertyName}"/>
+    <#elseif field.type?starts_with("datetime")>
+        <id column="${field.name}" jdbcType="TIMESTAMP" property="${field.propertyName}"/>
+    <#elseif field.type?starts_with("text") || field.type?starts_with("longtext")>
+        <id column="${field.name}" jdbcType="LONGVARCHAR" property="${field.propertyName}"/>
+    <#else>
+        <#if field.type?contains("(")>
+        <#assign fType = field.type?substring(0, field.type?index_of("("))?upper_case/>
+        <id column="${field.name}" jdbcType="${fType}" property="${field.propertyName}"/>
+        <#else>
+        <id column="${field.name}" jdbcType="${field.type?upper_case}" property="${field.propertyName}"/>
+        </#if>
+    </#if>
+</#if>
+</#list>
+<#list table.commonFields as field><#--生成公共字段 -->
+    <#if field.keyFlag>
+    <#if field.type?starts_with("int")>
+        <id column="${field.name}" jdbcType="INTEGER" property="${field.propertyName}"/>
+    <#elseif field.type?starts_with("datetime")>
+        <id column="${field.name}" jdbcType="TIMESTAMP" property="${field.propertyName}"/>
+    <#elseif field.type?starts_with("text") || field.type?starts_with("longtext")>
+        <id column="${field.name}" jdbcType="LONGVARCHAR" property="${field.propertyName}"/>
+    <#else>
+        <#if field.type?contains("(")>
+        <#assign fType = field.type?substring(0, field.type?index_of("("))?upper_case/>
+        <id column="${field.name}" jdbcType="${fType}" property="${field.propertyName}"/>
+        <#else>
+        <id column="${field.name}" jdbcType="${field.type?upper_case}" property="${field.propertyName}"/>
+        </#if>
+    </#if>
+    <#else>
+    <#if field.type?starts_with("int")>
+        <result column="${field.name}" jdbcType="INTEGER" property="${field.propertyName}"/>
+    <#elseif field.type?starts_with("datetime")>
+        <result column="${field.name}" jdbcType="TIMESTAMP" property="${field.propertyName}"/>
+    <#elseif field.type?starts_with("text") || field.type?starts_with("longtext") || field.type?starts_with("mediumtext")>
+        <result column="${field.name}" jdbcType="LONGVARCHAR" property="${field.propertyName}"/>
+    <#else>
+        <#if field.type?contains("(")>
+        <#assign fType = field.type?substring(0, field.type?index_of("("))?upper_case/>
+        <result column="${field.name}" jdbcType="${fType}" property="${field.propertyName}"/>
+        <#else>
+        <result column="${field.name}" jdbcType="${field.type?upper_case}" property="${field.propertyName}"/>
+        </#if>
+    </#if>
+    </#if>
+</#list>
+<#list table.fields as field>
+<#if !field.keyFlag><#--生成普通字段 -->
+
+    <#assign myPropertyName="${field.propertyName}"/>
+    <#-- 自动注入注解 -->
+    <#if field.customMap.annotation?? && field.propertyName?ends_with("Id")>
+        <#assign myPropertyName="${field.propertyName!?substring(0,field.propertyName?index_of('Id'))}"/>
+    </#if>
+    <#if field.type?starts_with("int")>
+        <result column="${field.name}" jdbcType="INTEGER" property="${myPropertyName}"/>
+    <#elseif field.type?starts_with("datetime")>
+        <result column="${field.name}" jdbcType="TIMESTAMP" property="${myPropertyName}"/>
+    <#elseif field.type?starts_with("text") || field.type?starts_with("longtext") || field.type?starts_with("mediumtext")>
+        <result column="${field.name}" jdbcType="LONGVARCHAR" property="${myPropertyName}"/>
+    <#else>
+    <#if field.type?contains("(")>
+        <#assign fType = field.type?substring(0, field.type?index_of("("))?upper_case/>
+        <result column="${field.name}" jdbcType="${fType}" property="${myPropertyName}"/>
+    <#else>
+        <result column="${field.name}" jdbcType="${field.type?upper_case}" property="${myPropertyName}"/>
+    </#if>
+    </#if>
+</#if>
+</#list>
+    </resultMap>
+
+</#if>
+<#if baseColumnList>
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        ${table.fieldNames}
+    </sql>
+
+</#if>
+</mapper>

+ 148 - 0
src/main/resources/templates/pageDto.java.ftl

@@ -0,0 +1,148 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${cfg.PageDTO};
+
+import java.time.LocalDateTime;
+<#list table.importPackages as pkg>
+import ${pkg};
+</#list>
+<#if swagger2>
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+</#if>
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+<#if entityLombokModel>
+import lombok.Data;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+</#if>
+<#list cfg.filedTypes as fieldType>
+    <#list table.fields as field>
+        <#if field.propertyName == fieldType.name && table.name==fieldType.table && field.propertyType=="String">
+import ${fieldType.packagePath};
+            <#break>
+        </#if>
+    </#list>
+</#list>
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 实体类
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+<#if entityLombokModel>
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = false)
+@Builder
+</#if>
+<#if swagger2>
+@ApiModel(value = "${entity}PageDTO", description = "${table.comment!?replace("\r\n"," ")?replace("\r"," ")?replace("\n"," ")}")
+</#if>
+public class ${entity}PageDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+<#list table.fields as field>
+<#-- 如果有父类,排除公共字段 -->
+<#if (superEntityClass?? && cfg.superExtend?? && field.propertyName !="id") || (superEntityClass?? && field.propertyName !="id" && field.propertyName !="createTime" && field.propertyName != "updateTime" && field.propertyName !="createUser" && field.propertyName !="updateUser") || !superEntityClass??>
+    <#if field.keyFlag>
+        <#assign keyPropertyName="${field.propertyName}"/>
+    </#if>
+    <#assign fieldComment="${field.comment!}"/>
+    <#if field.comment!?length gt 0>
+    /**
+     * ${field.comment!?replace("\n","\n     * ")}
+     */
+        <#if field.comment!?contains("\n") >
+            <#assign fieldComment="${field.comment!?substring(0,field.comment?index_of('\n'))?replace('\r\n','')?replace('\r','')?replace('\n','')?trim}"/>
+        </#if>
+    </#if>
+    <#if swagger2>
+    @ApiModelProperty(value = "${fieldComment}")
+    </#if>
+    <#assign myPropertyType="${field.propertyType}"/>
+    <#assign isEnumType="1"/>
+    <#list cfg.filedTypes as fieldType>
+        <#if fieldType.name == field.propertyName && table.name==fieldType.table && field.propertyType=="String">
+            <#assign myPropertyType="${fieldType.type}"/>
+            <#assign isEnumType="2"/>
+        </#if>
+    </#list>
+    <#if field.customMap.Null == "NO" >
+        <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+    @NotEmpty(message = "${fieldComment}不能为空")
+        <#else>
+    @NotNull(message = "${fieldComment}不能为空")
+        </#if>
+    </#if>
+    <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+        <#assign max = 255/>
+        <#if field.type?starts_with("varchar") || field.type?starts_with("char")>
+            <#if field.type?contains("(")>
+                <#assign max = field.type?substring(field.type?index_of("(") + 1, field.type?index_of(")"))/>
+            </#if>
+    @Length(max = ${max}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("text")>
+            <#assign max = 65535/>
+    @Length(max = ${max?string["0"]}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("mediumtext")>
+            <#assign max = 16777215/>
+    @Length(max = ${max?string["0"]}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("longtext")>
+        </#if>
+    <#else>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Byte")>
+    @Range(min = Byte.MIN_VALUE, max = Byte.MAX_VALUE, message = "${fieldComment}长度不能超过"+Byte.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+    </#if>
+    <#-- 自动注入注解 -->
+    <#if field.customMap.annotation??>
+    ${field.customMap.annotation}
+        <#assign myPropertyType="${field.customMap.type}"/>
+        <#if field.propertyName?ends_with("Id")>
+            <#assign myPropertyName="${field.propertyName!?substring(0,field.propertyName?index_of('Id'))}"/>
+        </#if>
+    </#if>
+    <#assign myPropertyName="${field.propertyName}"/>
+    private ${myPropertyType} ${myPropertyName};
+</#if>
+</#list>
+
+<#if superEntityClass?? && superEntityClass=="TreeEntity">
+    @ApiModelProperty(value = "名称")
+    @NotEmpty(message = "名称不能为空")
+    @Length(max = 255, message = "名称长度不能超过255")
+    protected String label;
+
+    @ApiModelProperty(value = "父ID")
+    protected <#list table.commonFields as field><#if field.keyFlag>${field.propertyType}</#if></#list> parentId;
+
+    @ApiModelProperty(value = "排序号")
+    protected Integer sortValue;
+</#if>
+}

+ 147 - 0
src/main/resources/templates/saveDto.java.ftl

@@ -0,0 +1,147 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${cfg.SaveDTO};
+
+<#list table.importPackages as pkg>
+import ${pkg};
+</#list>
+<#if swagger2>
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+</#if>
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+<#if entityLombokModel>
+import lombok.Data;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+</#if>
+<#list cfg.filedTypes as fieldType>
+    <#list table.fields as field>
+        <#if field.propertyName == fieldType.name && table.name==fieldType.table && field.propertyType=="String">
+import ${fieldType.packagePath};
+            <#break>
+        </#if>
+    </#list>
+</#list>
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 实体类
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+<#if entityLombokModel>
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = false)
+@Builder
+</#if>
+<#if swagger2>
+@ApiModel(value = "${entity}SaveDTO", description = "${table.comment!?replace("\r\n"," ")?replace("\r"," ")?replace("\n"," ")}")
+</#if>
+public class ${entity}SaveDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+<#list table.fields as field>
+<#-- 如果有父类,排除公共字段 -->
+<#if (superEntityClass?? && cfg.superExtend?? && field.propertyName !="id") || (superEntityClass?? && field.propertyName !="id" && field.propertyName !="createTime" && field.propertyName != "updateTime" && field.propertyName !="createUser" && field.propertyName !="updateUser") || !superEntityClass??>
+    <#if field.keyFlag>
+        <#assign keyPropertyName="${field.propertyName}"/>
+    </#if>
+    <#assign fieldComment="${field.comment!}"/>
+    <#if field.comment!?length gt 0>
+    /**
+     * ${field.comment!?replace("\n","\n     * ")}
+     */
+        <#if field.comment!?contains("\n") >
+            <#assign fieldComment="${field.comment!?substring(0,field.comment?index_of('\n'))?replace('\r\n','')?replace('\r','')?replace('\n','')?trim}"/>
+        </#if>
+    </#if>
+    <#if swagger2>
+    @ApiModelProperty(value = "${fieldComment}")
+    </#if>
+    <#assign myPropertyType="${field.propertyType}"/>
+    <#assign isEnumType="1"/>
+    <#list cfg.filedTypes as fieldType>
+        <#if fieldType.name == field.propertyName && table.name==fieldType.table && field.propertyType=="String">
+            <#assign myPropertyType="${fieldType.type}"/>
+            <#assign isEnumType="2"/>
+        </#if>
+    </#list>
+    <#if field.customMap.Null == "NO" >
+        <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+    @NotEmpty(message = "${fieldComment}不能为空")
+        <#else>
+    @NotNull(message = "${fieldComment}不能为空")
+        </#if>
+    </#if>
+    <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+        <#assign max = 255/>
+        <#if field.type?starts_with("varchar") || field.type?starts_with("char")>
+            <#if field.type?contains("(")>
+                <#assign max = field.type?substring(field.type?index_of("(") + 1, field.type?index_of(")"))/>
+            </#if>
+    @Length(max = ${max}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("text")>
+            <#assign max = 65535/>
+    @Length(max = ${max?string["0"]}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("mediumtext")>
+            <#assign max = 16777215/>
+    @Length(max = ${max?string["0"]}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("longtext")>
+        </#if>
+    <#else>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Byte")>
+    @Range(min = Byte.MIN_VALUE, max = Byte.MAX_VALUE, message = "${fieldComment}长度不能超过"+Byte.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+    </#if>
+    <#assign myPropertyName="${field.propertyName}"/>
+    <#-- 自动注入注解 -->
+    <#if field.customMap.annotation??>
+    ${field.customMap.annotation}
+        <#assign myPropertyType="${field.customMap.type}"/>
+        <#if field.propertyName?ends_with("Id")>
+            <#assign myPropertyName="${field.propertyName!?substring(0,field.propertyName?index_of('Id'))}"/>
+        </#if>
+    </#if>
+    private ${myPropertyType} ${myPropertyName};
+</#if>
+</#list>
+
+<#if superEntityClass?? && superEntityClass=="TreeEntity">
+    @ApiModelProperty(value = "名称")
+    @NotEmpty(message = "名称不能为空")
+    @Length(max = 255, message = "名称长度不能超过255")
+    protected String label;
+
+    @ApiModelProperty(value = "父ID")
+    protected <#list table.commonFields as field><#if field.keyFlag>${field.propertyType}</#if></#list> parentId;
+
+    @ApiModelProperty(value = "排序号")
+    protected Integer sortValue;
+</#if>
+}

+ 25 - 0
src/main/resources/templates/service.java.ftl

@@ -0,0 +1,25 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${package.Service};
+
+import ${package.Entity}.${entity};
+
+/**
+ * <p>
+ * 业务接口
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+<#if kotlin>
+interface ${table.serviceName} : ${superServiceClass}<${entity}>
+<#else>
+public interface ${table.serviceName} {
+
+}
+</#if>

+ 58 - 0
src/main/resources/templates/serviceImpl.java.ftl

@@ -0,0 +1,58 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${package.ServiceImpl};
+
+import ${package.Mapper}.${entity}DAO;
+import ${package.Entity}.${entity};
+import ${package.Service}.${table.serviceName};
+
+import lombok.extern.slf4j.Slf4j;
+<#if superServiceImplClass?? && superServiceImplClass == "SuperCacheServiceImpl">
+import org.springframework.aop.framework.AopContext;
+import org.springframework.cache.annotation.CacheConfig;
+</#if>
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 业务实现类
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Slf4j
+@Service
+<#if superServiceImplClass?? && superServiceImplClass == "SuperCacheServiceImpl">
+@CacheConfig(cacheNames = ${table.serviceImplName}.${entity?upper_case})
+</#if>
+<#if kotlin>
+open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
+}
+<#else>
+<#if superServiceImplClass??>
+public class ${table.serviceImplName} implements ${table.serviceName} {
+<#else>
+public class ${table.serviceImplName} {
+</#if>
+<#if superServiceImplClass?? && superServiceImplClass == "SuperCacheServiceImpl">
+    /**
+     * 建议将改变量移动到CacheKey工具类中统一管理,并在 caffeine.properties 文件中合理配置有效期
+     */
+    protected static final String ${entity?upper_case} = "${entity?lower_case}";
+
+    @Override
+    protected String getRegion() {
+        return ${entity?upper_case};
+    }
+
+    protected ${table.serviceName} currentProxy() {
+        return ((${table.serviceName}) AopContext.currentProxy());
+    }
+</#if>
+}
+</#if>

+ 162 - 0
src/main/resources/templates/updateDto.java.ftl

@@ -0,0 +1,162 @@
+/*
+* Copyright (C) 2017-2021
+* All rights reserved, Designed By 深圳中科鑫智科技有限公司
+* Copyright authorization contact 18814114118
+*/
+package ${cfg.SaveDTO};
+
+<#list table.importPackages as pkg>
+import ${pkg};
+</#list>
+<#if swagger2>
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+</#if>
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+import com.zkthink.base.entity.SuperEntity;
+<#if entityLombokModel>
+import lombok.Data;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+</#if>
+<#list cfg.filedTypes as fieldType>
+    <#list table.fields as field>
+        <#if field.propertyName == fieldType.name && table.name==fieldType.table && field.propertyType=="String">
+import ${fieldType.packagePath};
+            <#break>
+        </#if>
+    </#list>
+</#list>
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 实体类
+ * ${table.comment!?replace("\n","\n * ")}
+ * </p>
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+<#if entityLombokModel>
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = false)
+@Builder
+</#if>
+<#if swagger2>
+@ApiModel(value = "${entity}UpdateDTO", description = "${table.comment!?replace("\r\n"," ")?replace("\r"," ")?replace("\n"," ")}")
+</#if>
+public class ${entity}UpdateDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+<#list table.commonFields as field>
+    <#if field.keyFlag>
+    @ApiModelProperty(value = "主键")
+    @NotNull(message = "id不能为空", groups = SuperEntity.Update.class)
+    private ${field.propertyType} ${field.propertyName};
+    </#if>
+</#list>
+
+<#list table.fields as field>
+<#-- 如果有父类,排除公共字段 -->
+<#if (superEntityClass?? && cfg.superExtend?? && field.propertyName !="id") || (superEntityClass?? && field.propertyName !="id" && field.propertyName !="createTime" && field.propertyName != "updateTime" && field.propertyName !="createUser" && field.propertyName !="updateUser") || !superEntityClass??>
+    <#if field.keyFlag>
+        <#assign keyPropertyName="${field.propertyName}"/>
+    </#if>
+    <#assign fieldComment="${field.comment!}"/>
+    <#if field.comment!?length gt 0>
+    /**
+     * ${field.comment!?replace("\n","\n     * ")}
+     */
+        <#if field.comment!?contains("\n") >
+            <#assign fieldComment="${field.comment!?substring(0,field.comment?index_of('\n'))?replace('\r\n','')?replace('\r','')?replace('\n','')?trim}"/>
+        </#if>
+    </#if>
+    <#if swagger2>
+    @ApiModelProperty(value = "${fieldComment}")
+    </#if>
+    <#assign myPropertyType="${field.propertyType}"/>
+    <#assign isEnumType="1"/>
+    <#list cfg.filedTypes as fieldType>
+        <#if fieldType.name == field.propertyName && table.name==fieldType.table && field.propertyType=="String">
+            <#assign myPropertyType="${fieldType.type}"/>
+            <#assign isEnumType="2"/>
+        </#if>
+    </#list>
+    <#if field.customMap.dict??>
+        <#assign isEnumType="3"/>
+    </#if>
+    <#if field.customMap.Null == "NO" >
+        <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+    @NotEmpty(message = "${fieldComment}不能为空")
+        <#else>
+    @NotNull(message = "${fieldComment}不能为空")
+        </#if>
+    </#if>
+    <#if (field.columnType!"") == "STRING" && isEnumType == "1">
+        <#assign max = 255/>
+        <#if field.type?starts_with("varchar") || field.type?starts_with("char")>
+            <#if field.type?contains("(")>
+                <#assign max = field.type?substring(field.type?index_of("(") + 1, field.type?index_of(")"))/>
+            </#if>
+    @Length(max = ${max}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("text")>
+            <#assign max = 65535/>
+    @Length(max = ${max?string["0"]}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("mediumtext")>
+            <#assign max = 16777215/>
+    @Length(max = ${max?string["0"]}, message = "${fieldComment}长度不能超过${max}")
+        <#elseif field.type?starts_with("longtext")>
+        </#if>
+    <#else>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Byte")>
+    @Range(min = Byte.MIN_VALUE, max = Byte.MAX_VALUE, message = "${fieldComment}长度不能超过"+Byte.MAX_VALUE)
+        </#if>
+        <#if field.propertyType?starts_with("Short")>
+    @Range(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${fieldComment}长度不能超过"+Short.MAX_VALUE)
+        </#if>
+    </#if>
+    <#if field.customMap.dict??>
+    @DictionaryType("${field.customMap.dict}")
+        <#assign myPropertyType="Dictionary"/>
+    </#if>
+    <#assign myPropertyName="${field.propertyName}"/>
+<#-- 自动注入注解 -->
+    <#if field.customMap.annotation??>
+    ${field.customMap.annotation}
+        <#assign myPropertyType="${field.customMap.type}"/>
+        <#if field.propertyName?ends_with("Id")>
+            <#assign myPropertyName="${field.propertyName!?substring(0,field.propertyName?index_of('Id'))}"/>
+        </#if>
+    </#if>
+    private ${myPropertyType} ${myPropertyName};
+</#if>
+</#list>
+<#if superEntityClass?? && superEntityClass=="TreeEntity">
+    @ApiModelProperty(value = "名称")
+    @NotEmpty(message = "名称不能为空")
+    @Length(max = 255, message = "名称长度不能超过255")
+    protected String label;
+
+    @ApiModelProperty(value = "父ID")
+    protected <#list table.commonFields as field><#if field.keyFlag>${field.propertyType}</#if></#list> parentId;
+
+    @ApiModelProperty(value = "排序号")
+    protected Integer sortValue;
+</#if>
+}

+ 53 - 0
src/test/java/CommonGenerator.java

@@ -0,0 +1,53 @@
+import com.zkthink.ceres.generator.CodeGenerator;
+import com.zkthink.ceres.generator.config.CodeGeneratorConfig;
+import com.zkthink.ceres.generator.config.FileCreateConfig;
+import com.zkthink.ceres.generator.type.EntityType;
+import com.zkthink.ceres.generator.type.GenerateType;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ */
+public class CommonGenerator {
+
+    public static void main(String[] args) {
+        CodeGeneratorConfig build = buildMemberEntity();
+
+        // 下面是数据库的账号和密码
+        build.setUsername("root");
+        build.setPassword("123456");
+
+        System.out.println("输出路径:");
+        // 这里需要设置成你的项目所在的路径
+        String outputPath = System.getProperty("user.dir") + "/ceres/ceres-product";
+        System.out.println(outputPath);
+        build.setProjectRootPath(outputPath);
+
+        FileCreateConfig fileCreateConfig = new FileCreateConfig(GenerateType.OVERRIDE);
+        build.setFileCreateConfig(fileCreateConfig);
+
+        build.setProjectPrefix("cereshop");
+        for (String module:CodeGeneratorConfig.CERESHOP_MODULAR_LIST) {
+            build.setCurrentModule(module);
+            CodeGenerator.run(build);
+        }
+    }
+
+
+    private static CodeGeneratorConfig buildMemberEntity() {
+        List<String> tables = Arrays.asList(
+                "cere_generate_test"
+        );
+        //这一行不用改,第四个参数是表名称的前缀
+        CodeGeneratorConfig build = CodeGeneratorConfig.
+                build("", "", "", "cere", tables);
+        //填写基础包
+        build.setPackageBase("com.shop.cereshop");
+        //填写子包名称
+        build.setChildPackageName("live");
+        //设置数据库url
+        build.setUrl("jdbc:mysql://127.0.0.1:3306/cereshop1.6?serverTimezone=CTT&characterEncoding=utf8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull");
+        return build;
+    }
+}