Преглед изворни кода

打完收工,支持多引擎生成器

= пре 7 година
родитељ
комит
470b2bfb14

+ 44 - 269
mybatis-plus-generate/src/main/java/com/baomidou/mybatisplus/generator/AutoGenerator.java

@@ -15,23 +15,9 @@
  */
  */
 package com.baomidou.mybatisplus.generator;
 package com.baomidou.mybatisplus.generator;
 
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
 import java.io.Serializable;
 import java.io.Serializable;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
 import java.util.List;
-import java.util.Map;
-import java.util.Properties;
 
 
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.Velocity;
-import org.apache.velocity.app.VelocityEngine;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 
 
@@ -39,9 +25,7 @@ import com.baomidou.mybatisplus.activerecord.Model;
 import com.baomidou.mybatisplus.annotations.TableLogic;
 import com.baomidou.mybatisplus.annotations.TableLogic;
 import com.baomidou.mybatisplus.annotations.TableName;
 import com.baomidou.mybatisplus.annotations.TableName;
 import com.baomidou.mybatisplus.annotations.Version;
 import com.baomidou.mybatisplus.annotations.Version;
-import com.baomidou.mybatisplus.generator.config.ConstVal;
 import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
 import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
-import com.baomidou.mybatisplus.generator.config.FileOutConfig;
 import com.baomidou.mybatisplus.generator.config.GlobalConfig;
 import com.baomidou.mybatisplus.generator.config.GlobalConfig;
 import com.baomidou.mybatisplus.generator.config.PackageConfig;
 import com.baomidou.mybatisplus.generator.config.PackageConfig;
 import com.baomidou.mybatisplus.generator.config.StrategyConfig;
 import com.baomidou.mybatisplus.generator.config.StrategyConfig;
@@ -49,20 +33,26 @@ import com.baomidou.mybatisplus.generator.config.TemplateConfig;
 import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
 import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
 import com.baomidou.mybatisplus.generator.config.po.TableField;
 import com.baomidou.mybatisplus.generator.config.po.TableField;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
