package com.vci.ubcs.ddl.service.impl; import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.nacos.shaded.com.google.protobuf.ServiceException; import com.vci.ubcs.ddl.bo.DdlTableBO; import com.vci.ubcs.ddl.bo.DdlTableInDataBaseBO; import com.vci.ubcs.ddl.enums.BusinessTypeEnum; import com.vci.ubcs.ddl.enums.ModifyTableTaskEnum; import com.vci.ubcs.ddl.processor.ddl.DdlMapperProcessor; import com.vci.ubcs.ddl.processor.dll.DllMapperProcessor; import com.vci.ubcs.ddl.properties.DdlPropertise; import com.vci.ubcs.ddl.service.IDdlService; import com.vci.ubcs.omd.cache.BtmTypeCache; import com.vci.ubcs.omd.constant.BtmTypeFieldConstant; import com.vci.ubcs.omd.constant.BtmTypeLcStatusConstant; import com.vci.ubcs.omd.dto.BtmAndLinkTypeDdlDTO; import com.vci.ubcs.omd.dto.TableAddColumnDTO; import com.vci.ubcs.omd.dto.TableCheckDTO; import com.vci.ubcs.omd.dto.TableCheckResultDTO; import com.vci.ubcs.omd.entity.ModifyAttributeInfo; import com.vci.ubcs.omd.vo.*; import com.vci.ubcs.starter.exception.VciBaseException; import com.vci.ubcs.starter.web.enumpck.BooleanEnum; import com.vci.ubcs.starter.web.enumpck.VciFieldTypeEnum; import com.vci.ubcs.starter.web.util.VciBaseUtil; import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.BeanUtil; import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.StringPool; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.validation.constraints.NotNull; import java.rmi.ServerException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** * Description: 数据库表操作服务 * * @author LiHang * @date 2023/4/24 */ @Service public class DdlServiceImpl implements IDdlService { /** * 相应的配置 */ @Autowired private DdlPropertise ddlProperties; /** * word导出的时候的域字段映射 */ // @Autowired // private DdlExportWordFieldProperties wordFieldProperties; /** * ddl数据操作服务 */ @Autowired private DdlMapperProcessor ddlMapper; /** * dll数据操作服务 */ @Autowired private DllMapperProcessor dllMapper; private static final String YES = "Y"; private static final String NO = "N"; private final Map idBtmMap = new ConcurrentHashMap<>(); private final Map idLinkMap = new ConcurrentHashMap<>(); private void putBtm(@NotNull BtmTypeVO... voList) throws ServiceException { String collect = Arrays.stream(voList).map(BtmTypeVO::getId).filter(idBtmMap::containsKey).collect(Collectors.joining(",")); if (StringUtils.isBlank(collect)) { Arrays.stream(voList).forEach(vo -> { idBtmMap.put(vo.getId(), vo); }); } else { throw new ServiceException("业务类型:[" + collect + "]正在被其他用户操作"); } } private void putLink(@NotNull LinkTypeVO... voList) throws ServiceException { String collect = Arrays.stream(voList).map(LinkTypeVO::getId).filter(idLinkMap::containsKey).collect(Collectors.joining(",")); if (StringUtils.isBlank(collect)) { Arrays.stream(voList).forEach(vo -> { idLinkMap.put(vo.getId(), vo); }); } else { throw new ServiceException("链接类型:[" + collect + "]正在被其他用户操作"); } } private void removeBtm(@NotNull BtmTypeVO... btmTypeVO) throws ServiceException { if (Arrays.stream(btmTypeVO).allMatch(s -> idBtmMap.containsKey(s.getId()))) { for (BtmTypeVO vo : btmTypeVO) { idBtmMap.remove(vo.getId()); } } else { throw new ServiceException("解锁对象不存在"); } } private void removeLink(@NotNull LinkTypeVO... linkTypeVO) throws ServiceException { if (Arrays.stream(linkTypeVO).allMatch(s -> idLinkMap.containsKey(s.getId()))) { for (LinkTypeVO vo : linkTypeVO) { idLinkMap.remove(vo.getId()); } } else { throw new ServiceException("解锁对象不存在"); } } /** * 批量将业务类型创建数据库表 * * @param pkBtmTypes 业务类型的主键 * @throws VciBaseException 参数为空或者创建表出现了错误的时候会抛出异常 */ @Override public void createDbTables(String pkBtmTypes) throws VciBaseException { VciBaseUtil.alertNotNull(pkBtmTypes, "业务类型/链接类型的主键"); createDbTablesByOidCollection(VciBaseUtil.str2List(pkBtmTypes)); } /** * 批量将业务类型创建数据库表 * * @param oidCollection 业务类型的主键集合 * @throws VciBaseException 参数为空或者创建表出现了错误的时候会抛出异常 */ @Override public void createDbTablesByOidCollection(Collection oidCollection) throws VciBaseException { VciBaseUtil.alertNotNull("业务类型/链接类型的主键集合", oidCollection); List btmTypeVOList = BtmTypeCache.listBtmTypeByOidCollection(oidCollection); // List linkTypeVOList = linkTypeService.listLinkTypeByOidCollection(oidCollection); if (!CollectionUtils.isEmpty(btmTypeVOList)) { //说明是业务类型 btmTypeVOList.forEach(this::createDbTableForBtm); } //链接类型 /*if(!CollectionUtils.isEmpty(linkTypeVOList)){ linkTypeVOList.stream().forEach( s -> { createDbTableForLink(s); }); }*/ } /** * 创建业务类型的表格 * * @param btmTypeVO 业务类型的显示对象 * @throws VciBaseException 执行出错的时候会抛出异常 */ private void createDbTableForBtm(BtmTypeVO btmTypeVO) throws VciBaseException { VciBaseUtil.alertNotNull(btmTypeVO, "要创建表格所属的业务类型", btmTypeVO.getTableName(), "业务类型的表格名称"); if (btmTypeVO.isViewFlag() && StringUtils.isNotBlank(btmTypeVO.getViewCreateSql())) { //说明是视图 this.createViewBySql("create or replace " + btmTypeVO.getTableName() + " as " + btmTypeVO.getViewCreateSql()); } else { String tableName = btmTypeVO.getTableName(); if (!checkTableExistByTableName(tableName)) { String attributeSql = getCreateSqlByAttributeForBtm(btmTypeVO.getAttributes()); dllMapper.createTableBySql(tableName, attributeSql); if (StringUtils.isNotBlank(btmTypeVO.getName())) { dllMapper.commentTable(tableName, btmTypeVO.getName()); } btmTypeVO.getAttributes().forEach(s -> { dllMapper.commentColumnTable(tableName, s.getId(), s.getName()); }); } } } /** * 创建链接类型的表格 * * @param linkTypeVO 链接类型的显示对象 * @throws VciBaseException 执行出错的时候会抛出异常 */ private void createDbTableForLink(LinkTypeVO linkTypeVO) throws VciBaseException { VciBaseUtil.alertNotNull(linkTypeVO, "要创建表格所属的业务类型", linkTypeVO.getTableName(), "业务类型的表格名称"); String tableName = linkTypeVO.getTableName(); if (!checkTableExistByTableName(tableName)) { String attributeSql = getCreateSqlByAttributeForLink(linkTypeVO.getAttributes()); dllMapper.createTableBySql(tableName, attributeSql); if (StringUtils.isNotBlank(linkTypeVO.getName())) { dllMapper.commentTable(tableName, linkTypeVO.getName()); } linkTypeVO.getAttributes().forEach(s -> { dllMapper.commentColumnTable(tableName, s.getId(), s.getName()); }); } } /** * 获取创建的sql语句中属性部分 * * @param attributeVOList 属性的立碑 * @return sql语句 */ @Override public String getCreateSqlByAttributeForBtm(List attributeVOList) { StringBuilder sb = new StringBuilder(); attributeVOList.forEach(a -> { sb.append(a.getId()).append(StringPool.SPACE); VciFieldTypeEnum fieldTypeEnum = VciFieldTypeEnum.forValue(a.getAttrDataType()); sb.append(dllMapper.getColumnTypeSql(fieldTypeEnum, a)).append(","); }); return sb.substring(0, sb.lastIndexOf(",")); } /** * 获取创建的sql语句中属性部分 * * @param attributeVOList 属性的立碑 * @return sql语句 */ @Override public String getCreateSqlByAttributeForLink(List attributeVOList) { StringBuilder sb = new StringBuilder(); attributeVOList.forEach(a -> { BtmTypeAttributeVO attributeVO = Optional.ofNullable(BeanUtil.copy(a, BtmTypeAttributeVO.class)).orElseGet(BtmTypeAttributeVO::new); attributeVO.setPkBtmType(a.getPkLinkType()); sb.append(a.getId()).append(StringPool.SPACE); VciFieldTypeEnum fieldTypeEnum = VciFieldTypeEnum.forValue(a.getAttrDataType()); sb.append(dllMapper.getColumnTypeSql(fieldTypeEnum, attributeVO)).append(","); }); return sb.substring(0, sb.lastIndexOf(",")); } /** * 批量将业务类型创建数据库表 * * @param ids 业务类型的英文名称 * @throws VciBaseException 参数为空或者创建表出现了错误的时候会抛出异常 */ @Override public void createDbTablesById(String ids) throws VciBaseException { VciBaseUtil.alertNotNull(ids, "业务类型/链接类型的英文集合"); // 业务类型 Func.toStrList(",",ids).stream().filter(idBtmMap::containsKey).map(idBtmMap::get).forEach(this::createDbTableForBtm); // 链接类型 Func.toStrList(",",ids).stream().filter(idLinkMap::containsKey).map(idLinkMap::get).forEach(this::createDbTableForLink); } /** * 修改业务类型中的属性字段的长度,注意在执行这个方法时就会将以前的事务提交。 * * @param modifyLengthAttrVOList 需要修改的属性对象 * @throws VciBaseException 执行出错的时候会抛出异常 */ @Override public void changeColumnForBtm(List modifyLengthAttrVOList) throws VciBaseException { VciBaseUtil.alertNotNull("要修改长度的属性集", modifyLengthAttrVOList); Map> btmTypeHasAttributeVOMap = modifyLengthAttrVOList.stream().collect(Collectors.groupingBy(BtmTypeAttributeVO::getPkBtmType)); btmTypeHasAttributeVOMap.forEach((k, v) -> { BtmTypeVO btmTypeVO = BtmTypeCache.getDetail(k); if (btmTypeVO == null || StringUtils.isBlank(btmTypeVO.getOid())) { throw new VciBaseException("要修改属性列长度的业务类型不存在"); } if (!isCompatibilityTable(btmTypeVO.getId(), null)) { //要看看这个链接类型对应的数据库表是否存在 String tableName = btmTypeVO.getTableName(); if (checkTableExistByTableName(tableName)) { changeColumnsForTable(tableName, v); } else { createDbTableForBtm(btmTypeVO); } changeColumnsForTable(btmTypeVO.getTableName(), v); } }); } /** * 执行SQL语句的修改 * * @param tableName 表格的名称 * @param attributeVOList 要添加的属性字段 */ private void changeColumnsForTable(String tableName, List attributeVOList) { String attributeSql = getCreateSqlByAttributeForBtm(attributeVOList); //先判断表格是否存在 boolean tableExist = false; try { ddlMapper.countAll(tableName); tableExist = true; } catch (Throwable e) { //说明表格就不存在 createDbTables(attributeVOList.get(0).getPkBtmType()); } if (tableExist) { ddlMapper.modifyTableBySqlBase(tableName, attributeSql); commentColumnsForTable(tableName, attributeVOList); } } /** * 给表格的字段添加注释 * * @param tableName 表格名称 * @param attributeVOList 属性对象列表 */ private void commentColumnsForTable(String tableName, List attributeVOList) { if (StringUtils.isNotBlank(tableName) && !CollectionUtils.isEmpty(attributeVOList)) { attributeVOList.forEach(s -> { ddlMapper.commentColumnTable(tableName, s.getId(), s.getName()); }); } } /** * 修改链接类型中的属性字段的长度,注意在执行这个方法时就会将以前的事务提交。 * * @param modifyLengthAttrDOListForLinkType 需要修改的属性对象 * @throws VciBaseException 执行出错的时候会抛出异常 */ @Override public void changeColumnForLink(List modifyLengthAttrDOListForLinkType) throws VciBaseException { } /** * 添加属性字段到业务类型中,注意在执行这个方法时就会将以前的事务提交。 * * @param addAttrDOList 需要添加的属性对象 * @throws VciBaseException 执行出错的时候会抛出异常 */ @Override public void addColumn2TableForBtm(List addAttrDOList) throws VciBaseException { VciBaseUtil.alertNotNull("要添加到数据库表中的属性集", addAttrDOList); Map> btmTypeHasAttributeMap = addAttrDOList.stream().collect(Collectors.groupingBy(BtmTypeAttributeVO::getPkBtmType)); btmTypeHasAttributeMap.forEach((k, v) -> { BtmTypeVO btmTypeVO = BtmTypeCache.getDetail(k); if (btmTypeVO == null || StringUtils.isBlank(btmTypeVO.getOid())) { throw new VciBaseException("要修改属性列长度的业务类型不存在"); } if (!isCompatibilityTable(btmTypeVO.getId(), null)) { addColumnForTable(btmTypeVO.getTableName(), v); } }); } /** * 添加字段到表格中 * * @param tableName 表格名称 * @param attributeVOList 属性的显示对象 * @throws VciBaseException 执行或者获取sql语句的时候出现错误会抛出异常 */ private void addColumnForTable(String tableName, List attributeVOList) { String attributeSql = getCreateSqlByAttributeForBtm(attributeVOList); //先判断表格是否存在 if (!checkTableExistByTableName(tableName)) { BtmTypeAttributeVO attributeVO = attributeVOList.get(0); createDbTables(attributeVO.getPkBtmType()); } else { ddlMapper.addColumn2TableBySql(tableName, attributeSql); commentColumnsForTable(tableName, attributeVOList); } } /** * 添加属性字段到链接类型中,注意在执行这个方法时就会将以前的事务提交。 * * @param addAttrDOListForLinkType 需要添加的属性对象 * @throws VciBaseException 执行出错的时候会抛出异常 */ @Override public void addColumn2TableForLink(List addAttrDOListForLinkType) throws VciBaseException { VciBaseUtil.alertNotNull("要添加到数据库表中属性集",addAttrDOListForLinkType); Map> linkTypeHasAttributeVOMap = addAttrDOListForLinkType.stream().collect(Collectors.groupingBy(LinkTypeAttributeVO::getPkLinkType)); linkTypeHasAttributeVOMap.forEach((k,v) -> { }); } /** * 判断表中是否有数据 * * @param tableName 表格的名称 * @return true表示有数据,false表示没有数据,或者这个表格不存在的时候抛出异常 * @throws VciBaseException 参数错误的时候抛出异常 */ @Override public boolean checkTableHasDataByTableName(String tableName) throws VciBaseException { try { int tableCount = ddlMapper.countAll(tableName); if (tableCount > 0) { return true; } } catch (Throwable e) { throw new VciBaseException("统计某个表是否含有数据出错,可能表不存在"); } return false; } /** * 创建视图 * * @param viewCreateSql 视图的SQL语句 * @throws VciBaseException 参数错误或者执行错误的时候会抛出异常,执行错误主要包括SQL语句错误,没有权限等 */ @Override public void createViewBySql(String viewCreateSql) throws VciBaseException { VciBaseUtil.alertNotNull(viewCreateSql, "视图的SQL"); ddlMapper.createViewBySql(viewCreateSql); } /** * 删除表格或者视图 * * @param tableName 表格名称或者视图名称 * @throws VciBaseException 参数错误或者执行错误的时候会抛出异常 */ @Override public void dropTableByName(String tableName) throws VciBaseException { VciBaseUtil.alertNotNull(tableName, "要删除的表的名称"); ddlMapper.dropTable(tableName); } /** * 删除表格的某一列 * * @param tableName 表格名称 * @param columnName 列的名称 */ @Override public void dropColumnByName(String tableName, String columnName) { VciBaseUtil.alertNotNull(tableName, "要删除的表的名称", columnName, "要删除的表字段名称"); ddlMapper.dropTableColumn(tableName, columnName); } /** * 根据表格的名称判断表格是否存在 * * @param tableName 表格名称 * @return rue表示存在,false表示不存在 */ @Override public boolean checkTableExistByTableName(String tableName) { return ddlMapper.checkTableExist(tableName) > 0; } /** * 获取数据库和业务类型中的不同的地方 * * @param btmTypeVOList 业务类型对象,有属性时需要包含属性 * @param linkTypeVOList 链接类型对象,有属性时需要包含属性 * @return 不同的地方,每一个业务类型或者链接类型一条数据 */ @Override public List checkDifferent(List btmTypeVOList, List linkTypeVOList) throws VciBaseException { if (CollectionUtils.isEmpty(btmTypeVOList) && CollectionUtils.isEmpty(linkTypeVOList)) { throw new VciBaseException("要检查的业务类型和链接类型为空"); } List modifyAttributeInfoList = new ArrayList<>(); if (!CollectionUtils.isEmpty(btmTypeVOList)) { modifyAttributeInfoList.addAll(checkBtmType(btmTypeVOList)); } if (!CollectionUtils.isEmpty(linkTypeVOList)) { modifyAttributeInfoList.addAll(checkLinkType(linkTypeVOList)); } if (!CollectionUtils.isEmpty(modifyAttributeInfoList)) { reflexDifferent(modifyAttributeInfoList, btmTypeVOList, linkTypeVOList); } return modifyAttributeInfoList; } /** * 检查业务类型 * * @param btmTypeVOList 业务类型 * @return 检查结果 */ private List checkBtmType(List btmTypeVOList) { List modifyAttributeInfoDOList = new ArrayList<>(); btmTypeVOList.stream().filter(s -> !isCompatibilityTable(s.getId(),null)).forEach(btm -> { ModifyAttributeInfo modifyAttributeInfo = new ModifyAttributeInfo(); modifyAttributeInfo.setId(btm.getId()); modifyAttributeInfo.setName(btm.getName()); modifyAttributeInfo.setTableName(btm.getTableName()); modifyAttributeInfo.setBusinessType(BusinessTypeEnum.BTM.getValue()); // 1. 视图和新建的,直接创建,记录创建历史 if (btm.isViewFlag() || !checkTableExistByTableName(btm.getTableName())){ modifyAttributeInfo.setTaskName(ModifyTableTaskEnum.CREATE.getValue()); modifyAttributeInfo.setModifyColumnReason(ModifyTableTaskEnum.CREATE.getValue()); }else { VciBaseUtil.alertNotNull(btm.getAttributes(),"业务类型" + btm.getId() + "的属性"); List columnDataInTable = selectTableColumnInfo(btm.getTableName()); if (CollectionUtils.isEmpty(columnDataInTable)){ modifyAttributeInfo.setAddAttributes(btm.getAttributes().stream().map(s -> s.getId().toLowerCase().trim()).collect(Collectors.joining(","))); modifyAttributeInfo.setTaskName(ModifyTableTaskEnum.EDIT.getValue()); modifyAttributeInfo.setModifyColumnReason(ModifyTableTaskEnum.CREATE.getValue()); }else { // 2. 存在的才判断,分新增属性、属性更改、属性删除分别操作 // 3. 属性操作中特别判断[是否控制版本][是否控制密级][是否控制生命周期]来添加对应属性 Map tableColumMap = columnDataInTable.stream().collect(Collectors.toMap(t -> t.getId().toLowerCase().trim(), k -> k)); Map attributeMap = btm.getAttributes().stream().collect(Collectors.toMap(t -> t.getId().toLowerCase().trim(), k -> k)); List addList = new ArrayList<>(); List editList = new ArrayList<>(); List deleteList = new ArrayList<>(); List beforeList = new ArrayList<>(); attributeMap.forEach((k,v) -> { String attributeLowId = k.toLowerCase(); if (!checkIsDefaultColumn(attributeLowId)) { if (tableColumMap.containsKey(k)) { //说明以前也有,那就看是否需要修改 DdlTableInDataBaseBO columnInDB = tableColumMap.get(k); if (columnInDB.getAttributeLength() == null) { columnInDB.setAttributeLength(0); } boolean needEdit = false; if (!v.getName().equalsIgnoreCase(columnInDB.getName())) { //说明需要修改 needEdit = true; } if (needEdit || checkNeedEditAttr(v, columnInDB)) { editList.add(v.getId()); beforeList.add(columnInDB.getId() + StringPool.SPACE + columnInDB.getAttrDataType() + "(" + columnInDB.getAttributeLength() + ")" + StringPool.SPACE + columnInDB.getNullableFlag() + StringPool.SPACE + columnInDB.getPrecisionLength() + StringPool.SPACE + columnInDB.getScaleLength() + StringPool.SPACE + columnInDB.getName()); } } else { addList.add(v.getId()); } } else { //针对默认属性,如果以前没有,现在有可以添加,如果以前 if (!tableColumMap.containsKey(k)) { boolean needAddNewField = false; if (!BtmTypeLcStatusConstant.EMTYPE_LIFE_CYCLE.equalsIgnoreCase(btm.getLifeCycleId()) && BtmTypeFieldConstant.LIFECYCLE_MANAGE_FIELD_MAP.containsKey(attributeLowId)) { needAddNewField = true; } if (StringUtils.isNotBlank(btm.getRevisionRuleId()) && BtmTypeFieldConstant.REVISION_MANAGE_FIELD_MAP.containsKey(attributeLowId)) { needAddNewField = true; } if (btm.isSecretFlag() && BtmTypeFieldConstant.SECRET_MANAGE_FIELD_MAP.containsKey(attributeLowId)) { needAddNewField = true; } if (needAddNewField) { addList.add(v.getId()); } } } }); tableColumMap.forEach((k, v) -> { if (!attributeMap.containsKey(k)) { deleteList.add(k); } }); modifyAttributeInfo.setOrderModifyUserName(AuthUtil.getUserAccount()); modifyAttributeInfo.setOrderModifyDate(new Date()); modifyAttributeInfo.setModifyColumnReason(ModifyTableTaskEnum.CONSISTENCY_CHECK.getValue()); modifyAttributeInfo.setTaskName(ModifyTableTaskEnum.CONSISTENCY_CHECK.getValue()); modifyAttributeInfo.setAddAttributes(String.join(",", addList)); modifyAttributeInfo.setModifyAttributes(String.join(",", editList)); modifyAttributeInfo.setDeleteAttributes(String.join(",", deleteList)); modifyAttributeInfo.setBeforeModifyAttributes(String.join(",", beforeList)); } } modifyAttributeInfoDOList.add(modifyAttributeInfo); }); return modifyAttributeInfoDOList; } private boolean checkIsDefaultColumn(String attributeLowId) { return ((BtmTypeFieldConstant.BASIC_FIELD_MAP.containsKey(attributeLowId) && !VciBaseUtil.inArray(new String[]{"id", "name", "description"}, attributeLowId)) || BtmTypeFieldConstant.LINK_TYPE_FIELD_MAP.containsKey(attributeLowId) || BtmTypeFieldConstant.LIFECYCLE_MANAGE_FIELD_MAP.containsKey(attributeLowId) || BtmTypeFieldConstant.REVISION_MANAGE_FIELD_MAP.containsKey(attributeLowId) || BtmTypeFieldConstant.SECRET_MANAGE_FIELD_MAP.containsKey(attributeLowId)); } /** * 检查链接类型 * * @param linkTypeVOList 链接类型 * @return 检查结果 */ private List checkLinkType(List linkTypeVOList) { List modifyAttributeInfoDOList = new ArrayList<>(); linkTypeVOList.stream().filter(s -> !isCompatibilityTable(null,s.getId())).forEach(link -> { ModifyAttributeInfo modifyAttributeInfo = new ModifyAttributeInfo(); modifyAttributeInfo.setId(link.getId()); modifyAttributeInfo.setName(link.getName()); modifyAttributeInfo.setTableName(link.getTableName()); modifyAttributeInfo.setBusinessType(BusinessTypeEnum.LINK.getValue()); // 1. 视图和新建的,直接创建,记录创建历史 if (!checkTableExistByTableName(link.getTableName())){ modifyAttributeInfo.setTaskName(ModifyTableTaskEnum.CREATE.getValue()); modifyAttributeInfo.setModifyColumnReason(ModifyTableTaskEnum.CREATE.getValue()); }else { VciBaseUtil.alertNotNull(link.getAttributes(), "链接类型" + link.getId() + "的属性"); List columnDataInTable = selectTableColumnInfo(link.getTableName()); if (CollectionUtils.isEmpty(columnDataInTable)) { modifyAttributeInfo.setAddAttributes(link.getAttributes().stream().map(s -> s.getId().toLowerCase().trim()).collect(Collectors.joining(","))); modifyAttributeInfo.setTaskName(ModifyTableTaskEnum.EDIT.getValue()); modifyAttributeInfo.setModifyColumnReason(ModifyTableTaskEnum.CREATE.getValue()); } else { // 2. 存在的才判断,分新增属性、属性更改、属性删除分别操作 // 3. 属性操作中特别判断[是否控制版本][是否控制密级][是否控制生命周期]来添加对应属性 Map tableColumMap = columnDataInTable.stream().collect(Collectors.toMap(t -> t.getId().toLowerCase().trim(), k -> k)); Map attributeMap = link.getAttributes().stream().collect(Collectors.toMap(t -> t.getId().toLowerCase().trim(), k -> k)); List addList = new ArrayList<>(); List editList = new ArrayList<>(); List deleteList = new ArrayList<>(); List beforeList = new ArrayList<>(); attributeMap.forEach((k, v) -> { String attributeLowId = k.toLowerCase(); if (!(BtmTypeFieldConstant.LINK_TYPE_FIELD_MAP.containsKey(attributeLowId))) { if (tableColumMap.containsKey(k)) { //说明以前也有,那就看是否需要修改 DdlTableInDataBaseBO columnInDB = tableColumMap.get(k); if (columnInDB.getAttributeLength() == null) { columnInDB.setAttributeLength(0); } boolean needEdit = false; if (!v.getName().equalsIgnoreCase(columnInDB.getName())) { //说明需要修改 needEdit = true; } BtmTypeAttributeVO btmTypeAttributeVO = new BtmTypeAttributeVO(); BeanUtil.copy(v, btmTypeAttributeVO); if (needEdit || checkNeedEditAttr(btmTypeAttributeVO, columnInDB)) { editList.add(v.getId()); beforeList.add(columnInDB.getId() + StringPool.SPACE + columnInDB.getAttrDataType() + "(" + columnInDB.getAttributeLength() + ")" + StringPool.SPACE + columnInDB.getNullableFlag() + StringPool.SPACE + columnInDB.getPrecisionLength() + StringPool.SPACE + columnInDB.getScaleLength() + StringPool.SPACE + columnInDB.getName()); } } else { addList.add(v.getId()); } } else { //针对默认属性,如果以前没有,现在有可以添加,如果以前 if (!tableColumMap.containsKey(k)) { boolean needAddNewField = false; if (BtmTypeFieldConstant.LINK_TYPE_FIELD_MAP.containsKey(attributeLowId)) { //是链接类型的属性,以前没有就添加上 needAddNewField = true; } if (needAddNewField) { addList.add(v.getId()); } } } }); tableColumMap.forEach((k, v) -> { if (!attributeMap.containsKey(k)) { deleteList.add(k); } }); modifyAttributeInfo.setOrderModifyUserName(AuthUtil.getUserAccount()); modifyAttributeInfo.setOrderModifyDate(new Date()); modifyAttributeInfo.setModifyColumnReason(ModifyTableTaskEnum.CONSISTENCY_CHECK.getValue()); modifyAttributeInfo.setTaskName(ModifyTableTaskEnum.CONSISTENCY_CHECK.getValue()); modifyAttributeInfo.setAddAttributes(String.join(",", addList)); modifyAttributeInfo.setModifyAttributes(String.join(",", editList)); modifyAttributeInfo.setDeleteAttributes(String.join(",", deleteList)); modifyAttributeInfo.setBeforeModifyAttributes(String.join(",", beforeList)); } } modifyAttributeInfoDOList.add(modifyAttributeInfo); }); return modifyAttributeInfoDOList; } /** * 判断是否需要修改属性 * * @param btmTypeAttributeVO 属性的显示对象 * @param tableInDB 数据库表里的对象 * @return true表示需要修改,false表示不修改 */ private boolean checkNeedEditAttr(BtmTypeAttributeVO btmTypeAttributeVO, DdlTableInDataBaseBO tableInDB) { if (tableInDB.getAttributeLength() == null) { tableInDB.setAttributeLength(0); } if (tableInDB.getPrecisionLength() == null) { tableInDB.setPrecisionLength(20); } if (tableInDB.getScaleLength() == null) { tableInDB.setScaleLength(0); } String nullInDb = ""; if (YES.equalsIgnoreCase(tableInDB.getNullableFlag())) { nullInDb = BooleanEnum.TRUE.getValue(); } else if (NO.equalsIgnoreCase(tableInDB.getNullableFlag())) { nullInDb = BooleanEnum.FASLE.getValue(); } if (!(String.valueOf(btmTypeAttributeVO.isNullableFlag()).equalsIgnoreCase(nullInDb))) { return true; } if (StringUtils.isNotBlank(btmTypeAttributeVO.getDefaultValue())) { return true; } List fieldTypes = dllMapper.listFieldByColumnStr(tableInDB.getAttrDataType()); if (CollectionUtils.isEmpty(fieldTypes)) { throw new VciBaseException("没有找到对应的字段类型"); } Set names = fieldTypes.stream().map(Enum::name).collect(Collectors.toSet()); String attributeDataType = btmTypeAttributeVO.getAttrDataType(); if (names.size() > 1) { return !names.contains(attributeDataType); } else { VciFieldTypeEnum fieldType = fieldTypes.get(0); if (attributeDataType.equalsIgnoreCase(fieldType.name())) { switch (fieldType) { case VTString: if (btmTypeAttributeVO.getAttributeLength().intValue() != tableInDB.getAttributeLength().intValue()) { return true; } break; case VTDouble: //不超过128 if (btmTypeAttributeVO.getPrecisionLength().intValue() != tableInDB.getPrecisionLength().intValue()) { return true; } if (btmTypeAttributeVO.getScaleLength().intValue() != tableInDB.getScaleLength().intValue()) { return true; } break; default: break; } } return false; } } /** * 清理业务类型中和数据库里不一样的 * * @param differentAttributeList 不同的属性的列表 * @throws VciBaseException 参数为空或者执行出错的时候会抛出异常 */ @Override public void reflexDifferent(List differentAttributeList, List btmTypeVOList, List linkTypeVOList) throws VciBaseException { VciBaseUtil.alertNotNull(differentAttributeList, "要清理的数据库的信息为空"); Map idBtmTypeMap = Optional.ofNullable(btmTypeVOList).orElseGet(ArrayList::new).stream().collect(Collectors.toMap(BtmTypeVO::getId, t -> t, (o1, o2) -> o1)); Map idLinkTypeMap = Optional.ofNullable(linkTypeVOList).orElseGet(ArrayList::new).stream().collect(Collectors.toMap(LinkTypeVO::getId, t -> t, (o1, o2) -> o1)); differentAttributeList.forEach(s -> { // BtmTypeVO btmType = idBtmTypeMap.get(id); if (ModifyTableTaskEnum.CREATE.getValue().equalsIgnoreCase(s.getTaskName())) { //直接创建表格 // createDbTableForBtm(btmType); createDbTablesById(s.getId()); } else { String addAttributes = s.getAddAttributes(); if (StringUtils.isNotBlank(s.getModifyAttributes()) || StringUtils.isNotBlank(s.getDeleteAttributes())) { //需要去判断是否可以更改 if (checkTableHasDataByTableName(s.getTableName())) { //有数据的话,得需要判断属性是否可以删除 if (StringUtils.isNotBlank(s.getDeleteAttributes())) { s.setHandleResult("表格存在数据,不允许删除"+ s.getDeleteAttributes() +"字段"); return; } List columnInDbList = selectTableColumnInfo(s.getTableName()); Map columnInDbMap = new HashMap<>(); if (!CollectionUtils.isEmpty(columnInDbList)) { columnInDbMap = columnInDbList.stream().collect(Collectors.toMap(t -> t.getId().toLowerCase(), k -> k)); } List attributeVOList = idBtmTypeMap.getOrDefault(s.getId(), new BtmTypeVO()).getAttributes().stream().filter(vo -> Func.toStrList(",", s.getAddAttributes()).stream().anyMatch(id -> StringUtils.equals(vo.getId().toLowerCase(), id))).collect(Collectors.toList()); //有可能之前判断的时候数据库存在,而现在不存在了 List unExitInDbIdList = new ArrayList<>(); Map finalColumnInDbMap = columnInDbMap; List needEditAttributeVOList = new ArrayList<>(); if (!CollectionUtils.isEmpty(attributeVOList)) { attributeVOList.forEach(t -> { if (finalColumnInDbMap.containsKey(t.getId().toLowerCase().trim())) { needEditAttributeVOList.add(t); } else { unExitInDbIdList.add(t.getId()); } }); } if (!CollectionUtils.isEmpty(needEditAttributeVOList)) { List unModifyAttrVOList = needEditAttributeVOList.stream().filter(t -> !checkNotCanEditAttr(t.getAttrDataType(), finalColumnInDbMap.get(t.getId().trim().toLowerCase()))).collect(Collectors.toList()); if (!CollectionUtils.isEmpty(unModifyAttrVOList)) { s.setHandleResult("表格存在数据," + unModifyAttrVOList.stream().map(BtmTypeAttributeVO::getId).collect(Collectors.joining(",")) + "这些字段不能修改"); return; } needEditAttributeVOList.stream().forEach(t -> { String attributeLowerId = t.getId().trim().toLowerCase(); DdlTableInDataBaseBO columInDb = finalColumnInDbMap.get(attributeLowerId); if (!t.getName().equalsIgnoreCase(columInDb.getName())) { ddlMapper.commentColumnTable(s.getTableName(), t.getId(), t.getName()); } if (columInDb.getAttributeLength() != null && t.getAttributeLength() != null && t.getAttributeLength() < columInDb.getAttributeLength()) { t.setAttributeLength(columInDb.getAttributeLength()); } List attributeVOS = new ArrayList<>(); boolean nowNeedNull = false; if (!YES.equalsIgnoreCase(columInDb.getNullableFlag()) && !t.isNullableFlag()) { //说明以前是不能为空的,但是以前也是不为空的,修改会报错,所以这个调整一下 t.setNullableFlag(true); } else if (!YES.equalsIgnoreCase(columInDb.getNullableFlag()) && t.isNullableFlag()) { //以前不为空,现在为空 nowNeedNull = true; } attributeVOS.add(t); String attributeSql = getCreateSqlByAttributeForBtm(attributeVOS); if (nowNeedNull) { attributeSql += StringPool.SPACE + "null" + StringPool.SPACE; } ddlMapper.modifyTableBySql(s.getTableName(), attributeSql); }); } if (!CollectionUtils.isEmpty(unExitInDbIdList)) { if (StringUtils.isBlank(addAttributes)) { addAttributes = String.join(",", unExitInDbIdList); } else { addAttributes += "," + String.join(",", unExitInDbIdList); ; } } } else { //说明没有数据,那可以把修改的列和删除的列都删除,然后重新添加 if (StringUtils.isNotBlank(s.getModifyAttributes())) { List attributeVOList = idBtmTypeMap.getOrDefault(s.getId(), new BtmTypeVO()).getAttributes().stream().filter(vo -> Func.toStrList(",", s.getModifyAttributes()).stream().anyMatch(id -> StringUtils.equals(vo.getId(), id))).collect(Collectors.toList()); if (!CollectionUtils.isEmpty(attributeVOList)) { attributeVOList.forEach(t -> { List attributeVOS = new ArrayList<>(); attributeVOS.add(t); dropColumnByName(s.getTableName(), t.getId()); addColumnForTable(s.getTableName(), attributeVOS); ddlMapper.commentColumnTable(s.getTableName(), t.getId(), t.getName()); }); } } //需要删除的列 if (StringUtils.isNotBlank(s.getDeleteAttributes())) { List attributeIdList = VciBaseUtil.str2List(s.getDeleteAttributes()); Optional.ofNullable(attributeIdList).orElseGet(ArrayList::new).forEach(t -> { dropColumnByName(s.getTableName(), t); }); } } } if (StringUtils.isNotBlank(addAttributes)) { //只是添加属性值 if (BusinessTypeEnum.LINK.getValue().equalsIgnoreCase(s.getBusinessType())) { List attributeVOList = idLinkTypeMap.getOrDefault(s.getId(), new LinkTypeVO()).getAttributes().stream().filter(vo -> Func.toStrList(",", s.getAddAttributes()).stream().anyMatch(id -> StringUtils.equals(vo.getId(), id))).collect(Collectors.toList()); //是链接类型 // List attributeVOList = linkTypeService.listAttributeVOByIdsForLink(s.getId(), VciBaseUtil.str2List(s.getAddAttributes())); addColumn2TableForLink(attributeVOList); } else { List attributeVOList = idBtmTypeMap.getOrDefault(s.getId(), new BtmTypeVO()).getAttributes().stream().filter(vo -> Func.toStrList(",", s.getAddAttributes()).stream().anyMatch(id -> StringUtils.equals(vo.getId(), id))).collect(Collectors.toList()); addColumn2TableForBtm(attributeVOList); } } } }); } private boolean checkNotCanEditAttr(String attributeDataType, DdlTableInDataBaseBO tableInDB) { if (tableInDB != null && StringUtils.isNotBlank(attributeDataType)) { List fieldTypeEnums = dllMapper.listFieldByColumnStr(tableInDB.getAttrDataType()); Set names = fieldTypeEnums.stream().map(Enum::name).collect(Collectors.toSet()); if (names.contains(attributeDataType)) { return true; } return true; } else { //因为数据库里没有这个表格时 return true; } } /** * 获取数据库中所有的表格 * * @return 表格的名称,全是大写 */ @Override public List listAllTableName() { return ddlMapper.selectAllTableName(); } /** * 查询数据库中的表格信息 * * @param tableNamesCollections 数据库表名集合 * @return 在数据库中的信息 * @throws VciBaseException 参数为空或者数据库表不存在的时候会抛出异常 */ @Override public List listTableInfoInDB(Collection tableNamesCollections) throws VciBaseException { VciBaseUtil.alertNotNull("数据库表名称不能为空", tableNamesCollections); List tableBOList = new ArrayList<>(); tableNamesCollections.stream().forEach(s -> { tableBOList.add(ddlMapper.selectTableComment(s)); }); return tableBOList; } /** * 导出数据库中的表格信息到excel文件 * * @param tableNamesCollections 表格名称的集合 * @param merge 合并表格名称 * @return excel的文件名称 * @throws VciBaseException 蚕食为空或者数据库表不存在的时候会抛出异常 */ @Override public String exportDataBase2File(Collection tableNamesCollections, boolean merge) throws VciBaseException { return null; } /** * 获取存储文件所需要的临时文件夹,文件夹上已经包含了 * * @return 文件夹的地址,如果配置文件没有配置,则默认返回当前项目所在的文件夹 */ @Override public String getTempFolder() { return null; } /** * 导出数据库中的表格信息到word文件中 * * @param tableNamesCollections 表格名称的集合 * @return word的文件名称 * @throws VciBaseException 蚕食为空或者数据库表不存在的时候会抛出异常 */ @Override public String exportDataBase2Word(List tableNamesCollections) throws VciBaseException { return null; } /** * 拷贝数据到word模板中 * * @param tableDataBO 要写入的数据 * @return word 文件路径 *//* @Override public String writeDataToWord(WordMergeStartTableDataBO tableDataBO) { return null; }*/ /** * 判断是否为兼容性的表,这些表不应该被创建和修改 * * @param btmTypeId 业务类型的英文名称 * @param linkTypeId 业务类型的中文名称 * @return true 表示为兼容性的表,用户,角色,部门,权限这些 */ @Override public boolean isCompatibilityTable(String btmTypeId, String linkTypeId) { return false; } /** * 业务类型数据库新增或修改表 * * @param ddlDTO 业务类型链接类型传输对象 * @return 执行结果 */ @Override public R> submit(BtmAndLinkTypeDdlDTO ddlDTO) throws ServerException { try { List changedList = new ArrayList<>(); if (!CollectionUtils.isEmpty(ddlDTO.getBtmTypeList())) { List btmTypeList = ddlDTO.getBtmTypeList(); putBtm(btmTypeList.toArray(new BtmTypeVO[0])); changedList.addAll(checkDifferent(btmTypeList, null)); removeBtm(btmTypeList.toArray(new BtmTypeVO[0])); } if (!CollectionUtils.isEmpty(ddlDTO.getLinkTypeList())) { List linkTypeList = ddlDTO.getLinkTypeList(); putLink(linkTypeList.toArray(new LinkTypeVO[0])); changedList.addAll(checkDifferent(null,linkTypeList)); removeLink(linkTypeList.toArray(new LinkTypeVO[0])); } String msg = "数据库操作成功"; R> result = new R<>(); if((!changedList.isEmpty())&&Func.isEmpty(changedList.get(0).getHandleResult())){ result = R.success(msg); }else { result = R.fail(changedList.get(0).getHandleResult()); } result.setData(changedList); return result; } catch (Exception e) { try { // 建表失败有异常,捕获后返回,并释放线程中的内容 if (!CollectionUtils.isEmpty(ddlDTO.getBtmTypeList())) { removeBtm(ddlDTO.getBtmTypeList().toArray(new BtmTypeVO[0])); } if (!CollectionUtils.isEmpty(ddlDTO.getLinkTypeList())) { removeLink(ddlDTO.getLinkTypeList().toArray(new LinkTypeVO[0])); } return R.fail(e.getMessage()); }catch (ServiceException e2){ return R.fail(e.getMessage()); } } } /** * 按表名获取表信息 * * @param tableName 表名 * @return 表信息 */ @Override public DdlTableBO getTableColumnByTableName(String tableName) { VciBaseUtil.alertNotNull(tableName, "表名"); DdlTableBO tableBO = getTableInfoByTableName(tableName); List columnInfo = selectTableColumnInfo(tableName); tableBO.setColumns(columnInfo); return tableBO; } /** * 查询数据库中表格的字段信息 * * @param tableName 表格的名称 * @return 数据库表的字段信息 */ private List selectTableColumnInfo(String tableName) { VciBaseUtil.alertNotNull(tableName, "表格名称"); return ddlMapper.selectTableColumnInfo(tableName); } /** * 表名获取表信息 * * @param tableName 表名 * @return 表信息 */ private DdlTableBO getTableInfoByTableName(String tableName) { VciBaseUtil.alertNotNull(tableName, "表格名称"); return ddlMapper.selectTableComment(tableName); } /** * 获取所有表信息 * * @return 表信息集合 */ @Override public List getAllTableInfo() { List allTableName = listAllTableName(); if (!CollectionUtils.isEmpty(allTableName)) { List allTableBO = listTableInfoInDB(allTableName); List btmTypeVOList = new ArrayList<>(); allTableBO.forEach(table -> { BtmTypeVO vo = new BtmTypeVO(); vo.setTableName(table.getTableName().toLowerCase()); vo.setDescription(table.getTableDesc()); List columns = selectTableColumnInfo(table.getTableName()); List attributes = new ArrayList<>(); columns.forEach(col -> { BtmTypeAttributeVO attributeVO = new BtmTypeAttributeVO(); attributeVO.setId(col.getId().toLowerCase()); attributeVO.setName(col.getName()); attributeVO.setNullableFlag(StringUtils.equals(col.getNullableFlag(), BooleanEnum.TRUE.getValue())); attributeVO.setAttributeLength(col.getAttributeLength()); attributeVO.setPrecisionLength(col.getPrecisionLength()); attributeVO.setScaleLength(col.getScaleLength()); VciFieldTypeEnum field = dllMapper.getFieldTypeByColumnStr(col.getAttrDataType(), col.getAttributeLength()); if (field != null){ attributeVO.setAttrDataType(field.name()); } if(col.getPrecisionLength() != null){ attributeVO.setAttrDataType(VciFieldTypeEnum.VTDouble.name()); } attributes.add(attributeVO); }); vo.setAttributes(attributes); btmTypeVOList.add(vo); }); return btmTypeVOList; } return new ArrayList<>(); } /** * 检查数据表是否存在数据,不存在则删除 * * @param tableCheckDTOList 需要检查的表集合 * @return 检查结果 */ @Override public TableCheckResultDTO checkTableHasDataThenDelete(List tableCheckDTOList) { TableCheckResultDTO resultDTO = new TableCheckResultDTO(); List successList = new ArrayList<>(); List failList = new ArrayList<>(); tableCheckDTOList.forEach(table -> { VciBaseUtil.alertNotNull(table.getTableName(),"数据表名称"); TableCheckDTO checkDTO = new TableCheckDTO(); boolean hasDataFlag = checkTableHasDataByTableName(table.getTableName()); if (hasDataFlag){ table.setDone(false); failList.add(checkDTO); }else { dropTableByName(table.getTableName()); table.setDone(true); successList.add(table); } }); if (!CollectionUtils.isEmpty(successList)){ resultDTO.setSuccessList(successList); } if (!CollectionUtils.isEmpty(failList)){ resultDTO.setFailList(failList); } return resultDTO; } /** * 为表添加字段 * * @param addColumnDTO 添加的对象 * @return 执行结果标识 */ @Override public Boolean addColumnForTable(TableAddColumnDTO addColumnDTO) { VciBaseUtil.alertNotNull(addColumnDTO,"添加字段的对象"); if (!CollectionUtils.isEmpty(addColumnDTO.getLinkTypeAttributeVOList())){ addColumn2TableForLink(addColumnDTO.getLinkTypeAttributeVOList()); } if(!CollectionUtils.isEmpty(addColumnDTO.getBtmTypeAttributeVOList())){ addColumn2TableForBtm(addColumnDTO.getBtmTypeAttributeVOList()); } return true; } }