实现数据库字段的解析

pull/2/head
YunaiV 2021-01-31 16:42:16 +08:00
parent 58f83a2bd1
commit 0be7138eef
12 changed files with 310 additions and 297 deletions

View File

@ -32,82 +32,9 @@ public class GenConstants {
*/
public static final String PARENT_MENU_NAME = "parentMenuName";
/**
*
*/
public static final String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"};
/**
*
*/
public static final String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"};
/**
*
*/
public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"};
/**
*
*/
public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
"bit", "bigint", "float", "double", "decimal"};
/**
*
*/
public static final String[] COLUMNNAME_NOT_EDIT = {"id", "create_by", "create_time", "del_flag"};
/**
*
*/
public static final String[] COLUMNNAME_NOT_LIST = {"id", "create_by", "create_time", "del_flag", "update_by",
"update_time"};
/**
*
*/
public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by",
"update_time", "remark"};
/**
* Entity
*/
public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime", "remark"};
/**
* Tree
*/
public static final String[] TREE_ENTITY = {"parentName", "parentId", "orderNum", "ancestors", "children"};
/**
*
*/
public static final String TYPE_STRING = "String";
/**
*
*/
public static final String TYPE_INTEGER = "Integer";
/**
*
*/
public static final String TYPE_LONG = "Long";
/**
*
*/
public static final String TYPE_DOUBLE = "Double";
/**
*
*/
public static final String TYPE_BIGDECIMAL = "BigDecimal";
/**
*
*/
public static final String TYPE_DATE = "Date";
}

View File

@ -1,218 +0,0 @@
package com.ruoyi.generator.util;
import java.util.Arrays;
import org.apache.commons.lang3.RegExUtils;
import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.config.GenConfig;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
/**
*
*
* @author ruoyi
*/
public class GenUtils {
/**
*
*/
public static void initTable(GenTable genTable, String operName) {
genTable.setClassName(convertClassName(genTable.getTableName()));
genTable.setPackageName(GenConfig.getPackageName());
genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
genTable.setBusinessName(getBusinessName(genTable.getTableName()));
genTable.setFunctionName(replaceText(genTable.getTableComment()));
genTable.setFunctionAuthor(GenConfig.getAuthor());
genTable.setCreateBy(operName);
}
/**
*
*/
public static void initColumnField(GenTableColumn column, GenTable table) {
String dataType = getDbType(column.getColumnType());
String columnName = column.getColumnName();
column.setTableId(table.getTableId());
column.setCreateBy(table.getCreateBy());
// 设置java字段名
column.setJavaField(StringUtils.toCamelCase(columnName));
// 设置默认类型
column.setJavaType(GenConstants.TYPE_STRING);
if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) {
// 字符串长度超过500设置为文本域
Integer columnLength = getColumnLength(column.getColumnType());
String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
column.setHtmlType(htmlType);
} else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
column.setJavaType(GenConstants.TYPE_DATE);
column.setHtmlType(GenConstants.HTML_DATETIME);
} else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
column.setHtmlType(GenConstants.HTML_INPUT);
// 如果是浮点型 统一用BigDecimal
String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) {
column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
}
// 如果是整形
else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) {
column.setJavaType(GenConstants.TYPE_INTEGER);
}
// 长整形
else {
column.setJavaType(GenConstants.TYPE_LONG);
}
}
// 插入字段(默认所有字段都需要插入)
column.setIsInsert(GenConstants.REQUIRE);
// 编辑字段
if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk()) {
column.setIsEdit(GenConstants.REQUIRE);
}
// 列表字段
if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk()) {
column.setIsList(GenConstants.REQUIRE);
}
// 查询字段
if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) {
column.setIsQuery(GenConstants.REQUIRE);
}
// 查询字段类型
if (StringUtils.endsWithIgnoreCase(columnName, "name")) {
column.setQueryType(GenConstants.QUERY_LIKE);
}
// 状态字段设置单选框
if (StringUtils.endsWithIgnoreCase(columnName, "status")) {
column.setHtmlType(GenConstants.HTML_RADIO);
}
// 类型&性别字段设置下拉框
else if (StringUtils.endsWithIgnoreCase(columnName, "type")
|| StringUtils.endsWithIgnoreCase(columnName, "sex")) {
column.setHtmlType(GenConstants.HTML_SELECT);
}
// 文件字段设置上传控件
else if (StringUtils.endsWithIgnoreCase(columnName, "image")) {
column.setHtmlType(GenConstants.HTML_UPLOAD_IMAGE);
}
// 内容字段设置富文本控件
else if (StringUtils.endsWithIgnoreCase(columnName, "content")) {
column.setHtmlType(GenConstants.HTML_EDITOR);
}
}
/**
*
*
* @param arr
* @param targetValue
* @return
*/
public static boolean arraysContains(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}
/**
*
*
* @param packageName
* @return
*/
public static String getModuleName(String packageName) {
int lastIndex = packageName.lastIndexOf(".");
int nameLength = packageName.length();
String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength);
return moduleName;
}
/**
*
*
* @param tableName
* @return
*/
public static String getBusinessName(String tableName) {
int lastIndex = tableName.lastIndexOf("_");
int nameLength = tableName.length();
String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength);
return businessName;
}
/**
* Java
*
* @param tableName
* @return
*/
public static String convertClassName(String tableName) {
boolean autoRemovePre = GenConfig.getAutoRemovePre();
String tablePrefix = GenConfig.getTablePrefix();
if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) {
String[] searchList = StringUtils.split(tablePrefix, ",");
tableName = replaceFirst(tableName, searchList);
}
return StringUtils.convertToCamelCase(tableName);
}
/**
*
*
* @param replacementm
* @param searchList
* @return
*/
public static String replaceFirst(String replacementm, String[] searchList) {
String text = replacementm;
for (String searchString : searchList) {
if (replacementm.startsWith(searchString)) {
text = replacementm.replaceFirst(searchString, "");
break;
}
}
return text;
}
/**
*
*
* @param text
* @return
*/
public static String replaceText(String text) {
return RegExUtils.replaceAll(text, "(?:表|若依)", "");
}
/**
*
*
* @param columnType
* @return
*/
public static String getDbType(String columnType) {
if (StringUtils.indexOf(columnType, "(") > 0) {
return StringUtils.substringBefore(columnType, "(");
} else {
return columnType;
}
}
/**
*
*
* @param columnType
* @return
*/
public static Integer getColumnLength(String columnType) {
if (StringUtils.indexOf(columnType, "(") > 0) {
String length = StringUtils.substringBetween(columnType, "(", ")");
return Integer.valueOf(length);
} else {
return 0;
}
}
}