-import com.baomidou.mybatisplus.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
+import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
 import com.baomidou.mybatisplus.toolkit.StringUtils;
 import com.baomidou.mybatisplus.toolkit.StringUtils;
 
 
 /**
 /**
  * 生成文件
  * 生成文件
  *
  *
- * @author YangHu, tangguo
+ * @author YangHu, tangguo, hubin
  * @since 2016-08-30
  * @since 2016-08-30
  */
  */
 public class AutoGenerator {
 public class AutoGenerator {
 
 
     private static final Logger logger = LoggerFactory.getLogger(AutoGenerator.class);
     private static final Logger logger = LoggerFactory.getLogger(AutoGenerator.class);
-
+    /**
+     * 配置信息
+     */
     protected ConfigBuilder config;
     protected ConfigBuilder config;
+    /**
+     * 注入配置
+     */
     protected InjectionConfig injectionConfig;
     protected InjectionConfig injectionConfig;
     /**
     /**
      * 数据源配置
      * 数据源配置
@@ -85,9 +75,9 @@ public class AutoGenerator {
      */
      */
     private GlobalConfig globalConfig;
     private GlobalConfig globalConfig;
     /**
     /**
-     * velocity引擎
+     * 模板引擎
      */
      */
-    private VelocityEngine engine;
+    private AbstractTemplateEngine templateEngine;
 
 
     /**
     /**
      * 生成代码
      * 生成代码
@@ -95,32 +85,18 @@ public class AutoGenerator {
     public void execute() {
     public void execute() {
         logger.debug("==========================准备生成文件...==========================");
         logger.debug("==========================准备生成文件...==========================");
         // 初始化配置
         // 初始化配置
-        initConfig();
-        // 创建输出文件路径
-        mkdirs(config.getPathInfo());
-        // 获取上下文
-        Map<String, VelocityContext> ctxData = analyzeData(config);
-        // 循环生成文件
-        for (Map.Entry<String, VelocityContext> ctx : ctxData.entrySet()) {
-            batchOutput(ctx.getKey(), ctx.getValue());
-        }
-        // 打开输出目录
-        if (config.getGlobalConfig().isOpen()) {
-            try {
-                String osName = System.getProperty("os.name");
-                if (osName != null) {
-                    if (osName.contains("Mac")) {
-                        Runtime.getRuntime().exec("open " + config.getGlobalConfig().getOutputDir());
-                    } else if (osName.contains("Windows")) {
-                        Runtime.getRuntime().exec("cmd /c start " + config.getGlobalConfig().getOutputDir());
-                    } else {
-                        logger.debug("文件输出目录:" + config.getGlobalConfig().getOutputDir());
-                    }
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
+        if (null == config) {
+            config = new ConfigBuilder(packageInfo, dataSource, strategy, template, globalConfig);
+            if (null != injectionConfig) {
+                injectionConfig.setConfig(config);
             }
             }
         }
         }
+        if (null == templateEngine) {
+            // 为了兼容之前逻辑,采用 Velocity 引擎 【 默认 】
+            templateEngine = new VelocityTemplateEngine();
+        }
+        // 模板引擎初始化执行文件输出
+        templateEngine.init(this.pretreatmentConfigBuilder(config)).mkdirs().batchOutput().open();
         logger.debug("==========================文件生成完成!!!==========================");
         logger.debug("==========================文件生成完成!!!==========================");
     }
     }
 
 
@@ -138,32 +114,25 @@ public class AutoGenerator {
 
 
     /**
     /**
      * <p>
      * <p>
-     * 分析数据
+     * 预处理配置
      * </p>
      * </p>
      *
      *
      * @param config 总配置信息
      * @param config 总配置信息
      * @return 解析数据结果集
      * @return 解析数据结果集
      */
      */
-    private Map<String, VelocityContext> analyzeData(ConfigBuilder config) {
+    protected ConfigBuilder pretreatmentConfigBuilder(ConfigBuilder config) {
+        /**
+         * 注入自定义配置
+         */
+        if (null != injectionConfig) {
+            injectionConfig.initMap();
+            config.setInjectionConfig(injectionConfig);
+        }
+        /**
+         * 表信息列表
+         */
         List<TableInfo> tableList = this.getAllTableInfoList(config);
         List<TableInfo> tableList = this.getAllTableInfoList(config);
-        Map<String, String> packageInfo = config.getPackageInfo();
-        Map<String, VelocityContext> ctxData = new HashMap<>();
-        String superEntityClass = getSuperClassName(config.getSuperEntityClass());
-        String superMapperClass = getSuperClassName(config.getSuperMapperClass());
-        String superServiceClass = getSuperClassName(config.getSuperServiceClass());
-        String superServiceImplClass = getSuperClassName(config.getSuperServiceImplClass());
-        String superControllerClass = getSuperClassName(config.getSuperControllerClass());
-        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
-        VelocityContext ctx;
         for (TableInfo tableInfo : tableList) {
         for (TableInfo tableInfo : tableList) {
-            ctx = new VelocityContext();
-            if (null != injectionConfig) {
-                /**
-                 * 注入自定义配置
-                 */
-                injectionConfig.initMap();
-                ctx.put("cfg", injectionConfig.getMap());
-            }
             /* ---------- 添加导入包 ---------- */
             /* ---------- 添加导入包 ---------- */
             if (config.getGlobalConfig().isActiveRecord()) {
             if (config.getGlobalConfig().isActiveRecord()) {
                 // 开启 ActiveRecord 模式
                 // 开启 ActiveRecord 模式
@@ -193,220 +162,17 @@ public class AutoGenerator {
                     if (field.getPropertyType().equalsIgnoreCase("boolean")) {
                     if (field.getPropertyType().equalsIgnoreCase("boolean")) {
                         if (field.getPropertyName().startsWith("is")) {
                         if (field.getPropertyName().startsWith("is")) {
                             field.setPropertyName(config.getStrategyConfig(),
                             field.setPropertyName(config.getStrategyConfig(),
-                                    StringUtils.removePrefixAfterPrefixToLower(field.getPropertyName(), 2));
+                                StringUtils.removePrefixAfterPrefixToLower(field.getPropertyName(), 2));
                         }
                         }
                     }
                     }
                 }
                 }
             }
             }
-            // RequestMapping 连字符风格 user-info
-            if (config.getStrategyConfig().isControllerMappingHyphenStyle()) {
-                ctx.put("controllerMappingHyphenStyle", config.getStrategyConfig().isControllerMappingHyphenStyle());
-                ctx.put("controllerMappingHyphen", StringUtils.camelToHyphen(tableInfo.getEntityPath()));
-            }
-
-            ctx.put("restControllerStyle", config.getStrategyConfig().isRestControllerStyle());
-            ctx.put("package", packageInfo);
-            GlobalConfig globalConfig = config.getGlobalConfig();
-            ctx.put("author", globalConfig.getAuthor());
-            ctx.put("idType", globalConfig.getIdType() == null ? null : globalConfig.getIdType().toString());
-            ctx.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
-            ctx.put("versionFieldName", config.getStrategyConfig().getVersionFieldName());
-            ctx.put("activeRecord", globalConfig.isActiveRecord());
-            ctx.put("kotlin", globalConfig.isKotlin());
-            ctx.put("date", date);
-            ctx.put("table", tableInfo);
-            ctx.put("enableCache", globalConfig.isEnableCache());
-            ctx.put("baseResultMap", globalConfig.isBaseResultMap());
-            ctx.put("baseColumnList", globalConfig.isBaseColumnList());
-            ctx.put("entity", tableInfo.getEntityName());
-            ctx.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
-            ctx.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel());
-            ctx.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
-            ctx.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
-            ctx.put("superEntityClass", superEntityClass);
-            ctx.put("superMapperClassPackage", config.getSuperMapperClass());
-            ctx.put("superMapperClass", superMapperClass);
-            ctx.put("superServiceClassPackage", config.getSuperServiceClass());
-            ctx.put("superServiceClass", superServiceClass);
-            ctx.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
-            ctx.put("superServiceImplClass", superServiceImplClass);
-            ctx.put("superControllerClassPackage", config.getSuperControllerClass());
-            ctx.put("superControllerClass", superControllerClass);
-            ctxData.put(tableInfo.getEntityName(), ctx);
         }
         }
-        return ctxData;
-    }
-
-    /**
-     * <p>
-     * 获取类名
-     * </p>
-     *
-     * @param classPath
-     * @return
-     */
-    private String getSuperClassName(String classPath) {
-        if (StringUtils.isEmpty(classPath)) {
-            return null;
-        }
-        return classPath.substring(classPath.lastIndexOf(".") + 1);
-    }
-
-    /**
-     * <p>
-     * 处理输出目录
-     * </p>
-     *
-     * @param pathInfo 路径信息
-     */
-    private void mkdirs(Map<String, String> pathInfo) {
-        for (Map.Entry<String, String> entry : pathInfo.entrySet()) {
-            File dir = new File(entry.getValue());
-            if (!dir.exists()) {
-                boolean result = dir.mkdirs();
-                if (result) {
-                    logger.debug("创建目录: [" + entry.getValue() + "]");
-                }
-            }
-        }
-    }
-
-    /**
-     * <p>
-     * 合成上下文与模板
-     * </p>
-     *
-     * @param context vm上下文
-     */
-    private void batchOutput(String entityName, VelocityContext context) {
-        try {
-            TableInfo tableInfo = (TableInfo) context.get("table");
-            Map<String, String> pathInfo = config.getPathInfo();
-            String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + this.suffixJavaOrKt()), entityName);
-            String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + this.suffixJavaOrKt()), entityName);
-            String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
-            String serviceFile = String.format((pathInfo.get(ConstVal.SERIVCE_PATH) + File.separator + tableInfo.getServiceName() + this.suffixJavaOrKt()), entityName);
-            String implFile = String.format((pathInfo.get(ConstVal.SERVICEIMPL_PATH) + File.separator + tableInfo.getServiceImplName() + this.suffixJavaOrKt()), entityName);
-            String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + this.suffixJavaOrKt()), entityName);
-
-            TemplateConfig template = config.getTemplate();
-
-            // 根据override标识来判断是否需要创建文件
-            if (isCreate(entityFile)) {
-                vmToFile(context, template.getEntity(config.getGlobalConfig().isKotlin()), entityFile);
-            }
-            if (isCreate(mapperFile)) {
-                vmToFile(context, template.getMapper(), mapperFile);
-            }
-            if (isCreate(xmlFile)) {
-                vmToFile(context, template.getXml(), xmlFile);
-            }
-            if (isCreate(serviceFile)) {
-                vmToFile(context, template.getService(), serviceFile);
-            }
-            if (isCreate(implFile)) {
-                vmToFile(context, template.getServiceImpl(), implFile);
-            }
-            if (isCreate(controllerFile)) {
-                vmToFile(context, template.getController(), controllerFile);
-            }
-            if (injectionConfig != null) {
-                /**
-                 * 输出自定义文件内容
-                 */
-                List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
-                if (CollectionUtils.isNotEmpty(focList)) {
-                    for (FileOutConfig foc : focList) {
-                        // 判断自定义文件是否存在
-                        if (isCreate(foc.outputFile(tableInfo))) {
-                            vmToFile(context, foc.getTemplatePath(), foc.outputFile(tableInfo));
-                        }
-                    }
-                }
-            }
-
-        } catch (IOException e) {
-            logger.error("无法创建文件,请检查配置信息!", e);
-        }
-    }
-
-    /**
-     * 文件后缀
-     */
-    protected String suffixJavaOrKt() {
-        return config.getGlobalConfig().isKotlin() ? ConstVal.KT_SUFFIX : ConstVal.JAVA_SUFFIX;
-    }
-
-    /**
-     * <p>
-     * 将模板转化成为文件
-     * </p>
-     *
-     * @param context      内容对象
-     * @param templatePath 模板文件
-     * @param outputFile   文件生成的目录
-     */
-    private void vmToFile(VelocityContext context, String templatePath, String outputFile) throws IOException {
-        if (StringUtils.isEmpty(templatePath)) {
-            return;
-        }
-        VelocityEngine velocity = getVelocityEngine();
-        Template template = velocity.getTemplate(templatePath, ConstVal.UTF8);
-        File file = new File(outputFile);
-        if (!file.getParentFile().exists()) {
-            // 如果文件所在的目录不存在,则创建目录
-            if (!file.getParentFile().mkdirs()) {
-                logger.debug("创建文件所在的目录失败!");
-                return;
-            }
-        }
-        FileOutputStream fos = new FileOutputStream(outputFile);
-        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, ConstVal.UTF8));
-        template.merge(context, writer);
-        writer.close();
-        logger.debug("模板:" + templatePath + ";  文件:" + outputFile);
-    }
-
-    /**
-     * 设置模版引擎,主要指向获取模版路径
-     */
-    private VelocityEngine getVelocityEngine() {
-        if (engine == null) {
-            Properties p = new Properties();
-            p.setProperty(ConstVal.VM_LOADPATH_KEY, ConstVal.VM_LOADPATH_VALUE);
-            p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
-            p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
-            p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
-            p.setProperty("file.resource.loader.unicode", "true");
-            engine = new VelocityEngine(p);
-        }
-        return engine;
-    }
-
-    /**
-     * 检测文件是否存在
-     *
-     * @return 是否
-     */
-    private boolean isCreate(String filePath) {
-        File file = new File(filePath);
-        return !file.exists() || config.getGlobalConfig().isFileOverride();
+        return config.setTableInfoList(tableList);
     }
     }
 
 
     // ==================================  相关配置  ==================================
     // ==================================  相关配置  ==================================
 
 
