mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-07-17 20:45:06 +08:00
实现数据库字段的解析
This commit is contained in:
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
package cn.iocoder.dashboard.modules.tool.convert;
|
@ -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> {
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.dashboard.modules.tool.service.codegen;
|
||||
|
||||
/**
|
||||
* 代码生成 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface ToolCodegenService {
|
||||
|
||||
/**
|
||||
* 基于数据库的表结构,创建代码生成器的表定义
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @return 表定义的编号
|
||||
*/
|
||||
Long createCodegenTable(String tableName);
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
package cn.iocoder.dashboard.modules.tool.service;
|
Reference in New Issue
Block a user