View File

@ -3,19 +3,31 @@ package cn.iocoder.dashboard.modules.tool.controller.codegen;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodeGenTablePageItemRespVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.iocoder.dashboard.modules.tool.service.codegen.ToolCodegenService;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
@RestController
@RequestMapping("/tool/code-gen")
@RequestMapping("/tool/codegen")
public class ToolCodeGenController {
@Resource
private ToolCodegenService codegenService;
@GetMapping("/table/page")
public CommonResult<PageResult<ToolCodeGenTablePageItemRespVO>> getCodeGenTablePage() {
return success(null);
}
@ApiOperation("基于数据库的表结构,创建代码生成器的表定义")
@PostMapping("/table/create")
// TODO 权限
public CommonResult<Long> createCodeGenTable(@RequestParam("tableName") String tableName) {
return success(codegenService.createCodegenTable(tableName));
}
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.dashboard.modules.tool.convert.codegen;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaColumnDO;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaTableDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface CodegenConvert {
CodegenConvert INSTANCE = Mappers.getMapper(CodegenConvert.class);
ToolCodegenTableDO convert(ToolInformationSchemaTableDO bean);
List<ToolCodegenColumnDO> convertList(List<ToolInformationSchemaColumnDO> list);
}

View File

@ -0,0 +1 @@
package cn.iocoder.dashboard.modules.tool.convert;

View File

@ -0,0 +1,9 @@
package cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen;
import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ToolCodegenColumnMapper extends BaseMapperX<ToolCodegenColumnDO> {
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen;
import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ToolCodegenTableMapper extends BaseMapperX<ToolCodegenTableDO> {
default ToolCodegenTableDO selectByTableName(String tableName) {
return selectOne(new QueryWrapper<ToolCodegenTableDO>().eq("table_name", tableName));
}
}

View File

@ -14,4 +14,8 @@ public interface ToolInformationSchemaTableMapper extends BaseMapperX<ToolInform
return selectList(new QueryWrapper<ToolInformationSchemaTableDO>().eq("table_schema", tableSchema));
}
default ToolInformationSchemaTableDO selectByTableName(String tableName) {
return selectOne(new QueryWrapper<ToolInformationSchemaTableDO>().eq("table_name", tableName));
}
}

View File