-    /**
-     * 初始化配置
-     */
-    protected void initConfig() {
-        if (null == config) {
-            config = new ConfigBuilder(packageInfo, dataSource, strategy, template, globalConfig);
-            if (null != injectionConfig) {
-                injectionConfig.setConfig(config);
-            }
-        }
-    }
-
     public DataSourceConfig getDataSource() {
     public DataSourceConfig getDataSource() {
         return dataSource;
         return dataSource;
     }
     }
@@ -469,4 +235,13 @@ public class AutoGenerator {
         this.injectionConfig = injectionConfig;
         this.injectionConfig = injectionConfig;
         return this;
         return this;
     }
     }
+
+    public AbstractTemplateEngine getTemplateEngine() {
+        return templateEngine;
+    }
+
+    public AutoGenerator setTemplateEngine(AbstractTemplateEngine templateEngine) {
+        this.templateEngine = templateEngine;
+        return this;
+    }
 }
 }

+ 12 - 7
mybatis-plus-generate/src/main/java/com/baomidou/mybatisplus/generator/config/ConstVal.java

@@ -49,13 +49,13 @@ public class ConstVal {
     public static final String KT_SUFFIX = ".kt";
     public static final String KT_SUFFIX = ".kt";
     public static final String XML_SUFFIX = ".xml";
     public static final String XML_SUFFIX = ".xml";
 
 
-    public static final String TEMPLATE_ENTITY_JAVA = "/templates/entity.java.vm";
-    public static final String TEMPLATE_ENTITY_KT = "/templates/entity.kt.vm";
-    public static final String TEMPLATE_MAPPER = "/templates/mapper.java.vm";
-    public static final String TEMPLATE_XML = "/templates/mapper.xml.vm";
-    public static final String TEMPLATE_SERVICE = "/templates/service.java.vm";
-    public static final String TEMPLATE_SERVICEIMPL = "/templates/serviceImpl.java.vm";
-    public static final String TEMPLATE_CONTROLLER = "/templates/controller.java.vm";
+    public static final String TEMPLATE_ENTITY_JAVA = "/templates/entity.java";
+    public static final String TEMPLATE_ENTITY_KT = "/templates/entity.kt";
+    public static final String TEMPLATE_MAPPER = "/templates/mapper.java";
+    public static final String TEMPLATE_XML = "/templates/mapper.xml";
+    public static final String TEMPLATE_SERVICE = "/templates/service.java";
+    public static final String TEMPLATE_SERVICEIMPL = "/templates/serviceImpl.java";
+    public static final String TEMPLATE_CONTROLLER = "/templates/controller.java";
 
 
     public static final String VM_LOADPATH_KEY = "file.resource.loader.class";
     public static final String VM_LOADPATH_KEY = "file.resource.loader.class";
     public static final String VM_LOADPATH_VALUE = "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader";
     public static final String VM_LOADPATH_VALUE = "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader";
@@ -64,4 +64,9 @@ public class ConstVal {
     public static final String SUPERD_SERVICE_CLASS = "com.baomidou.mybatisplus.service.IService";
     public static final String SUPERD_SERVICE_CLASS = "com.baomidou.mybatisplus.service.IService";
     public static final String SUPERD_SERVICEIMPL_CLASS = "com.baomidou.mybatisplus.service.impl.ServiceImpl";
     public static final String SUPERD_SERVICEIMPL_CLASS = "com.baomidou.mybatisplus.service.impl.ServiceImpl";
 
 
+    /**
+     * 输出相关常量
+     */
+    public static final String OUT_CONFIG = "config";
+
 }
 }

