mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-10-15 00:57:14 +08:00
feat: 新增生成代码接口(后端代码)
This commit is contained in:
@@ -16,11 +16,15 @@
|
||||
|
||||
package top.charles7c.cnadmin.tool.config.properties;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
|
||||
/**
|
||||
* 代码生成器配置属性
|
||||
*
|
||||
@@ -36,4 +40,26 @@ public class GeneratorProperties {
|
||||
* 排除数据表(哪些数据表不展示在代码生成中)
|
||||
*/
|
||||
private String[] excludeTables;
|
||||
|
||||
/**
|
||||
* 模板配置
|
||||
*/
|
||||
private Map<String, TemplateConfig> templateConfigs = MapUtil.newHashMap(true);
|
||||
|
||||
/**
|
||||
* 模板配置
|
||||
*/
|
||||
@Data
|
||||
public static class TemplateConfig {
|
||||
|
||||
/**
|
||||
* 模板路径
|
||||
*/
|
||||
private String templatePath;
|
||||
|
||||
/**
|
||||
* 包名称
|
||||
*/
|
||||
private String packageName;
|
||||
}
|
||||
}
|
||||
|
@@ -18,19 +18,25 @@ package top.charles7c.cnadmin.tool.model.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import top.charles7c.cnadmin.common.constant.RegexConsts;
|
||||
|
||||
@@ -78,6 +84,7 @@ public class GenConfigDO implements Serializable {
|
||||
*/
|
||||
@Schema(description = "前端路径")
|
||||
@Length(max = 255, message = "前端路径不能超过 {max} 个字符")
|
||||
@Pattern(regexp = "^(?=.*src\\/views)(?!.*\\/views\\/?$).*", message = "前端路径配置错误")
|
||||
private String frontendPath;
|
||||
|
||||
/**
|
||||
@@ -123,7 +130,28 @@ public class GenConfigDO implements Serializable {
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 类名前缀
|
||||
*/
|
||||
@Setter(AccessLevel.NONE)
|
||||
@JsonIgnore
|
||||
@TableField(exist = false)
|
||||
private String classNamePrefix;
|
||||
|
||||
/**
|
||||
* 字段配置信息
|
||||
*/
|
||||
@JsonIgnore
|
||||
@TableField(exist = false)
|
||||
private List<FieldConfigDO> fieldConfigs;
|
||||
|
||||
public GenConfigDO(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getClassNamePrefix() {
|
||||
String rawClassName = StrUtil.isNotBlank(this.tablePrefix)
|
||||
? StrUtil.removePrefix(this.tableName, this.tablePrefix) : this.tableName;
|
||||
return StrUtil.upperFirst(StrUtil.toCamelCase(rawClassName));
|
||||
}
|
||||
}
|
||||
|
@@ -43,16 +43,16 @@ public class GenConfigRequest implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 字段配置
|
||||
* 字段配置信息
|
||||
*/
|
||||
@Schema(description = "字段配置")
|
||||
@Schema(description = "字段配置信息")
|
||||
@NotEmpty(message = "字段配置不能为空")
|
||||
private List<FieldConfigDO> fieldConfigs = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 生成配置
|
||||
* 生成配置信息
|
||||
*/
|
||||
@Schema(description = "生成配置")
|
||||
@Schema(description = "生成配置信息")
|
||||
@NotNull(message = "生成配置不能为空")
|
||||
private GenConfigDO genConfig;
|
||||
}
|
||||
|
@@ -79,4 +79,12 @@ public interface GeneratorService {
|
||||
* 表名称
|
||||
*/
|
||||
void saveConfig(GenConfigRequest request, String tableName);
|
||||
|
||||
/**
|
||||
* 生成代码
|
||||
*
|
||||
* @param tableName
|
||||
* 表名称
|
||||
*/
|
||||
void generate(String tableName);
|
||||
}
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package top.charles7c.cnadmin.tool.service.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -35,15 +37,24 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.meta.Column;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
|
||||
import top.charles7c.cnadmin.common.constant.StringConsts;
|
||||
import top.charles7c.cnadmin.common.enums.QueryTypeEnum;
|
||||
import top.charles7c.cnadmin.common.exception.ServiceException;
|
||||
import top.charles7c.cnadmin.common.model.query.PageQuery;
|
||||
import top.charles7c.cnadmin.common.model.vo.PageDataVO;
|
||||
import top.charles7c.cnadmin.common.util.TemplateUtils;
|
||||
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
|
||||
import top.charles7c.cnadmin.tool.config.properties.GeneratorProperties;
|
||||
import top.charles7c.cnadmin.tool.config.properties.GeneratorProperties.TemplateConfig;
|
||||
import top.charles7c.cnadmin.tool.mapper.FieldConfigMapper;
|
||||
import top.charles7c.cnadmin.tool.mapper.GenConfigMapper;
|
||||
import top.charles7c.cnadmin.tool.model.entity.FieldConfigDO;
|
||||
@@ -182,6 +193,10 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
|
||||
// 保存或更新生成配置信息
|
||||
GenConfigDO newGenConfig = request.getGenConfig();
|
||||
String frontendPath = newGenConfig.getFrontendPath();
|
||||
if (StrUtil.isNotBlank(frontendPath)) {
|
||||
CheckUtils.throwIf(!StrUtil.containsAll(frontendPath, "src", "views"), "前端路径配置错误");
|
||||
}
|
||||
GenConfigDO oldGenConfig = genConfigMapper.selectById(tableName);
|
||||
if (null != oldGenConfig) {
|
||||
BeanUtil.copyProperties(newGenConfig, oldGenConfig);
|
||||
@@ -190,4 +205,122 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
genConfigMapper.insert(newGenConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(String tableName) {
|
||||
GenConfigDO genConfig = genConfigMapper.selectById(tableName);
|
||||
CheckUtils.throwIfNull(genConfig, "请先进行数据表 [{}] 生成配置", tableName);
|
||||
List<FieldConfigDO> fieldConfigList = fieldConfigMapper.selectListByTableName(tableName);
|
||||
CheckUtils.throwIfEmpty(fieldConfigList, "请先进行数据表 [{}] 字段配置", tableName);
|
||||
Map<String, Object> genConfigMap = this.pretreatment(genConfig, fieldConfigList);
|
||||
|
||||
try {
|
||||
String classNamePrefix = genConfig.getClassNamePrefix();
|
||||
Boolean isOverride = genConfig.getIsOverride();
|
||||
// 生成后端代码
|
||||
// 1、确定后端代码基础路径
|
||||
// 例如:D:/continew-admin
|
||||
String projectPath = SystemUtil.getUserInfo().getCurrentDir();
|
||||
// 例如:D:/continew-admin/continew-admin-tool
|
||||
File backendModuleFile = new File(projectPath, genConfig.getModuleName());
|
||||
// 例如:D:/continew-admin/continew-admin-tool/src/main/java/top/charles7c/cnadmin/tool
|
||||
List<String> backendModuleChildPathList = CollUtil.newArrayList("src", "main", "java");
|
||||
backendModuleChildPathList.addAll(StrUtil.split(genConfig.getPackageName(), StringConsts.DOT));
|
||||
File backendParentFile =
|
||||
FileUtil.file(backendModuleFile, backendModuleChildPathList.toArray(new String[0]));
|
||||
// 2、生成代码
|
||||
Map<String, TemplateConfig> templateConfigMap = generatorProperties.getTemplateConfigs();
|
||||
for (Map.Entry<String, TemplateConfig> templateConfigEntry : templateConfigMap.entrySet()) {
|
||||
// 例如:D:/continew-admin/continew-admin-tool/src/main/java/top/charles7c/cnadmin/tool/service/impl/XxxServiceImpl.java
|
||||
TemplateConfig templateConfig = templateConfigEntry.getValue();
|
||||
String subPackageName = templateConfig.getPackageName();
|
||||
genConfigMap.put("subPackageName", subPackageName);
|
||||
File classParentFile =
|
||||
FileUtil.file(backendParentFile, StrUtil.splitToArray(subPackageName, StringConsts.DOT));
|
||||
String className = classNamePrefix + StrUtil.nullToEmpty(templateConfigEntry.getKey());
|
||||
genConfigMap.put("className", className);
|
||||
File classFile = new File(classParentFile, className + FileNameUtil.EXT_JAVA);
|
||||
// 如果已经存在,且不允许覆盖,则跳过
|
||||
if (classFile.exists() && !isOverride) {
|
||||
continue;
|
||||
}
|
||||
String content = TemplateUtils.render(templateConfig.getTemplatePath(), genConfigMap);
|
||||
FileUtil.writeString(content, classFile, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
// 生成前端代码
|
||||
String frontendPath = genConfig.getFrontendPath();
|
||||
if (StrUtil.isBlank(frontendPath)) {
|
||||
return;
|
||||
}
|
||||
// 1、生成 api 代码
|
||||
// 例如:D:/continew-admin/continew-admin-ui
|
||||
List<String> frontendSubPathList = StrUtil.split(frontendPath, "src");
|
||||
String frontendModulePath = frontendSubPathList.get(0);
|
||||
// 例如:D:/continew-admin/continew-admin-ui/src/api/tool/xxx.ts
|
||||
String moduleSimpleName = new File(frontendPath).getName();
|
||||
File apiParentFile = FileUtil.file(frontendModulePath, "src", "api", moduleSimpleName);
|
||||
String apiFileName = classNamePrefix.toLowerCase() + ".ts";
|
||||
File apiFile = new File(apiParentFile, apiFileName);
|
||||
if (apiFile.exists() && !isOverride) {
|
||||
return;
|
||||
}
|
||||
String apiContent = TemplateUtils.render("generator/api.ftl", genConfigMap);
|
||||
FileUtil.writeString(apiContent, apiFile, StandardCharsets.UTF_8);
|
||||
// 2、生成 view 代码
|
||||
// 例如:D:/continew-admin/continew-admin-ui/src/views/tool/xxx/index.vue
|
||||
File indexFile = FileUtil.file(frontendPath, classNamePrefix, "index.vue");
|
||||
if (indexFile.exists() && !isOverride) {
|
||||
return;
|
||||
}
|
||||
String indexContent = TemplateUtils.render("generator/index.ftl", genConfigMap);
|
||||
FileUtil.writeString(indexContent, indexFile, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
log.error("Generate code occurred an error: {}. tableName: {}.", e.getMessage(), tableName, e);
|
||||
throw new ServiceException("代码生成失败,请手动清理生成文件");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预处理生成配置
|
||||
*
|
||||
* @param genConfig
|
||||
* 生成配置
|
||||
* @param fieldConfigList
|
||||
* 字段配置列表
|
||||
* @return 处理后的生成配置
|
||||
*/
|
||||
private Map<String, Object> pretreatment(GenConfigDO genConfig, List<FieldConfigDO> fieldConfigList) {
|
||||
Map<String, Object> genConfigMap = MapUtil.newHashMap();
|
||||
genConfigMap.put("date", DateUtil.date().toString("yyyy/MM/dd HH:mm"));
|
||||
genConfigMap.put("hasLocalDateTime", false);
|
||||
genConfigMap.put("hasBigDecimal", false);
|
||||
genConfigMap.put("hasRequiredField", false);
|
||||
genConfigMap.put("hasListQueryField", false);
|
||||
for (FieldConfigDO fieldConfig : fieldConfigList) {
|
||||
String fieldType = fieldConfig.getFieldType();
|
||||
if ("LocalDateTime".equals(fieldType)) {
|
||||
genConfigMap.put("hasLocalDateTime", true);
|
||||
}
|
||||
if ("BigDecimal".equals(fieldType)) {
|
||||
genConfigMap.put("hasLocalDateTime", true);
|
||||
}
|
||||
if (Boolean.TRUE.equals(fieldConfig.getIsRequired())) {
|
||||
genConfigMap.put("hasRequiredField", true);
|
||||
}
|
||||
QueryTypeEnum queryType = fieldConfig.getQueryType();
|
||||
if (null != queryType && StrUtil.equalsAny(queryType.name(), QueryTypeEnum.IN.name(),
|
||||
QueryTypeEnum.NOT_IN.name(), QueryTypeEnum.BETWEEN.name())) {
|
||||
genConfigMap.put("hasListQueryField", true);
|
||||
}
|
||||
}
|
||||
genConfig.setFieldConfigs(fieldConfigList);
|
||||
genConfigMap.putAll(BeanUtil.beanToMap(genConfig));
|
||||
String packageName = genConfig.getPackageName();
|
||||
String moduleName =
|
||||
StrUtil.subSuf(packageName, StrUtil.lastIndexOfIgnoreCase(packageName, StringConsts.DOT) + 1);
|
||||
genConfigMap.put("moduleName", moduleName);
|
||||
genConfigMap.put("apiName", StrUtil.lowerFirst(genConfig.getClassNamePrefix()));
|
||||
return genConfigMap;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user