@ -16,13 +16,14 @@ public enum ToolCodegenColumnHtmlTypeEnum {
RADIO("radio"), // 单选框
CHECKBOX("checkbox"), // 复选框
DATETIME("datetime"), // 日期控件
UPLOAD_IMAGE("upload_image"), // 上传控件
UPLOAD_IMAGE("upload_image"), // 上传图片
UPLOAD_FILE("upload_file"), // 上传文件
EDITOR("editor"), // 富文本控件
;
/**
*
*/
private final String condition;
private final String type;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.dashboard.modules.tool.service.codegen;
/**
* Service
*
* @author
*/
public interface ToolCodegenService {
/**
*
*
* @param tableName
* @return
*/
Long createCodegenTable(String tableName);
}

View File

@ -0,0 +1,222 @@
package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.dashboard.modules.tool.convert.codegen.CodegenConvert;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenColumnMapper;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenTableMapper;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolInformationSchemaColumnMapper;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolInformationSchemaTableMapper;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaColumnDO;
import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaTableDO;
import cn.iocoder.dashboard.modules.tool.enums.codegen.ToolCodegenColumnHtmlTypeEnum;
import cn.iocoder.dashboard.modules.tool.enums.codegen.ToolCodegenColumnListConditionEnum;
import cn.iocoder.dashboard.modules.tool.service.codegen.ToolCodegenService;
import com.google.common.collect.Sets;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
/**
* Service
*
* @author
*/
@Service
public class ToolCodegenServiceImpl implements ToolCodegenService {
/**
* {@link ToolCodegenColumnListConditionEnum}
*
*/
private static final Map<String, ToolCodegenColumnListConditionEnum> columnListOperationConditionMappings =
MapUtil.<String, ToolCodegenColumnListConditionEnum>builder()
.put("name", ToolCodegenColumnListConditionEnum.LIKE)
.put("time", ToolCodegenColumnListConditionEnum.BETWEEN)
.put("date", ToolCodegenColumnListConditionEnum.BETWEEN)
.build();
/**
* {@link ToolCodegenColumnHtmlTypeEnum}
*
*/
private static final Map<String, ToolCodegenColumnHtmlTypeEnum> columnHtmlTypeMappings =
MapUtil.<String, ToolCodegenColumnHtmlTypeEnum>builder()
.put("status", ToolCodegenColumnHtmlTypeEnum.RADIO)
.put("sex", ToolCodegenColumnHtmlTypeEnum.RADIO)
.put("type", ToolCodegenColumnHtmlTypeEnum.SELECT)
.put("image", ToolCodegenColumnHtmlTypeEnum.UPLOAD_IMAGE)
.put("file", ToolCodegenColumnHtmlTypeEnum.UPLOAD_FILE)
.put("content", ToolCodegenColumnHtmlTypeEnum.EDITOR)
.build();
/**
*
*/
private static final Set<String> CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet(
"id");
/**
*
*/
private static final Set<String> UPDATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet();
/**
*
*/
private static final Set<String> LIST_OPERATION_CONDITION_COLUMN = Sets.newHashSet();
/**
*
*/
private static final Set<String> LIST_OPERATION_RESULT_COLUMN = Sets.newHashSet();
/**
* Java MySQL
*/
private static final Map<String, Set<String>> javaTypeMappings = MapUtil.<String, Set<String>>builder()
.put(Boolean.class.getSimpleName(), Sets.newHashSet("bit"))
.put(Integer.class.getSimpleName(), Sets.newHashSet("tinyint", "smallint", "mediumint", "int"))
.put(Long.class.getSimpleName(), Collections.singleton("bigint"))
.put(Double.class.getSimpleName(), Sets.newHashSet("float", "double"))
.put(BigDecimal.class.getSimpleName(), Sets.newHashSet("decimal", "numeric"))
.put(String.class.getSimpleName(), Sets.newHashSet("tinytext", "text", "mediumtext", "longtext", // 长文本
"char", "varchar", "nvarchar", "varchar2")) // 短文本
.put(Date.class.getSimpleName(), Sets.newHashSet("datetime", "time", "date", "timestamp"))
.build();
static {
Arrays.stream(BaseDO.class.getDeclaredFields()).forEach(field -> {
CREATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
UPDATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
LIST_OPERATION_CONDITION_COLUMN.add(field.getName());
LIST_OPERATION_RESULT_COLUMN.add(field.getName());
});
LIST_OPERATION_RESULT_COLUMN.remove("create_time"); // 创建时间,还是需要返回的
}
@Resource
private ToolInformationSchemaTableMapper informationSchemaTableMapper;
@Resource
private ToolInformationSchemaColumnMapper informationSchemaColumnMapper;
@Resource
private ToolCodegenTableMapper codegenTableMapper;
@Resource
private ToolCodegenColumnMapper codegenColumnMapper;
@Override
@Transactional
public Long createCodegenTable(String tableName) {
// 从数据库中,获得数据库表结构
ToolInformationSchemaTableDO schemaTable = informationSchemaTableMapper.selectByTableName(tableName);
if (schemaTable == null) {
throw new RuntimeException(""); // TODO
}
List<ToolInformationSchemaColumnDO> schemaColumns = informationSchemaColumnMapper.selectListByTableName(tableName);
if (CollUtil.isEmpty(schemaColumns)) {
throw new RuntimeException(""); // TODO
}
// 校验是否已经存在
if (codegenTableMapper.selectByTableName(tableName) != null) {
throw new RuntimeException(""); // TODO
}
// 将 table 插入到数据库
ToolCodegenTableDO table = CodegenConvert.INSTANCE.convert(schemaTable);
initTableDefault(table);
codegenTableMapper.insert(table);
// 将 column 插入到数据库
List<ToolCodegenColumnDO> columns = CodegenConvert.INSTANCE.convertList(schemaColumns);
columns.forEach(column -> {
initColumnDefault(column);
column.setTableId(table.getId());
codegenColumnMapper.insert(column);
});
return table.getId();
}
/**
* Table
*
* @param table
*/
private void initTableDefault(ToolCodegenTableDO table) {
table.setModuleName(StrUtil.subBefore(table.getTableName(),
'_', false)); // 第一个 _ 前缀的前面,作为 module 名字
table.setBusinessName(StrUtil.subAfter(table.getTableName(),
'_', false)); // 第一个 _ 前缀的后面,作为 module 名字
table.setBusinessName(StrUtil.toCamelCase(table.getBusinessName())); // 可能存在多个 _ 的情况,转换成驼峰
table.setClassName(StrUtil.toCamelCase(table.getClassName())); // 驼峰
table.setClassComment(StrUtil.subBefore(table.getClassComment(), // 去除结尾的表,作为类描述
'表', true));
table.setAuthor("芋艿"); // TODO 稍后改成创建人
}
/**
* Column
*
* @param column
*/
private void initColumnDefault(ToolCodegenColumnDO column) {
// 处理 Java 相关的字段的默认值
processColumnJava(column);
// 处理 CRUD 相关的字段的默认值
processColumnOperation(column);
// 处理 UI 相关的字段的默认值
processColumnUI(column);
}
private void processColumnJava(ToolCodegenColumnDO column) {
// 处理 javaField 字段
column.setJavaField(StrUtil.toCamelCase(column.getColumnName()));
// 处理 dictType 字段,暂无
// 处理 javaType 字段
String dbType = StrUtil.subBefore(column.getColumnName(), ')', false);
javaTypeMappings.entrySet().stream()
.filter(entry -> entry.getValue().contains(dbType))
.findFirst().ifPresent(entry -> column.setJavaType(entry.getKey()));
if (column.getJavaType() == null) {
throw new IllegalStateException(String.format("column(%s) 的数据库类型(%s) 找不到匹配的 Java 类型",
column.getColumnName(), column.getColumnType()));
}
}
private void processColumnOperation(ToolCodegenColumnDO column) {
// 处理 createOperation 字段
column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getColumnName())
&& !column.getPrimaryKey()); // 非主键
// 处理 updateOperation 字段
column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getColumnName()));
// 处理 listOperationResult 字段
column.setListOperationResult(!LIST_OPERATION_RESULT_COLUMN.contains(column.getColumnName()));
// 处理 listOperationCondition 字段。默认设置为需要过滤的条件,手动进行取消
if (!LIST_OPERATION_CONDITION_COLUMN.contains(column.getColumnName())
&& !column.getPrimaryKey()) { // 非主键
column.setListOperationCondition(ToolCodegenColumnListConditionEnum.EQ.getCondition());
}
columnListOperationConditionMappings.entrySet().stream()
.filter(entry -> StrUtil.endWithIgnoreCase(column.getColumnName(), entry.getKey()))
.findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition()));
}
private void processColumnUI(ToolCodegenColumnDO column) {
// 基于后缀进行匹配
columnHtmlTypeMappings.entrySet().stream()
.filter(entry -> StrUtil.endWithIgnoreCase(column.getColumnName(), entry.getKey()))
.findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType()));
// 如果是 Boolean 类型时,设置为 radio 类型.
// 其它类型,因为字段名可以相对保障,所以不进行处理。例如说 date 对应 datetime 类型.
if (Boolean.class.getSimpleName().equals(column.getJavaType())) {
column.setHtmlType(ToolCodegenColumnHtmlTypeEnum.RADIO.getType());
}
// 兜底,设置默认为 input 类型
if (column.getHtmlType() == null) {
column.setHtmlType(ToolCodegenColumnHtmlTypeEnum.INPUT.getType());
}
}
}

View File

@ -0,0 +1 @@
package cn.iocoder.dashboard.modules.tool.service;