update 优化 代码生成支持接入各种不同前端 只需要将模板放到vm文件夹下 前端传对应的文件夹名即可

This commit is contained in:
疯狂的狮子Li
2026-06-03 15:27:39 +08:00
parent 626496f4ca
commit 97524974d5
14 changed files with 1266 additions and 45 deletions
@@ -80,6 +80,11 @@ public interface GenConstants {
*/
String SORT_FIELD = "sortField";
/**
* 默认前端模板类型,对应 vm/vue 目录。
*/
String FRONTEND_TYPE_VUE = "vue";
/**
* 树根节点值
*/
@@ -268,10 +273,10 @@ public interface GenConstants {
// MyBatis MapperXML 模板
String XML_MAPPER_TEMPLATE_PATH = "vm/xml/mapper.xml.vm";
// 前端源码模板
String TS_API_TEMPLATE_PATH = "vm/vue/api.ts.vm";
String TS_TYPES_TEMPLATE_PATH = "vm/vue/types.ts.vm";
String VUE_INDEX_TEMPLATE_PATH = "vm/vue/index.vue.vm";
String VUE_INDEX_TREE_TEMPLATE_PATH = "vm/vue/index-tree.vue.vm";
String FRONTEND_API_TEMPLATE_NAME = "api.ts.vm";
String FRONTEND_TYPES_TEMPLATE_NAME = "types.ts.vm";
String FRONTEND_INDEX_TEMPLATE_PREFIX = "index";
String FRONTEND_INDEX_TREE_TEMPLATE_PREFIX = "index-tree";
// 数据库SQL模板
String SQL_ORACLE_TEMPLATE_PATH = "vm/sql/oracle.sql.vm";
String SQL_POSTGRES_TEMPLATE_PATH = "vm/sql/postgres.sql.vm";
@@ -290,10 +295,14 @@ public interface GenConstants {
, JAVA_SERVICE_IMPL_TEMPLATE_PATH
, JAVA_CONTROLLER_TEMPLATE_PATH
, XML_MAPPER_TEMPLATE_PATH
, TS_API_TEMPLATE_PATH
, TS_TYPES_TEMPLATE_PATH
, VUE_INDEX_TEMPLATE_PATH
, VUE_INDEX_TREE_TEMPLATE_PATH
, "vm/vue/api.ts.vm"
, "vm/vue/types.ts.vm"
, "vm/vue/index.vue.vm"
, "vm/vue/index-tree.vue.vm"
, "vm/react/api.ts.vm"
, "vm/react/types.ts.vm"
, "vm/react/index.tsx.vm"
, "vm/react/index-tree.tsx.vm"
, SQL_ORACLE_TEMPLATE_PATH
, SQL_POSTGRES_TEMPLATE_PATH
, SQL_SQLSERVER_TEMPLATE_PATH
@@ -61,6 +61,11 @@ public class GenTable extends BaseEntity {
*/
private String tplCategory;
/**
* 前端模板类型,对应 vm 下的模板目录
*/
private String frontendType;
/**
* 生成包路径
*/
@@ -453,7 +453,7 @@ public class GenTableServiceImpl implements IGenTableService {
table.setMenuIds(menuIds);
setPkColumn(table);
Dict context = TemplateEngineUtils.buildContext(table);
List<PathNamedTemplate> templates = TemplateEngineUtils.getTemplateList(table.getTplCategory(), table.getDataName());
List<PathNamedTemplate> templates = TemplateEngineUtils.getTemplateList(table.getTplCategory(), table.getDataName(), table.getFrontendType());
return new RenderContext(table, context, templates);
}
@@ -34,6 +34,7 @@ public class GenUtils {
genTable.setBusinessName(getBusinessName(genTable.getTableName()));
genTable.setFunctionName(replaceText(genTable.getTableComment()));
genTable.setFunctionAuthor(PROPERTIES.getAuthor());
genTable.setFrontendType(GenConstants.FRONTEND_TYPE_VUE);
genTable.setCreateTime(null);
genTable.setUpdateTime(null);
}
@@ -9,6 +9,7 @@ import cn.hutool.extra.template.TemplateUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
@@ -20,7 +21,11 @@ import org.dromara.gen.constant.GenConstants;
import org.dromara.gen.domain.GenTable;
import org.dromara.gen.domain.GenTableColumn;
import org.dromara.gen.util.template.PathNamedTemplate;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
import java.util.*;
import java.util.function.Consumer;
@@ -49,6 +54,7 @@ public class TemplateEngineUtils {
// 模板引擎
private static final TemplateEngine TEMPLATE_ENGINE;
private static final Map<String, PathNamedTemplate> TEMPLATE_MAPPER;
private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver();
static {
// 模板引擎初始化
@@ -85,6 +91,7 @@ public class TemplateEngineUtils {
String functionName = genTable.getFunctionName();
context.put("tplCategory", genTable.getTplCategory());
context.put("frontendType", resolveFrontendType(genTable.getFrontendType()));
context.put("tableName", genTable.getTableName());
context.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
context.put("ClassName", genTable.getClassName());
@@ -186,6 +193,18 @@ public class TemplateEngineUtils {
* @return 模板列表
*/
public static List<PathNamedTemplate> getTemplateList(String tplCategory, String dsName) {
return getTemplateList(tplCategory, dsName, GenConstants.FRONTEND_TYPE_VUE);
}
/**
* 获取模板信息
*
* @param tplCategory 前端页面模板分类
* @param dsName 数据源名称
* @param frontendType 前端模板类型
* @return 模板列表
*/
public static List<PathNamedTemplate> getTemplateList(String tplCategory, String dsName, String frontendType) {
List<PathNamedTemplate> templates = new ArrayList<>();
// 后端源码模板
templates.add(TEMPLATE_MAPPER.get(GenConstants.JAVA_DOMAIN_TEMPLATE_PATH));
@@ -198,8 +217,8 @@ public class TemplateEngineUtils {
// MyBatis MapperXML 模板
templates.add(TEMPLATE_MAPPER.get(GenConstants.XML_MAPPER_TEMPLATE_PATH));
// 前端 API 与类型模板
templates.add(TEMPLATE_MAPPER.get(GenConstants.TS_API_TEMPLATE_PATH));
templates.add(TEMPLATE_MAPPER.get(GenConstants.TS_TYPES_TEMPLATE_PATH));
templates.add(getTemplate(getFrontendApiTemplatePath(frontendType)));
templates.add(getTemplate(getFrontendTypesTemplatePath(frontendType)));
// 数据库模板
DataBaseType dataBaseType = DataBaseHelper.getDataBaseType(dsName);
if (dataBaseType.isOracle()) {
@@ -214,13 +233,27 @@ public class TemplateEngineUtils {
}
// 前端页面模板
if (GenConstants.TPL_CRUD.equals(tplCategory)) {
templates.add(TEMPLATE_MAPPER.get(GenConstants.VUE_INDEX_TEMPLATE_PATH));
templates.add(getTemplate(getFrontendIndexTemplatePath(frontendType)));
} else if (GenConstants.TPL_TREE.equals(tplCategory)) {
templates.add(TEMPLATE_MAPPER.get(GenConstants.VUE_INDEX_TREE_TEMPLATE_PATH));
templates.add(getTemplate(getFrontendIndexTreeTemplatePath(frontendType)));
}
return templates;
}
/**
* 获取模板,支持按前端模板类型动态加载 vm/{frontendType} 下的模板。
*
* @param templatePath 模板路径
* @return 带路径名的模板
*/
private static PathNamedTemplate getTemplate(String templatePath) {
PathNamedTemplate template = TEMPLATE_MAPPER.get(templatePath);
if (ObjectUtil.isNotNull(template)) {
return template;
}
return PathNamedTemplate.form(TEMPLATE_ENGINE, templatePath);
}
/**
* 获取文件名
*
@@ -242,7 +275,7 @@ public class TemplateEngineUtils {
String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
String mybatisPath = MYBATIS_PATH + "/" + moduleName;
String vuePath = "vue";
String frontendPath = getFrontendPath(genTable.getFrontendType());
// templatePath
// genFilePathFormat
if (template.contains("domain.java.vm")) {
@@ -264,17 +297,112 @@ public class TemplateEngineUtils {
} else if (template.contains("sql.vm")) {
fileName = businessName + "Menu.sql";
} else if (template.contains("api.ts.vm")) {
fileName = StringUtils.format("{}/api/{}/{}/index.ts", vuePath, moduleName, businessName);
fileName = StringUtils.format("{}/api/{}/{}/index.ts", frontendPath, moduleName, businessName);
} else if (template.contains("types.ts.vm")) {
fileName = StringUtils.format("{}/api/{}/{}/types.ts", vuePath, moduleName, businessName);
} else if (template.contains("index.vue.vm")) {
fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
} else if (template.contains("index-tree.vue.vm")) {
fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
fileName = StringUtils.format("{}/api/{}/{}/types.ts", frontendPath, moduleName, businessName);
} else if (isFrontendPageTemplate(template, GenConstants.FRONTEND_INDEX_TEMPLATE_PREFIX)) {
fileName = StringUtils.format("{}/views/{}/{}/index.{}", frontendPath, moduleName, businessName,
getFrontendPageExtension(template, GenConstants.FRONTEND_INDEX_TEMPLATE_PREFIX));
} else if (isFrontendPageTemplate(template, GenConstants.FRONTEND_INDEX_TREE_TEMPLATE_PREFIX)) {
fileName = StringUtils.format("{}/views/{}/{}/index.{}", frontendPath, moduleName, businessName,
getFrontendPageExtension(template, GenConstants.FRONTEND_INDEX_TREE_TEMPLATE_PREFIX));
}
return fileName;
}
/**
* 获取前端输出目录。
*
* @param frontendType 前端模板类型
* @return 前端输出目录
*/
private static String getFrontendPath(String frontendType) {
return resolveFrontendType(frontendType);
}
/**
* 获取前端页面文件扩展名。
*
* @param template 模板路径
* @param templatePrefix 模板文件名前缀
* @return 文件扩展名
*/
private static String getFrontendPageExtension(String template, String templatePrefix) {
String fileName = getTemplateFileName(template);
return fileName.substring((templatePrefix + ".").length(), fileName.length() - ".vm".length());
}
private static String getFrontendApiTemplatePath(String frontendType) {
return getFrontendTemplatePath(frontendType, GenConstants.FRONTEND_API_TEMPLATE_NAME);
}
private static String getFrontendTypesTemplatePath(String frontendType) {
return getFrontendTemplatePath(frontendType, GenConstants.FRONTEND_TYPES_TEMPLATE_NAME);
}
private static String getFrontendIndexTemplatePath(String frontendType) {
return getFrontendPageTemplatePath(frontendType, GenConstants.FRONTEND_INDEX_TEMPLATE_PREFIX);
}
private static String getFrontendIndexTreeTemplatePath(String frontendType) {
return getFrontendPageTemplatePath(frontendType, GenConstants.FRONTEND_INDEX_TREE_TEMPLATE_PREFIX);
}
/**
* 解析前端模板类型。
*
* @param frontendType 前端模板类型
* @return 已规范化的模板目录名
*/
private static String resolveFrontendType(String frontendType) {
String type = StringUtils.blankToDefault(frontendType, GenConstants.FRONTEND_TYPE_VUE);
if (!type.matches("[A-Za-z0-9_-]+")) {
throw new ServiceException("前端模板类型仅支持字母、数字、下划线和中划线");
}
return type;
}
private static String getFrontendTemplatePath(String frontendType, String templateName) {
return StringUtils.format("vm/{}/{}", resolveFrontendType(frontendType), templateName);
}
/**
* 获取前端页面模板路径,页面输出扩展名由模板文件名决定。
*
* @param frontendType 前端模板类型
* @param templatePrefix 页面模板文件名前缀
* @return 页面模板路径
*/
private static String getFrontendPageTemplatePath(String frontendType, String templatePrefix) {
String type = resolveFrontendType(frontendType);
String pattern = StringUtils.format("classpath*:vm/{}/{}.*.vm", type, templatePrefix);
try {
Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(pattern);
if (resources.length == 0) {
throw new ServiceException(StringUtils.format("未找到前端模板: vm/{}/{}.*.vm", type, templatePrefix));
}
return Arrays.stream(resources)
.map(Resource::getFilename)
.filter(StringUtils::isNotBlank)
.sorted()
.findFirst()
.map(fileName -> StringUtils.format("vm/{}/{}", type, fileName))
.orElseThrow(() -> new ServiceException(StringUtils.format("未找到前端模板: vm/{}/{}.*.vm", type, templatePrefix)));
} catch (IOException e) {
throw new ServiceException(StringUtils.format("读取前端模板失败: vm/{}/{}.*.vm", type, templatePrefix), e);
}
}
private static boolean isFrontendPageTemplate(String template, String templatePrefix) {
String fileName = getTemplateFileName(template);
return fileName.startsWith(templatePrefix + ".") && fileName.endsWith(".vm");
}
private static String getTemplateFileName(String template) {
int index = Math.max(template.lastIndexOf('/'), template.lastIndexOf('\\'));
return index >= 0 ? template.substring(index + 1) : template;
}
/**
* 获取包前缀
*