+ 18 - 1
mybatis-plus-generate/src/main/java/com/baomidou/mybatisplus/generator/config/builder/ConfigBuilder.java

@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
 
 
+import com.baomidou.mybatisplus.generator.InjectionConfig;
 import com.baomidou.mybatisplus.generator.config.ConstVal;
 import com.baomidou.mybatisplus.generator.config.ConstVal;
 import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
 import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
 import com.baomidou.mybatisplus.generator.config.GlobalConfig;
 import com.baomidou.mybatisplus.generator.config.GlobalConfig;
@@ -91,11 +92,14 @@ public class ConfigBuilder {
      * 策略配置
      * 策略配置
      */
      */
     private StrategyConfig strategyConfig;
     private StrategyConfig strategyConfig;
-
     /**
     /**
      * 全局配置信息
      * 全局配置信息
      */
      */
     private GlobalConfig globalConfig;
     private GlobalConfig globalConfig;
+    /**
+     * 注入配置信息
+     */
+    private InjectionConfig injectionConfig;
 
 
     /**
     /**
      * <p>
      * <p>
@@ -201,6 +205,11 @@ public class ConfigBuilder {
         return tableInfoList;
         return tableInfoList;
     }
     }
 
 
+    public ConfigBuilder setTableInfoList(List<TableInfo> tableInfoList) {
+        this.tableInfoList = tableInfoList;
+        return this;
+    }
+
     /**
     /**
      * <p>
      * <p>
      * 模板路径配置信息
      * 模板路径配置信息
@@ -714,4 +723,12 @@ public class ConfigBuilder {
         return this;
         return this;
     }
     }
 
 
+    public InjectionConfig getInjectionConfig() {
+        return injectionConfig;
+    }
+
+    public ConfigBuilder setInjectionConfig(InjectionConfig injectionConfig) {
+        this.injectionConfig = injectionConfig;
+        return this;
+    }
 }
 }

+ 2 - 1
mybatis-plus-generate/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableInfo.java

@@ -47,7 +47,8 @@ public class TableInfo {
     private String controllerName;
     private String controllerName;
 
 
     private List<TableField> fields;
     private List<TableField> fields;
-    private List<TableField> commonFields;// 公共字段
+    // 公共字段
+    private List<TableField> commonFields;
     private List<String> importPackages = new ArrayList<>();
     private List<String> importPackages = new ArrayList<>();
     private String fieldNames;
     private String fieldNames;
 
 

+ 132 - 0
mybatis-plus-generate/src/main/java/com/baomidou/mybatisplus/generator/engine/AbstractTemplateEngine.java

@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.baomidou.mybatisplus.generator.engine;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+
+/**
+ * <p>
+ * 模板引擎抽象类
+ * </p>
+ *
+ * @author hubin
+ * @since 2018-01-10
+ */
+public abstract class AbstractTemplateEngine {
+
+    protected static final Logger logger = LoggerFactory.getLogger(AbstractTemplateEngine.class);
+    /**
+     * 配置信息
+     */
+    private ConfigBuilder configBuilder;
+
+    /**
+     * <p>
+     * 模板引擎初始化
+     * </p>
+     */
+    public AbstractTemplateEngine init(ConfigBuilder configBuilder) {
+        this.configBuilder = configBuilder;
+        return this;
+    }
+
+    /**
+     * <p>
+     * 输出 java xml 文件
+     * </p>
+     */
+    public abstract AbstractTemplateEngine batchOutput();
+
+
+    /**
+     * <p>
+     * 处理输出目录
+     * </p>
+     */
+    public AbstractTemplateEngine mkdirs() {
+        Map<String, String> pathInfo = this.getConfigBuilder().getPathInfo();
+        for (Map.Entry<String, String> entry : pathInfo.entrySet()) {
+            File dir = new File(entry.getValue());
+            if (!dir.exists()) {
+                boolean result = dir.mkdirs();
+                if (result) {
+                    logger.debug("创建目录: [" + entry.getValue() + "]");
+                }
+            }
+        }
+        return this;
+    }
+
+
+    /**
+     * <p>
+     * 打开输出目录
+     * </p>
+     */
+    public void open() {
+        if (this.getConfigBuilder().getGlobalConfig().isOpen()) {
+            try {
+                String osName = System.getProperty("os.name");
+                if (osName != null) {
+                    if (osName.contains("Mac")) {
+                        Runtime.getRuntime().exec("open " + this.getConfigBuilder().getGlobalConfig().getOutputDir());
+                    } else if (osName.contains("Windows")) {
+                        Runtime.getRuntime().exec("cmd /c start " + this.getConfigBuilder().getGlobalConfig().getOutputDir());
+                    } else {
+                        logger.debug("文件输出目录:" + this.getConfigBuilder().getGlobalConfig().getOutputDir());
+                    }
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+
+    /**
+     * 检测文件是否存在
+     *
+     * @return 是否
+     */
+    protected boolean isCreate(String filePath) {
+        File file = new File(filePath);
+        return !file.exists() || this.getConfigBuilder().getGlobalConfig().isFileOverride();
+    }
+
+    /**
+     * 文件后缀
+     */
+    protected String suffixJavaOrKt() {
+        return this.getConfigBuilder().getGlobalConfig().isKotlin() ? ConstVal.KT_SUFFIX : ConstVal.JAVA_SUFFIX;
+    }
+
+    public ConfigBuilder getConfigBuilder() {
+        return configBuilder;
+    }
+
+    public AbstractTemplateEngine setConfigBuilder(ConfigBuilder configBuilder) {
+        this.configBuilder = configBuilder;
+        return this;
+    }
+}

+ 233 - 0
mybatis-plus-generate/src/main/java/com/baomidou/mybatisplus/generator/engine/VelocityTemplateEngine.java

@@ -0,0 +1,233 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.baomidou.mybatisplus.generator.engine;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.generator.config.FileOutConfig;
+import com.baomidou.mybatisplus.generator.config.GlobalConfig;
+import com.baomidou.mybatisplus.generator.config.TemplateConfig;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * Velocity 模板引擎实现文件输出
+ * </p>
+ *
+ * @author hubin
+ * @since 2018-01-10
+ */
+public class VelocityTemplateEngine extends AbstractTemplateEngine {
+
+    private VelocityEngine velocityEngine;
+
+    @Override
+    public VelocityTemplateEngine init(ConfigBuilder configBuilder) {
+        super.init(configBuilder);
+        if (null == velocityEngine) {
+            Properties p = new Properties();
+            p.setProperty(ConstVal.VM_LOADPATH_KEY, ConstVal.VM_LOADPATH_VALUE);
+            p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
+            p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
+            p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
+            p.setProperty("file.resource.loader.unicode", "true");
+            velocityEngine = new VelocityEngine(p);
+        }
+        return this;
+    }
+
+    @Override
+    public VelocityTemplateEngine batchOutput() {
+        try {
+            List<TableInfo> tableInfoList = this.getConfigBuilder().getTableInfoList();
+            for (TableInfo tableInfo : tableInfoList) {
+                VelocityContext context = this.getVelocityContextInfo(tableInfo);
+                String entityName = tableInfo.getEntityName();
+                Map<String, String> pathInfo = this.getConfigBuilder().getPathInfo();
+                String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + this.suffixJavaOrKt()), entityName);
+                String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + this.suffixJavaOrKt()), entityName);
+                String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
+                String serviceFile = String.format((pathInfo.get(ConstVal.SERIVCE_PATH) + File.separator + tableInfo.getServiceName() + this.suffixJavaOrKt()), entityName);
+                String implFile = String.format((pathInfo.get(ConstVal.SERVICEIMPL_PATH) + File.separator + tableInfo.getServiceImplName() + this.suffixJavaOrKt()), entityName);
+                String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + this.suffixJavaOrKt()), entityName);
+                TemplateConfig template = this.getConfigBuilder().getTemplate();
+                // 根据override标识来判断是否需要创建文件
+                if (isCreate(entityFile)) {
+                    this.vmToFile(context, this.templateFilePath(template.getEntity(this.getConfigBuilder()
+                        .getGlobalConfig().isKotlin())), entityFile);
+                }
+                if (isCreate(mapperFile)) {
+                    this.vmToFile(context, this.templateFilePath(template.getMapper()), mapperFile);
+                }
+                if (isCreate(xmlFile)) {
+                    this.vmToFile(context, this.templateFilePath(template.getXml()), xmlFile);
+                }
+                if (isCreate(serviceFile)) {
+                    this.vmToFile(context, this.templateFilePath(template.getService()), serviceFile);
+                }
+                if (isCreate(implFile)) {
+                    this.vmToFile(context, this.templateFilePath(template.getServiceImpl()), implFile);
+                }
+                if (isCreate(controllerFile)) {
+                    this.vmToFile(context, this.templateFilePath(template.getController()), controllerFile);
+                }
+                if (this.getConfigBuilder().getInjectionConfig() != null) {
+                    /**
+                     * 输出自定义文件内容
+                     */
+                    List<FileOutConfig> focList = this.getConfigBuilder().getInjectionConfig().getFileOutConfigList();
+                    if (CollectionUtils.isNotEmpty(focList)) {
+                        for (FileOutConfig foc : focList) {
+                            // 判断自定义文件是否存在
+                            if (isCreate(foc.outputFile(tableInfo))) {
+                                this.vmToFile(context, foc.getTemplatePath(), foc.outputFile(tableInfo));
+                            }
+                        }
+                    }
+                }
+
+            }
+        } catch (IOException e) {
+            logger.error("无法创建文件,请检查配置信息!", e);
+        }
+        return this;
+    }
+
+    /**
+     * <p>
+     * 模板真实文件路径加上 .vm
+     * </p>
+     *
+     * @param filePath 文件路径
+     * @return
+     */
+    protected String templateFilePath(String filePath) {
+        StringBuilder fp = new StringBuilder();
+        fp.append(filePath).append(".vm");
+        return fp.toString();
+    }
+
+    /**
+     * <p>
+     * 获取模板引擎渲染上下文信息
+     * </p>
+     *
+     * @param tableInfo 表信息对象
+     * @return
+     */
+    public VelocityContext getVelocityContextInfo(TableInfo tableInfo) {
+        VelocityContext ctx = new VelocityContext();
+        ConfigBuilder config = this.getConfigBuilder();
+        // RequestMapping 连字符风格 user-info
+        if (config.getStrategyConfig().isControllerMappingHyphenStyle()) {
+            ctx.put("controllerMappingHyphenStyle", config.getStrategyConfig().isControllerMappingHyphenStyle());
+            ctx.put("controllerMappingHyphen", StringUtils.camelToHyphen(tableInfo.getEntityPath()));
+        }
+        ctx.put("restControllerStyle", config.getStrategyConfig().isRestControllerStyle());
+        ctx.put("package", config.getPackageInfo());
+        GlobalConfig globalConfig = config.getGlobalConfig();
+        ctx.put("author", globalConfig.getAuthor());
+        ctx.put("idType", globalConfig.getIdType() == null ? null : globalConfig.getIdType().toString());
+        ctx.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
+        ctx.put("versionFieldName", config.getStrategyConfig().getVersionFieldName());
+        ctx.put("activeRecord", globalConfig.isActiveRecord());
+        ctx.put("kotlin", globalConfig.isKotlin());
+        ctx.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
+        ctx.put("table", tableInfo);
+        ctx.put("enableCache", globalConfig.isEnableCache());
+        ctx.put("baseResultMap", globalConfig.isBaseResultMap());
+        ctx.put("baseColumnList", globalConfig.isBaseColumnList());
+        ctx.put("entity", tableInfo.getEntityName());
+        ctx.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
+        ctx.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel());
+        ctx.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
+        ctx.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
+        ctx.put("superEntityClass", this.getSuperClassName(config.getSuperEntityClass()));
+        ctx.put("superMapperClassPackage", config.getSuperMapperClass());
+        ctx.put("superMapperClass", this.getSuperClassName(config.getSuperMapperClass()));
+        ctx.put("superServiceClassPackage", config.getSuperServiceClass());
+        ctx.put("superServiceClass", this.getSuperClassName(config.getSuperServiceClass()));
+        ctx.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
+        ctx.put("superServiceImplClass", this.getSuperClassName(config.getSuperServiceImplClass()));
+        ctx.put("superControllerClassPackage", config.getSuperControllerClass());
+        ctx.put("superControllerClass", this.getSuperClassName(config.getSuperControllerClass()));
+        return ctx;
+    }
+
+
+    /**
+     * <p>
+     * 获取类名
+     * </p>
+     *
+     * @param classPath
+     * @return
+     */
+    private String getSuperClassName(String classPath) {
+        if (StringUtils.isEmpty(classPath)) {
+            return null;
+        }
+        return classPath.substring(classPath.lastIndexOf(".") + 1);
+    }
+
+    /**
+     * <p>
+     * 将模板转化成为文件
+     * </p>
+     *
+     * @param context      内容对象
+     * @param templatePath 模板文件
+     * @param outputFile   文件生成的目录
+     */
+    private void vmToFile(VelocityContext context, String templatePath, String outputFile) throws IOException {
+        if (StringUtils.isEmpty(templatePath)) {
+            return;
+        }
+        Template template = velocityEngine.getTemplate(templatePath, ConstVal.UTF8);
+        File file = new File(outputFile);
+        if (!file.getParentFile().exists()) {
+            // 如果文件所在的目录不存在,则创建目录
+            if (!file.getParentFile().mkdirs()) {
+                logger.debug("创建文件所在的目录失败!");
+                return;
+            }
+        }
+        FileOutputStream fos = new FileOutputStream(outputFile);
+        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, ConstVal.UTF8));
+        template.merge(context, writer);
+        writer.close();
+        logger.debug("模板:" + templatePath + ";  文件:" + outputFile);
+    }
+
+}

+ 0 - 4
mybatis-plus-generate/src/main/resources/templates/entity.java.vm

@@ -1,9 +1,5 @@
 package ${package.Entity};
 package ${package.Entity};
 
 
-#if(${activeRecord})
-import java.io.Serializable;
-
-#end
 #foreach($pkg in ${table.importPackages})
 #foreach($pkg in ${table.importPackages})
 import ${pkg};
 import ${pkg};
 #end
 #end