/** * 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; 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.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; 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.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; /** * 生成文件 * * @author YangHu, tangguo * @since 2016-08-30 */ public class AutoGenerator extends AbstractGenerator { private static final Log logger = LogFactory.getLog(AutoGenerator.class); /** * velocity引擎 */ private VelocityEngine engine; /** * 生成代码 */ public void execute() { 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(); } } logger.debug("==========================文件生成完成!!!=========================="); } /** * <p> * 开放表信息、预留子类重写 * </p> * * @param config 配置信息 * @return */ protected List<TableInfo> getAllTableInfoList(ConfigBuilder config) { return config.getTableInfoList(); } /** * 分析数据 * * @param config 总配置信息 * @return 解析数据结果集 */ private Map<String, VelocityContext> analyzeData(ConfigBuilder 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) { ctx = new VelocityContext(); if (null != injectionConfig) { /** * 注入自定义配置 */ injectionConfig.initMap(); ctx.put("cfg", injectionConfig.getMap()); } /* ---------- 添加导入包 ---------- */ if (config.getGlobalConfig().isActiveRecord()) { // 开启 ActiveRecord 模式 tableInfo.setImportPackages("com.baomidou.mybatisplus.activerecord.Model"); } if (tableInfo.isConvert()) { // 表注解 tableInfo.setImportPackages("com.baomidou.mybatisplus.annotations.TableName"); } if (StringUtils.isNotEmpty(config.getSuperEntityClass())) { // 父实体 tableInfo.setImportPackages(config.getSuperEntityClass()); } else { tableInfo.setImportPackages("java.io.Serializable"); } ctx.put("package", packageInfo); ctx.put("author", config.getGlobalConfig().getAuthor()); ctx.put("activeRecord", config.getGlobalConfig().isActiveRecord()); ctx.put("date", date); ctx.put("table", tableInfo); ctx.put("enableCache", config.getGlobalConfig().isEnableCache()); ctx.put("baseResultMap", config.getGlobalConfig().isBaseResultMap()); ctx.put("baseColumnList", config.getGlobalConfig().isBaseColumnList()); ctx.put("entity", tableInfo.getEntityName()); ctx.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant()); ctx.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel()); 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; } /** * 获取类名 * * @param classPath * @return */ private String getSuperClassName(String classPath) { if (StringUtils.isEmpty(classPath)) return null; return classPath.substring(classPath.lastIndexOf(".") + 1); } /** * 处理输出目录 * * @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() + "]"); } } } } /** * 合成上下文与模板 * * @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) + ConstVal.ENTITY_NAME), entityName); String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + ConstVal.JAVA_SUFFIX), 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() + ConstVal.JAVA_SUFFIX), entityName); String implFile = String.format((pathInfo.get(ConstVal.SERVICEIMPL_PATH) + File.separator + tableInfo.getServiceImplName() + ConstVal.JAVA_SUFFIX), entityName); String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + ConstVal.JAVA_SUFFIX), entityName); TemplateConfig template = config.getTemplate(); // 根据override标识来判断是否需要创建文件 if (isCreate(entityFile)) { vmToFile(context, template.getEntity(), 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) { vmToFile(context, foc.getTemplatePath(), foc.outputFile(tableInfo)); } } } } catch (IOException e) { logger.error("无法创建文件,请检查配置信息!", e); } } /** * 将模板转化成为文件 * * @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(Velocity.OUTPUT_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(); } }