From 610a4d10ed02a771ad31c4d719cd6648b535e9b1 Mon Sep 17 00:00:00 2001 From: sunquan <287962685@qq.com> Date: Mon, 6 Jul 2026 11:26:44 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feature-online-form-direct-creation:?= =?UTF-8?q?=E6=94=B6=E5=88=B0=E8=AF=B7=E6=B1=82=E5=90=8E=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=95=B0=E6=8D=AE=E5=BA=93=E7=89=A9=E7=90=86?= =?UTF-8?q?=E8=A1=A8=20+=20=E5=85=83=E6=95=B0=E6=8D=AE=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=20+=20=E6=95=B0=E6=8D=AE=E6=BA=90=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generator/service/IOnlFormHeadService.java | 11 + .../service/impl/OnlFormHeadServiceImpl.java | 38 +++ .../online/controller/OnlineFormController.java | 293 +++++++++++++++++++++ .../online/controller/OnlinePageController.java | 71 +++-- .../apelet/common/online/dto/OnlinePageDto.java | 14 +- 5 files changed, 410 insertions(+), 17 deletions(-) diff --git a/common/common-generator/src/main/java/apelet/common/generator/service/IOnlFormHeadService.java b/common/common-generator/src/main/java/apelet/common/generator/service/IOnlFormHeadService.java index 0782aa4..0172fe3 100644 --- a/common/common-generator/src/main/java/apelet/common/generator/service/IOnlFormHeadService.java +++ b/common/common-generator/src/main/java/apelet/common/generator/service/IOnlFormHeadService.java @@ -119,4 +119,15 @@ public interface IOnlFormHeadService extends IService { * @return */ OnlFormHead getHeadTableNameCache(String tableName); + + /** + * 创建元数据(含默认字段)并同步数据库. 返回创建后的 OnlFormHead. + * + * @param tableName 表名 + * @param tableTxt 表描述 + * @param metaType 表类型: "0"=附表(分录), "1"=主表(业务单据), "2"=单表(基础资料) + * @param sortFiled 关联字段(附表时传主表表名) + * @return OnlFormHead + */ + OnlFormHead createMetaAndSync(String tableName, String tableTxt, String metaType, String sortFiled); } diff --git a/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java b/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java index 4f54f5a..a6915a5 100644 --- a/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java +++ b/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java @@ -1660,4 +1660,42 @@ public class OnlFormHeadServiceImpl extends ServiceImpl list) { onlFormHeadMapper.saveEasDict(list); } + + @Override + @Transactional(rollbackFor = Exception.class) + public OnlFormHead createMetaAndSync(String tableName, String tableTxt, String metaType, String sortFiled) { + OnlFormHead head = new OnlFormHead(); + head.setId(idGenerator.nextLongId()); + head.setTableName(tableName); + head.setTableTxt(tableTxt); + head.setTableType(metaType); + head.setStatus("0"); // 未同步状态 + head.setLine(CustomUtil.MetaType_Entry.equals(metaType) ? 1 : 0); + if (StringUtils.isNotEmpty(sortFiled)) { + head.setSort(sortFiled); + } + + // 初始化审计字段(createUserId/updateUserId/createTime/updateTime/deletedFlag) + addOrUpdateBaseData(head, head.getId()); + + // Build DTO + OnlFormHeadDto dto = new OnlFormHeadDto(); + BeanUtil.copyProperties(head, dto); + + // Generate default fields + List defaultFields = new ArrayList<>(); + defaultData(defaultFields, null, null, metaType); + dto.setOnlFormFieldList(defaultFields); + + // Save + this.addAll(dto); + + // Reload to get full info + OnlFormHead saved = this.getById(head.getId()); + + // Sync database (type=0: CREATE TABLE or ALTER TABLE ADD COLUMN) + this.syncDB(saved, 0L); + + return saved; + } } diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java index fa8dc0c..d075054 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java @@ -12,8 +12,12 @@ import apelet.common.core.util.MyPageUtil; import apelet.common.core.validator.UpdateGroup; import apelet.common.dbutil.object.SqlTable; import apelet.common.dbutil.object.SqlTableColumn; +import apelet.common.generator.model.OnlFormField; import apelet.common.generator.model.OnlFormHead; +import apelet.common.generator.service.IOnlFormFieldService; import apelet.common.generator.service.IOnlFormHeadService; +import apelet.common.generator.utils.CustomUtil; +import apelet.common.online.util.WidgetFieldTypeMapping; import apelet.common.log.annotation.OperationLog; import apelet.common.log.model.constant.SysOperationLogType; import apelet.common.online.config.OnlineProperties; @@ -49,6 +53,7 @@ import javax.annotation.Resource; import javax.validation.groups.Default; import java.lang.reflect.Method; import java.util.*; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -83,6 +88,8 @@ public class OnlineFormController { @Autowired IOnlFormHeadService onlFormHeadService; @Autowired + IOnlFormFieldService onlFormFieldService; + @Autowired OnlinePageService onlinePageService; @Autowired private OnlineProperties properties; @@ -326,6 +333,13 @@ public class OnlineFormController { onlineForm.setWidgetJson(jsonObject.toJSONString()); } + // ★ 新增: 处理新增字段和子表 + JSONObject updatedJson = syncNewFieldsAndSubTables(onlineForm, onlineFormDto, JSON.parseObject(onlineForm.getWidgetJson())); + if (updatedJson != null) { + onlineForm.setWidgetJson(updatedJson.toJSONString()); + onlineFormDto.setWidgetJson(updatedJson.toJSONString()); + } + if (!onlineFormService.update(onlineForm, originalOnlineForm, datasourceIdSet)) { redissonClient.getBucket(OnlineRedisKeyUtil.makeOnlineFormKey(onlineForm.getFormId())).delete(); return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); @@ -685,4 +699,283 @@ public class OnlineFormController { } return ResponseResult.success(onlineFormList); } + + // ============ 字段diff+同步 相关私有方法 ============ + + /** + * 对比 widgetJson 与现有 OnlFormField / OnlFormHead 识别新增字段和子表, + * 创建 OnlFormField 记录、同步数据库、创建 OnlineColumn、回填 columnId/relationId。 + * + * @return 修改后的 widgetJson (含回填的 columnId/relationId),无变更则返回 null + */ + private JSONObject syncNewFieldsAndSubTables(OnlineForm form, OnlineFormDto dto, JSONObject widgetJson) { + // 1. 获取数据源 → OnlineTable → OnlFormHead + OnlineDatasource datasource = onlineDatasourceService.getById(dto.getDatasourceIdList().get(0)); + OnlineTable onlineTable = onlineTableService.getById(datasource.getMasterTableId()); + + OnlFormHead onlFormHead = onlFormHeadService.getOne( + new LambdaQueryWrapper() + .eq(OnlFormHead::getTableName, onlineTable.getTableName())); + if (onlFormHead == null) { + return null; + } + + boolean changed = false; + + // === Diff 新增字段 === + Set widgetColumnNames = collectAllBindColumnNames(widgetJson); + List existingFields = onlFormFieldService.list( + new LambdaQueryWrapper().eq(OnlFormField::getHeadId, onlFormHead.getId())); + Set existingFieldNames = existingFields.stream() + .map(OnlFormField::getFieldName).collect(Collectors.toSet()); + Set newColumnNames = new HashSet<>(widgetColumnNames); + newColumnNames.removeAll(existingFieldNames); + + if (!newColumnNames.isEmpty()) { + Map nameToWidget = mapColumnNameToWidget(widgetJson); + OnlineDblink dblink = onlineDblinkService.getById(datasource.getDblinkId()); + + // 预校验:过滤掉 widgetType 不在映射中的控件,避免 getFieldTypeId 抛异常导致部分数据已入库 + Set validColumnNames = new LinkedHashSet<>(); + for (String fieldName : newColumnNames) { + JSONObject widget = nameToWidget.get(fieldName); + Integer widgetType = widget != null ? widget.getInteger("widgetType") : null; + if (widgetType == null || !WidgetFieldTypeMapping.isDataWidget(widgetType)) { + continue; + } + validColumnNames.add(fieldName); + } + if (validColumnNames.isEmpty()) { + return changed ? widgetJson : null; + } + + for (String fieldName : validColumnNames) { + JSONObject widget = nameToWidget.get(fieldName); + Integer widgetType = widget.getInteger("widgetType"); + + OnlFormField field = new OnlFormField(); + field.setHeadId(onlFormHead.getId()); + field.setFieldName(fieldName); + field.setFieldType(WidgetFieldTypeMapping.getFieldTypeId(widgetType)); + Integer length = WidgetFieldTypeMapping.getDefaultLength(widgetType); + if (length != null) { + field.setFieldLength(length); + } + field.setIsEmpty(1); + field.setIsDefault(0); + field.setRowDisabled(0); + field.setSyncFlag(0); + + // 从 widget 的 bindData.columnComment 设置字段备注 + JSONObject bindData = widget.getJSONObject("bindData"); + if (bindData != null && bindData.containsKey("columnComment")) { + field.setFieldRemark(bindData.getString("columnComment")); + } + onlFormFieldService.save(field); + } + + // ALTER TABLE ADD COLUMN + onlFormHeadService.syncDB(onlFormHead, 0L); + + // 批量获取所有列信息,避免 N+1 查询 + List allColumns = onlineDblinkService.getDblinkTableColumnList( + dblink, onlineTable.getTableName()); + Map columnMap = new HashMap<>(); + if (CollUtil.isNotEmpty(allColumns)) { + for (SqlTableColumn col : allColumns) { + if (col.getColumnName() != null) { + columnMap.put(col.getColumnName().toLowerCase(), col); + } + } + } + + // 增量创建 OnlineColumn + 回填 columnId 到 widgetJson + for (String fieldName : validColumnNames) { + SqlTableColumn sqlCol = columnMap.get(fieldName.toLowerCase()); + if (sqlCol != null) { + OnlineColumn newCol = new OnlineColumn(); + newCol.setColumnName(sqlCol.getColumnName()); + newCol.setColumnType(sqlCol.getColumnType()); + newCol.setFullColumnType(sqlCol.getFullColumnType()); + if (sqlCol.getColumnDefault() != null) { + newCol.setColumnDefault(sqlCol.getColumnDefault().toString()); + } + newCol.setNullable(sqlCol.getNullable()); + newCol.setTableId(onlineTable.getTableId()); + onlineColumnService.save(newCol); + + // 回填 columnId 到 widgetJson + JSONObject widget = nameToWidget.get(fieldName); + if (widget != null) { + JSONObject bindData2 = widget.getJSONObject("bindData"); + if (bindData2 != null) { + bindData2.put("columnId", newCol.getColumnId()); + bindData2.put("tableId", onlineTable.getTableId()); + } + } + } + } + changed = true; + } + + // === Diff 新增子表 === + Set widgetSubTables = collectSubTableNames(widgetJson); + List existingSubTables = onlFormHeadService.list( + new LambdaQueryWrapper() + .eq(OnlFormHead::getSort, onlFormHead.getTableName()) + .eq(OnlFormHead::getLine, 1)); + Set existingSubTableNames = existingSubTables.stream() + .map(OnlFormHead::getTableName).collect(Collectors.toSet()); + Set newSubTableNames = new HashSet<>(widgetSubTables); + newSubTableNames.removeAll(existingSubTableNames); + + if (!newSubTableNames.isEmpty()) { + // 获取主表的主键字段(id)作为关联字段 + OnlineColumn masterPkColumn = onlineColumnService.getOne( + new LambdaQueryWrapper() + .eq(OnlineColumn::getTableId, onlineTable.getTableId()) + .eq(OnlineColumn::getColumnName, "id")); + + for (String subTableName : newSubTableNames) { + OnlFormHead subHead = onlFormHeadService.createMetaAndSync( + subTableName, + onlFormHead.getTableTxt() + "附表", + CustomUtil.MetaType_Entry, + onlFormHead.getTableName()); + + // 获取子表的 OnlineTable + OnlineTable subOnlineTable = onlineTableService.getOne( + new LambdaQueryWrapper() + .eq(OnlineTable::getTableName, subTableName.toLowerCase())); + if (subOnlineTable == null) { + // 从DB获取表结构并创建 OnlineTable + SqlTable subSqlTable = onlineDblinkService.getDblinkTable( + onlineDblinkService.getById(datasource.getDblinkId()), subTableName); + if (subSqlTable != null) { + subOnlineTable = onlineTableService.saveNewFromSqlTable(subSqlTable); + } + } + + // 创建子表数据源 + OnlineDatasource subDatasource = new OnlineDatasource(); + subDatasource.setDblinkId(datasource.getDblinkId()); + if (subOnlineTable != null) { + subDatasource.setMasterTableId(subOnlineTable.getTableId()); + } + onlineDatasourceService.save(subDatasource); + + // 创建 1:N 关系 + OnlineDatasourceRelation relation = new OnlineDatasourceRelation(); + relation.setDatasourceId(datasource.getDatasourceId()); + relation.setRelationType(1); + if (subOnlineTable != null) { + relation.setSlaveTableId(subOnlineTable.getTableId()); + } + if (masterPkColumn != null) { + relation.setMasterColumnId(masterPkColumn.getColumnId()); + } + onlineDatasourceRelationService.save(relation); + + backfillRelationId(widgetJson, subTableName, relation.getRelationId()); + } + changed = true; + } + + return changed ? widgetJson : null; + } + + /** + * 遍历 pc/mobile 的 widget 树,收集所有 bindData.columnName 值。 + */ + private Set collectAllBindColumnNames(JSONObject widgetJson) { + Set names = new HashSet<>(); + walkAllModes(widgetJson, widget -> { + JSONObject bindData = widget.getJSONObject("bindData"); + if (bindData != null && bindData.containsKey("columnName")) { + String name = bindData.getString("columnName"); + if (StrUtil.isNotEmpty(name)) { + names.add(name); + } + } + }); + return names; + } + + /** + * 遍历 pc/mobile 的 widget 树,收集 widgetType=403 (TableContainer) 的 props.tableName 值。 + */ + private Set collectSubTableNames(JSONObject widgetJson) { + Set names = new HashSet<>(); + walkAllModes(widgetJson, widget -> { + if (widget.getInteger("widgetType") != null && 403 == widget.getInteger("widgetType")) { + JSONObject props = widget.getJSONObject("props"); + if (props != null && props.containsKey("tableName")) { + String tn = props.getString("tableName"); + if (StrUtil.isNotEmpty(tn)) { + names.add(tn); + } + } + } + }); + return names; + } + + /** + * 构建 columnName → widget 的映射。 + */ + private Map mapColumnNameToWidget(JSONObject widgetJson) { + Map map = new HashMap<>(); + walkAllModes(widgetJson, widget -> { + JSONObject bindData = widget.getJSONObject("bindData"); + if (bindData != null && bindData.containsKey("columnName")) { + String name = bindData.getString("columnName"); + if (StrUtil.isNotEmpty(name)) { + map.put(name, widget); + } + } + }); + return map; + } + + /** + * 在 widgetJson 中查找匹配 tableName 的 TableContainer 控件,回填 relationId。 + */ + private void backfillRelationId(JSONObject widgetJson, String tableName, Long relationId) { + walkAllModes(widgetJson, widget -> { + if (widget.getInteger("widgetType") != null && 403 == widget.getInteger("widgetType")) { + JSONObject props = widget.getJSONObject("props"); + if (props != null && tableName.equals(props.getString("tableName"))) { + props.put("relationId", relationId); + } + } + }); + } + + /** + * 遍历 "pc" 和 "mobile" 两个模式的控件树。 + */ + private void walkAllModes(JSONObject widgetJson, Consumer visitor) { + for (String mode : new String[]{"pc", "mobile"}) { + JSONObject modeObj = widgetJson.getJSONObject(mode); + if (modeObj != null) { + walkWidgets(modeObj, visitor); + } + } + } + + /** + * 递归遍历控件树,访问每个控件及其子控件(widgetList)。 + */ + private void walkWidgets(JSONObject node, Consumer visitor) { + if (node == null) { + return; + } + visitor.accept(node); + JSONArray children = node.getJSONArray("widgetList"); + if (children != null) { + for (int i = 0; i < children.size(); i++) { + walkWidgets(children.getJSONObject(i), visitor); + } + } + } } diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java index 666ea6d..0fd5efa 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java @@ -36,6 +36,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.dao.DuplicateKeyException; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import javax.validation.groups.Default; @@ -82,41 +83,84 @@ public class OnlinePageController { */ @ApiOperationSupport(ignoreParameters = {"onlinePageDto.pageId"}) @OperationLog(type = SysOperationLogType.ADD) + @Transactional(rollbackFor = Exception.class) @PostMapping("/add") public ResponseResult add(@MyRequestBody OnlinePageDto onlinePageDto) { String errorMessage = MyCommonUtil.getModelValidationError(onlinePageDto); if (errorMessage != null) { return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); } + // Validate based on metaSource + String metaSource = onlinePageDto.getMetaSource(); + if ("new".equals(metaSource)) { + // New metadata flow: metaType and pageCode are required + if (StrUtil.isEmpty(onlinePageDto.getMetaType())) { + errorMessage = "数据验证失败,新建元数据时表类型(metaType)不能为空!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (StrUtil.isEmpty(onlinePageDto.getPageCode())) { + errorMessage = "数据验证失败,新建元数据时页面编码不能为空!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } else { + // Existing metadata flow: masterTableId is required + if (StrUtil.isEmpty(onlinePageDto.getMasterTableId())) { + errorMessage = "数据验证失败,表单元数据不能为空!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } OnlinePage onlinePage = MyModelUtil.copyTo(onlinePageDto, OnlinePage.class); if (onlinePageService.existByPageCode(onlinePage.getPageCode())) { errorMessage = "数据验证失败,页面编码已经存在!"; return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, errorMessage); } + + Long masterTableId; + OnlFormHead onlFormHead; + + if ("new".equals(metaSource)) { + // === New branch: create fresh metadata === + String metaType = onlinePageDto.getMetaType(); + String tableName = onlinePageDto.getPageCode(); + String tableTxt = onlinePageDto.getPageName(); + + onlFormHead = iOnlFormHeadService.createMetaAndSync(tableName, tableTxt, metaType, null); + masterTableId = onlFormHead.getId(); + onlinePage.setMasterTableId(String.valueOf(masterTableId)); + onlinePage.setMasterTableName(onlFormHead.getTableName()); + + // For business documents (metaType="1"): auto-create sub-table + if (CustomUtil.MetaType_Main.equals(metaType)) { + String entryTableName = tableName + "_entry"; + iOnlFormHeadService.createMetaAndSync(entryTableName, tableTxt + "附表", CustomUtil.MetaType_Entry, tableName); + } + } else { + // === Existing branch: use existing metadata === + String formMetadata = onlinePageDto.getMasterTableId(); + onlFormHead = iOnlFormHeadService.getById(formMetadata); + masterTableId = Long.valueOf(formMetadata); + } + try { onlinePage = onlinePageService.saveNew(onlinePage); } catch (DuplicateKeyException e) { errorMessage = "数据验证失败,当前应用的页面编码已经存在!"; return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); } - //根据所传表单元数据id查出对应表单信息 - String formMetadata = onlinePageDto.getMasterTableId(); - //在线表单主表对象 - OnlFormHead onlFormHead = iOnlFormHeadService.getById(formMetadata); - //准备创建数据模型所需的数据 + + // 准备创建数据模型所需的数据 OnlineDatasourceDto onlineDatasourceDto = new OnlineDatasourceDto(); - //数据源标识-取表名驼峰 + // 数据源标识-取表名驼峰 onlineDatasourceDto.setVariableName(CustomUtil.UnderlineToCamel(onlFormHead.getTableName())); - //数据主表标识 + // 数据主表标识 onlineDatasourceDto.setMasterTableName(onlFormHead.getTableName()); - //数据源名称-取表名 + // 数据源名称-取表名 onlineDatasourceDto.setDatasourceName((onlFormHead.getTableName())); - - //目前系统只有一个数据源,所以默认1740180645717610505 + // 目前系统只有一个数据源,所以默认1740180645717610505 OnlineDblink onlineDblink = onlineDblinkService.getById(1740180645717610505L); onlineDatasourceDto.setDblinkId(1740180645717610505L); - //创建数据模型 + // 创建数据模型 SqlTable sqlTable = onlineDblinkService.getDblinkTable(onlineDblink, onlineDatasourceDto.getMasterTableName()); if (sqlTable == null) { errorMessage = "数据验证失败,指定的数据表名不存在!"; @@ -130,14 +174,11 @@ public class OnlinePageController { return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); } /** - *创建数据表关联关系 先查出改元数据表的所有附表关系 + * 创建数据表关联关系 先查出改元数据表的所有附表关系 * 一对多 - * */ - addOnlineDatasourceRelation(onlFormHead, onlineDatasource, errorMessage, onlineDblink); - return ResponseResult.success(onlinePage.getPageId()); } diff --git a/common/common-online/src/main/java/apelet/common/online/dto/OnlinePageDto.java b/common/common-online/src/main/java/apelet/common/online/dto/OnlinePageDto.java index 59c2529..afa6f86 100644 --- a/common/common-online/src/main/java/apelet/common/online/dto/OnlinePageDto.java +++ b/common/common-online/src/main/java/apelet/common/online/dto/OnlinePageDto.java @@ -60,13 +60,23 @@ public class OnlinePageDto { * 表单元数据。 */ @Schema(description = "表单元数据") - @NotNull(message = "数据验证失败,表单元数据不能为空!") private String masterTableId; /** * 表单元数据。 */ @Schema(description = "表单元数据表名") -// @NotNull(message = "数据验证失败,表单元数据不能为空!") private String masterTableName; + + /** + * 数据来源: "new"=新建元数据, "existing"=使用已有元数据。 + */ + @Schema(description = "数据来源: new=新建元数据, existing=使用已有元数据") + private String metaSource; + + /** + * 表类型: "2"=基础资料(单表), "1"=业务单据(主表+附表)。仅在metaSource="new"时有效。 + */ + @Schema(description = "表类型: 2=基础资料(单表), 1=业务单据(主表+附表)。仅在metaSource=new时有效") + private String metaType; } From c665cde835f528c7fc4969e22097af0181df5a5f Mon Sep 17 00:00:00 2001 From: sunquan <287962685@qq.com> Date: Mon, 6 Jul 2026 16:38:39 +0800 Subject: [PATCH 2/9] =?UTF-8?q?fix:=E5=8E=BB=E6=8E=89nacos=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenant-admin/src/main/resources/bootstrap.yml | 22 +++--- .../src/main/resources/logback-spring.xml | 82 +++++++++++----------- 2 files changed, 50 insertions(+), 54 deletions(-) diff --git a/application-tenant/tenant-admin/src/main/resources/bootstrap.yml b/application-tenant/tenant-admin/src/main/resources/bootstrap.yml index e6112a8..f1901e3 100644 --- a/application-tenant/tenant-admin/src/main/resources/bootstrap.yml +++ b/application-tenant/tenant-admin/src/main/resources/bootstrap.yml @@ -3,20 +3,14 @@ spring: name: tenant-admin profiles: active: @profile.name@ - cloud: - nacos: - discovery: - server-addr: @discovery.server-addr@ - config: - server-addr: @config.server-addr@ - group: @config.group@ - namespace: @config.namespace@ - file-extension: yaml - # 共享配置文件,排序越高后,优先级越高。 - shared-configs: - - data-id: application-${spring.profiles.active}.yaml - group: @config.group@ - refresh: true main: allow-bean-definition-overriding: true allow-circular-references: true + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure + config: + import: + - classpath:tenant-admin-dev.yml + - classpath:application-config.yml # 引入共享配置 diff --git a/application-tenant/tenant-admin/src/main/resources/logback-spring.xml b/application-tenant/tenant-admin/src/main/resources/logback-spring.xml index 759d941..68533c6 100644 --- a/application-tenant/tenant-admin/src/main/resources/logback-spring.xml +++ b/application-tenant/tenant-admin/src/main/resources/logback-spring.xml @@ -16,6 +16,7 @@ debug:当此属性设置为true时,将打印出logback内部日志信息, + @@ -89,48 +91,48 @@ debug:当此属性设置为true时,将打印出logback内部日志信息, - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1d42dfc702366a4e5f857725981ca2cb3b271cff Mon Sep 17 00:00:00 2001 From: sunquan <287962685@qq.com> Date: Mon, 6 Jul 2026 16:44:11 +0800 Subject: [PATCH 3/9] =?UTF-8?q?fix:=E5=8E=BB=E6=8E=89nacos=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=20app-config=E3=80=81t-admin-dev?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-config.yml | 161 ++++++++++ .../src/main/resources/tenant-admin-dev.yml | 355 +++++++++++++++++++++ 2 files changed, 516 insertions(+) create mode 100644 application-tenant/tenant-admin/src/main/resources/application-config.yml create mode 100644 application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml diff --git a/application-tenant/tenant-admin/src/main/resources/application-config.yml b/application-tenant/tenant-admin/src/main/resources/application-config.yml new file mode 100644 index 0000000..158d786 --- /dev/null +++ b/application-tenant/tenant-admin/src/main/resources/application-config.yml @@ -0,0 +1,161 @@ +server: + tomcat: + uri-encoding: UTF-8 + threads: + max: 100 + min-spare: 10 + servlet: + encoding: + force: true + charset: UTF-8 + enabled: true + +logging: + config: classpath:logback-spring.xml + +spring: + servlet: + multipart: + max-file-size: 50MB + max-request-size: 50MB + mvc: + converters: + preferred-json-mapper: fastjson + freemarker: + template-loader-path: classpath:/template/ + cache: false + charset: UTF-8 + check-template-location: true + content-type: text/html + expose-request-attributes: false + expose-session-attributes: false + request-context-attribute: request + suffix: .ftl + cloud: + sentinel: + transport: + # sentinel控制台地址。 + # 由于8080端口容易与其他服务端口冲突,可以在启动sentinel控制台时动态修改,如: + # java -Dserver.port=8858 -jar sentinel-dashboard-$VERSION.jar + # 改为8858后,下面的配置端口也需要改为:localhost:8858。 + dashboard: localhost:8858 + +# feign 配置 +feign: + sentinel: + enabled: false + httpclient: + enabled: true + max-connections: 200 + max-connections-per-route: 50 + client: + config: + default: + # 输出feignclient的日志,缺省值为none,可选值为none/basic/headers/full + # 注意:需要把feignclient类所在包的日志级别设置为debug时才生效。如: + # logging: + # level: + # com.demo.multi: info + # com.demo.multi.coursepaperinterface.client: debug + loggerLevel: full + connectTimeout: 5000 + readTimeout: 10000 + compression: + request: + enabled: true + response: + enabled: true + +common-core: + # 可选值为 mysql / postgresql / oracle / dm8 / kingbase + databaseType: mysql + +swagger: + # 当enabled为false的时候,则可禁用swagger。 + enabled: true + # 工程的基础包名。 + basePackage: apelet + # 工程服务的基础包名。 + serviceBasePackage: + title: 小猿微服务工程 + description: 小猿微服务工程详情 + version: 1.0 +knife4j: + # 打开knife4j增强模式。 + enable: true + +aliyun: + oss: + enabled: false + expireSeconds: 1000 + # 下面几项均需在申请阿里云OSS后,根据自己的实际情况进行配置。 + endpoint: + accessKey: + secretKey: + bucketName: + +minio: + enabled: false + endpoint: + accessKey: + secretKey: + bucketName: + +# 暴露监控端点 +management: + metrics: + tags: + application: ${spring.application.name} + endpoints: + web: + exposure: + include: '*' + jmx: + exposure: + include: '*' + endpoint: + # 与中间件相关的健康详情也会被展示 + health: + show-details: always + configprops: + # 在/actuator/configprops中,所有包含password的配置,将用 * 隐藏。 + # 如果不想隐藏任何配置项的值,可以直接使用如下被注释的空值。 + # keys-to-sanitize: + keys-to-sanitize: password + server: + base-path: "/" + +# 存储session数据的Redis,所有服务均需要,因此放到公共配置中。 +# 根据实际情况,该Redis也可以用于存储其他数据。 +common-redis: + # redisson的配置。每个服务可以自己的配置文件中覆盖此选项。 + redisson: + # 如果该值为false,系统将不会创建RedissionClient的bean。 + enabled: true + # mode的可用值为,single/cluster/sentinel/master-slave + mode: single + # single: 单机模式 + # address: redis://localhost:6379 + # cluster: 集群模式 + # 每个节点逗号分隔,同时每个节点前必须以redis://开头。 + # address: redis://localhost:6379,redis://localhost:6378,... + # sentinel: + # 每个节点逗号分隔,同时每个节点前必须以redis://开头。 + # address: redis://localhost:6379,redis://localhost:6378,... + # master-slave: + # 每个节点逗号分隔,第一个为主节点,其余为从节点。同时每个节点前必须以redis://开头。 + # address: redis://localhost:6379,redis://localhost:6378,... + address: redis://192.168.100.25:6379 + # 链接超时,单位毫秒。 + timeout: 6000 + # 单位毫秒。分布式锁的超时检测时长。 + # 如果一次锁内操作超该毫秒数,或在释放锁之前异常退出,Redis会在该时长之后主动删除该锁使用的key。 + lockWatchdogTimeout: 60000 + # redis 密码,空可以不填。 + password: + database: 0 + pool: + # 连接池数量。 + poolSize: 20 + # 连接池中最小空闲数量。 + minIdle: 5 diff --git a/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml b/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml new file mode 100644 index 0000000..14aee5a --- /dev/null +++ b/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml @@ -0,0 +1,355 @@ +logging: + level: + # 这里设置的日志级别优先于logback-spring.xml文件Loggers中的日志级别。 + apelet: info + config: classpath:logback-spring.xml + +server: + port: 8075 + +application: + # Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。 + tokenSigningKey: tenantadmin-signing-key-signing-key + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # Jwt令牌过期时间(毫秒)。 + expiration: 72000000 + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./zz-resource/upload-files/tenant-admin + # 跨域的IP(http://192.168.10.10:8086)白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + # 同步租户公共管理数据到消息队列的主题,再由同步消费者服务将数据同步到目标数据库中。 + tenantSyncTopic: TenantSync + # Session会话和用户和权限在Redis中的过期时间(秒)。 + sessionExpiredSeconds: 86400 + # Session的数据权限信息在Redis中的过期时间(秒)。 + dataPermExpiredSeconds: 86460 + # 是否排他登录。 + excludeLogin: false +common-eas: + urlPrefix: /tenantadmin/eas +common-ext: + urlPrefix: /tenantadmin/commonext +common-mobile: + # 注意不要以反斜杠(/)结尾。 + urlPrefix: /tenantadmin/mobile + # 在线表单业务数据上传资源路径 + uploadFileBaseDir: ./zz-resource/upload-files/mobile +common-online: + # 注意不要以反斜杠(/)结尾。 + urlPrefix: /tenantadmin/online + # 打印接口的路径,不要以反斜杠(/)结尾。 + printUrlPath: /tenantadmin/report/reportPrint/print + # 在线表单业务数据上传资源路径 + uploadFileBaseDir: ./zz-resource/upload-files/online + # 如果为false,在线表单模块中所有Controller接口将不能使用。 + operationEnabled: true + # 1: minio 2: aliyun-oss 3: qcloud-cos。 + distributeStoreType: 2 + # 调用render接口时候,是否打开一级缓存加速。 + enableRenderCache: false + # 脱敏字段的掩码字符,只能为单个字符。 + maskChar: '*' + # 下面的url列表,请保持反斜杠(/)结尾。 + viewUrlList: + - ${common-online.urlPrefix}/onlineOperation/viewByDatasourceId/ + - ${common-online.urlPrefix}/onlineOperation/viewByOneToManyRelationId/ + - ${common-online.urlPrefix}/onlineOperation/listByDatasourceId/ + - ${common-online.urlPrefix}/onlineOperation/listByOneToManyRelationId/ + - ${common-online.urlPrefix}/onlineOperation/exportByDatasourceId/ + - ${common-online.urlPrefix}/onlineOperation/exportByOneToManyRelationId/ + - ${common-online.urlPrefix}/onlineOperation/downloadDatasource/ + - ${common-online.urlPrefix}/onlineOperation/downloadOneToManyRelation/ + - ${common-online.urlPrefix}/onlineOperation/print/ + editUrlList: + - ${common-online.urlPrefix}/onlineOperation/addDatasource/ + - ${common-online.urlPrefix}/onlineOperation/addOneToManyRelation/ + - ${common-online.urlPrefix}/onlineOperation/updateDatasource/ + - ${common-online.urlPrefix}/onlineOperation/updateOneToManyRelation/ + - ${common-online.urlPrefix}/onlineOperation/deleteDatasource/ + - ${common-online.urlPrefix}/onlineOperation/deleteOneToManyRelation/ + - ${common-online.urlPrefix}/onlineOperation/deleteBatchDatasource/ + - ${common-online.urlPrefix}/onlineOperation/deleteBatchOneToManyRelation/ + - ${common-online.urlPrefix}/onlineOperation/uploadDatasource/ + - ${common-online.urlPrefix}/onlineOperation/uploadOneToManyRelation/ + +common-flow: + # 请慎重修改urlPrefix的缺省配置,注意不要以反斜杠(/)结尾。如必须修改其他路径,请同步修改数据库脚本。 + urlPrefix: /tenantadmin/flow + # 如果为false,流程模块的所有Controller中的接口将不能使用。 + operationEnabled: true + +common-report: + # 注意不要以反斜杠(/)结尾。 + urlPrefix: /tenantadmin/report + # 如果为false,报表模块的所有Controller中的接口将不能使用。 + operationEnabled: true + # 该配置项仅当打印模板中,打印图片字段时,才会需要。 + # 这里的url配置只是一个示例,并不能保证开箱即用,代码示例和说明可参考common-report模块 + # example包内的ReportExampleController中的代码和详细说明。 + imageDownloadUrl: "http://localhost:8083/tenantadmin/report/example/downloadDirectly" + # 该配置用于报表部分的数据权限过滤功能。 + # 当前数据权限需要获取指定部门Ids的所有下级子部门Ids的时候,会调用该接口。 + dataPermAllChildrenDeptIdUrl: "http://localhost:8083/tenantadmin/upms/sysDept/listAllChildDeptIdByParentIds" + # 当前服务是否为可视化后台服务。 + isVisualization: false + # 下面的url列表,请保持反斜杠(/)结尾。 + viewUrlList: + - ${common-report.urlPrefix}/reportOperation/listData/ + +datasync: + producer: + # upms服务作为生产者,需要打开该选项。 + enabled: true + # Redisson 分布式锁的名称。 + # 当存在多个发送者实例时,需要分布式锁控制只有一个实例可以执行消息流水读取并发送到MQ的操作。 + distributeLockName: tenant-datasync + # 每次读取生产者消息流水的等待时间间隔,单位分钟。 + fetchTransIntervalMins: 2 + # 每次读取生产者消息流水的记录数量。 + fetchCount: 10 + +rocketmq: + name-server: 127.0.0.1:9876 + producer: + group: apelet_saas + +datafilter: + tenant: + enabled: false + dataperm: + enabled: true + # 在拼接数据权限过滤的SQL时,我们会用到sys_dept_relation表,该表的前缀由此配置项指定。 + # 如果没有前缀,请使用 "" 。 + deptRelationTablePrefix: xy_ + # 是否在每次执行数据权限查询过滤时,都要进行菜单Id和URL之间的越权验证。 + enableMenuPermVerify: true + +sequence: + # 是否使用基于美团Leaf的分布式Id生成器。 + advanceIdGenerator: true + # 多个zk服务之间逗号分隔。 + zkAddress: localhost:2181 + # 与本机的ip一起构成zk中标识不同服务实例的key值。 + idPort: 18083 + # zk中生成WorkNode的路径。不同的业务可以使用不同的路径,以免冲突。 + zkPath: apelet + +common-log: + # 操作日志配置,对应配置文件common-log/OperationLogProperties.java + operation-log: + enabled: false + kafkaTopic: SysOperationLog-TenantAdmin + +mybatis-plus: + mapper-locations: classpath:apelet/tenantadmin/tenant/dao/mapper/*Mapper.xml,apelet/tenantadmin/upms/dao/mapper/*Mapper.xml,apelet/common/report/dao/mapper/*Mapper.xml,apelet/common/datasync/dao/mapper/*Mapper.xml,apelet/common/log/dao/mapper/*Mapper.xml,apelet/common/flow/dao/mapper/*Mapper.xml,apelet/common/online/dao/mapper/*Mapper.xml,apelet/common/generator/dao/mapper/*Mapper.xml,apelet/common/botp/dao/mapper/*Mapper.xml,apelet/tenantadmin/app/dao/mapper/*Mapper.xml,apelet/common/mobile/dao/mapper/*Mapper.xml,apelet/common/eas/dao/mapper/*Mapper.xml,classpath:mapper/*Mapper.xml + type-aliases-package: apelet.tenantadmin.*.model,apelet.common.report.model,apelet.common.datasync.model,apelet.common.log.model,apelet.common.flow.model,apelet.common.online.model,apelet.common.mobile.model,apelet.common.eas.model + global-config: + db-config: + logic-delete-value: -1 + logic-not-delete-value: 1 + +# 自动分页的配置 +pagehelper: + helperDialect: mysql + reasonable: true + supportMethodsArguments: false + params: count=countSql + +aj: + captcha: + # 缓存local/redis.. + cache-type: redis + # 验证码类型default两种都实例化。 + type: default + # 右下角水印文字(我的水印) + water-mark: 我的水印 + #点选字体样式 默认Font.BOLD + font-style: 1 + #点选字体字体大小 + font-size: 25 + # 支持项目路径,以classpath:开头,取resource目录下路径,例:classpath:images/jigsaw + jigsaw: classpath:images/jigsaw + # 支持项目路径,以classpath:开头,取resource目录下路径,例:classpath:images/pic-click + pic-click: classpath:images/pic-click + history-data-clear-enable: false + # 接口请求次数一分钟限制是否开启 true|false + req-frequency-limit-enable: false + # 验证失败5次,get接口锁定 + req-get-lock-limit: 5 + # 验证失败后,锁定时间间隔,s + req-get-lock-seconds: 360 + # get接口一分钟内请求数限制 + req-get-minute-limit: 30 + # check接口一分钟内请求数限制 + req-check-minute-limit: 30 + # verify接口一分钟内请求数限制 + req-verify-minute-limit: 60 + # 校验滑动拼图允许误差偏移量(默认5像素) + slip-offset: 5 + # aes加密坐标开启或者禁用(true|false) + aes-status: true + # 滑动干扰项(0/1/2) + interference-options: 2 + +# 开发数据库相关配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + # 租户管理数据源。 + tenant-admin: + url: jdbc:mysql://192.168.100.18:3306/apelet_admin_xk?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + username: root + password: X7&9p8L2@6z4K7!8 + # 租户业务平台的通用业务数据,如字典、在线表单、流程、报表的定义等数据。 + tenant-common: + url: jdbc:mysql://192.168.100.18:3306/apelet_admin_xk?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai + username: root + password: X7&9p8L2@6z4K7!8 + # 默认生成的操作日志数据源配置。 + operation-log: + url: jdbc:mysql://192.168.100.18:3306/apelet_admin_xk?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + username: root + password: X7&9p8L2@6z4K7!8 + driverClassName: com.mysql.cj.jdbc.Driver + name: tenant-admin + initialSize: 10 + minIdle: 10 + maxActive: 50 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + maxOpenPreparedStatements: 20 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + filters: stat,wall + useGlobalDataSourceStat: true + web-stat-filter: + enabled: true + url-pattern: "/*" + exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*,/ai/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true +eas: + config: + easurl: + userName: + password: 1 + dcName: + dbType: 2 + ltpaToken: C:\work\company\project\plat\orm\apelet_saas\common\common-eas\src\main\resources\LtpaToken.properties + #easurl: https://ehr.jztweb.com + #userName: SSQadmin + #password: SSQadmin + #dcName: EHR_001 + #dbType: 2 + #ltpaToken: C:\work\company\project\plat\orm\apelet_saas\common\common-eas\src\main\resources\LtpaToken_zs.properties +hubCloud: + #测试 + #secret: RXmdRE0lf5ngGfLJSSj4 + #appId: 501019058 + secret: + appId: +dingTalk: + secret: 95gAMy_7nWGqRwFbt_kLzRpI9BqKhB7LM3SPgpcvV8Q7s0Az_PMei_yRxWE6LmhV +project: + server: + url: https://jgzy-api.nbjgcloud.com + sync: + url: http://10.22.98.37:9999 + loginUrl: /sys/login + loginName: nbjg + loginPassword: NBjj123456 + userUrl: + projectUrl: +ai: + dify: + baseUrl: + datasetKey: + appKey: + appUrl: + pandoc: + panurl: pandoc + genurl: + templateFileName: sample-orgin-change.docx + luaFileName: parse-html.lua + preUrl: +mineru: + workspace: + batchfile: + timeout: 10000 + baseurl: http://192.168.77.6:8000 + pdfurl: /file_parse + mdSaveDir: /app/work/pdf +cqurl: + config: + url: + gys: + #client_id: xy_mobile + #client_secret: asdasdnsandlkadnlkas!@#@!3WWW + #username: sunquan + client_id: + client_secret: + username: + accountId: + +msg: + notice: + # 是否启用定时消息提醒(true启用,false禁用) + enabled: true + + # 定时任务cron表达式,控制提醒执行频率 + # 默认值:0 0 * * * ? (每小时整点执行) + # 常用示例: + # 0 0 * * * ? - 每小时执行一次 + # 0 0 */2 * * ? - 每2小时执行一次 + # 0 0 9 * * ? - 每天上午9点执行 + # 0 0 9,18 * * ? - 每天上午9点和下午6点执行 + # 0 */30 * * * ? - 每30分钟执行一次 + cron: "0 0 * * * ?" + + # 默认提醒消息内容 + default-message: hello + + # ==================================== + # 短信通知配置 + # ==================================== + sms: + # 是否启用短信通知 + enabled: false + # 短信API地址(根据实际短信服务商配置) + api-url: https://sms.example.com/send + # 短信API密钥 + api-key: your-sms-api-key + # 短信签名 + sign: "【您的签名】" + + # ==================================== + # 邮箱通知配置 + # ==================================== + email: + # 是否启用邮箱通知 + enabled: true + # SMTP服务器地址 + smtp-host: smtp.qq.com + # SMTP端口(25或465或587) + smtp-port: 465 + # 发件人邮箱地址 + from-email: 287962685@qq.com + # 发件人密码或授权码 + password: evccxezdmdnpbhbh + # 是否启用SSL(如果使用465端口,建议启用SSL) + ssl-enabled: true + From 15dd345744c56e880ab9b01e45e73da2ff0d1a04 Mon Sep 17 00:00:00 2001 From: sunquan <287962685@qq.com> Date: Mon, 6 Jul 2026 17:48:08 +0800 Subject: [PATCH 4/9] =?UTF-8?q?fix:=E8=A1=A5=E5=9C=A8=E7=BA=BF=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=8E=A7=E4=BB=B6=E5=92=8C=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/online/util/WidgetFieldTypeMapping.java | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 common/common-online/src/main/java/apelet/common/online/util/WidgetFieldTypeMapping.java diff --git a/common/common-online/src/main/java/apelet/common/online/util/WidgetFieldTypeMapping.java b/common/common-online/src/main/java/apelet/common/online/util/WidgetFieldTypeMapping.java new file mode 100644 index 0000000..50d6801 --- /dev/null +++ b/common/common-online/src/main/java/apelet/common/online/util/WidgetFieldTypeMapping.java @@ -0,0 +1,87 @@ +package apelet.common.online.util; + +import java.util.HashMap; +import java.util.Map; + +public class WidgetFieldTypeMapping { + + private WidgetFieldTypeMapping() { + } + + private static final Map WIDGET_TO_FIELD_TYPE = new HashMap<>(); + private static final Map DEFAULT_LENGTH = new HashMap<>(); + + static { + // 文本输入框 → varchar + WIDGET_TO_FIELD_TYPE.put(1, "0"); + DEFAULT_LENGTH.put(1, 255); + // 数字输入框 → int + WIDGET_TO_FIELD_TYPE.put(3, "1"); + // 开关组件 → int + WIDGET_TO_FIELD_TYPE.put(5, "1"); + // 滑块组件 → decimal + WIDGET_TO_FIELD_TYPE.put(6, "4"); + // 单选组件 → varchar + WIDGET_TO_FIELD_TYPE.put(7, "0"); + DEFAULT_LENGTH.put(7, 255); + // 复选框 → varchar + WIDGET_TO_FIELD_TYPE.put(8, "0"); + DEFAULT_LENGTH.put(8, 255); + // 下拉选择框 → varchar + WIDGET_TO_FIELD_TYPE.put(10, "0"); + DEFAULT_LENGTH.put(10, 255); + // 级联选择框 → varchar + WIDGET_TO_FIELD_TYPE.put(12, "0"); + DEFAULT_LENGTH.put(12, 255); + // 树形选择 → varchar + WIDGET_TO_FIELD_TYPE.put(13, "0"); + DEFAULT_LENGTH.put(13, 255); + // 评分组件 → int + WIDGET_TO_FIELD_TYPE.put(14, "1"); + DEFAULT_LENGTH.put(14, 5); + // 日期选择框 → datetime + WIDGET_TO_FIELD_TYPE.put(20, "3"); + // 颜色选择 → varchar + WIDGET_TO_FIELD_TYPE.put(30, "0"); + DEFAULT_LENGTH.put(30, 50); + // 附件上传 → varchar + WIDGET_TO_FIELD_TYPE.put(31, "0"); + DEFAULT_LENGTH.put(31, 255); + // 图片上传 → varchar + WIDGET_TO_FIELD_TYPE.put(653, "0"); + DEFAULT_LENGTH.put(653, 255); + // 富文本编辑 → varchar(2000) + WIDGET_TO_FIELD_TYPE.put(32, "0"); + DEFAULT_LENGTH.put(32, 2000); + // MD编辑器 → varchar(2000) + WIDGET_TO_FIELD_TYPE.put(760, "0"); + DEFAULT_LENGTH.put(760, 2000); + // 用户选择 → bigint + WIDGET_TO_FIELD_TYPE.put(400, "2"); + // 部门选择 → bigint + WIDGET_TO_FIELD_TYPE.put(401, "2"); + // 关联选择 → bigint + WIDGET_TO_FIELD_TYPE.put(402, "2"); + // 时间选择器 → datetime + WIDGET_TO_FIELD_TYPE.put(652, "3"); + // 文件上传 → varchar + WIDGET_TO_FIELD_TYPE.put(750, "0"); + DEFAULT_LENGTH.put(750, 255); + } + + public static String getFieldTypeId(Integer widgetType) { + String type = WIDGET_TO_FIELD_TYPE.get(widgetType); + if (type == null) { + throw new IllegalArgumentException("不支持的控件类型: " + widgetType); + } + return type; + } + + public static Integer getDefaultLength(Integer widgetType) { + return DEFAULT_LENGTH.get(widgetType); + } + + public static boolean isDataWidget(Integer widgetType) { + return WIDGET_TO_FIELD_TYPE.containsKey(widgetType); + } +} From f4051135527852fedb2f480ca9e938bf7320f12f Mon Sep 17 00:00:00 2001 From: chenchuchuan <13554600537@163.com> Date: Tue, 7 Jul 2026 15:55:04 +0800 Subject: [PATCH 5/9] =?UTF-8?q?fix(controller):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E9=A1=B5=E9=9D=A2=E6=8E=A7=E5=88=B6=E5=99=A8?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改OnlinePageController的add方法返回类型从Long改为OnlinePage - 移除不必要的masterTableId变量声明 - 修复TenantOnlinePageController继承类的返回类型一致性 - 添加OnlinePage模型导入到TenantOnlinePageController - 统一两个控制器的返回值结构为完整的OnlinePage对象 --- .../apelet/common/online/controller/OnlinePageController.java | 8 +++----- .../tenant/online/controller/TenantOnlinePageController.java | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java index 0fd5efa..ea304d8 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java @@ -85,7 +85,7 @@ public class OnlinePageController { @OperationLog(type = SysOperationLogType.ADD) @Transactional(rollbackFor = Exception.class) @PostMapping("/add") - public ResponseResult add(@MyRequestBody OnlinePageDto onlinePageDto) { + public ResponseResult add(@MyRequestBody OnlinePageDto onlinePageDto) { String errorMessage = MyCommonUtil.getModelValidationError(onlinePageDto); if (errorMessage != null) { return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); @@ -115,7 +115,6 @@ public class OnlinePageController { return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, errorMessage); } - Long masterTableId; OnlFormHead onlFormHead; if ("new".equals(metaSource)) { @@ -125,7 +124,7 @@ public class OnlinePageController { String tableTxt = onlinePageDto.getPageName(); onlFormHead = iOnlFormHeadService.createMetaAndSync(tableName, tableTxt, metaType, null); - masterTableId = onlFormHead.getId(); + Long masterTableId = onlFormHead.getId(); onlinePage.setMasterTableId(String.valueOf(masterTableId)); onlinePage.setMasterTableName(onlFormHead.getTableName()); @@ -138,7 +137,6 @@ public class OnlinePageController { // === Existing branch: use existing metadata === String formMetadata = onlinePageDto.getMasterTableId(); onlFormHead = iOnlFormHeadService.getById(formMetadata); - masterTableId = Long.valueOf(formMetadata); } try { @@ -179,7 +177,7 @@ public class OnlinePageController { */ addOnlineDatasourceRelation(onlFormHead, onlineDatasource, errorMessage, onlineDblink); - return ResponseResult.success(onlinePage.getPageId()); + return ResponseResult.success(onlinePage); } diff --git a/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlinePageController.java b/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlinePageController.java index dfce3fb..d6021f7 100644 --- a/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlinePageController.java +++ b/common/common-tenant-online/src/main/java/apelet/common/tenant/online/controller/TenantOnlinePageController.java @@ -8,6 +8,7 @@ import apelet.common.online.controller.OnlinePageController; import apelet.common.online.dto.OnlineDatasourceDto; import apelet.common.online.dto.OnlinePageDatasourceDto; import apelet.common.online.dto.OnlinePageDto; +import apelet.common.online.model.OnlinePage; import apelet.common.online.vo.OnlineDatasourceVo; import apelet.common.online.vo.OnlinePageDatasourceVo; import apelet.common.online.vo.OnlinePageVo; @@ -43,7 +44,7 @@ public class TenantOnlinePageController extends OnlinePageController { @OperationLog(type = SysOperationLogType.ADD) @PostMapping("/add") @Override - public ResponseResult add(@MyRequestBody OnlinePageDto onlinePageDto) { + public ResponseResult add(@MyRequestBody OnlinePageDto onlinePageDto) { return super.add(onlinePageDto); } From 7dcb3bb5c9d8bafd182f277ffa5e1089f0f75702 Mon Sep 17 00:00:00 2001 From: chenchuchuan <13554600537@163.com> Date: Tue, 7 Jul 2026 16:48:59 +0800 Subject: [PATCH 6/9] =?UTF-8?q?refactor(online):=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=B8=B8=E9=87=8F=E6=9B=BF=E6=8D=A2=E7=A1=AC=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E7=9A=84=E5=85=83=E6=95=B0=E6=8D=AE=E6=BA=90=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apelet/common/online/controller/OnlinePageController.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java index ea304d8..1d928ae 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java @@ -75,6 +75,10 @@ public class OnlinePageController { @Autowired private IOnlFormFieldService onlFormFieldService; + //new=新建元数据,exist=现有元数据 + private static final String META_SOURCE_NEW = "new"; + private static final String META_SOURCE_EXIST = "exist"; + /** * 新增在线表单页面数据。 * @@ -92,7 +96,7 @@ public class OnlinePageController { } // Validate based on metaSource String metaSource = onlinePageDto.getMetaSource(); - if ("new".equals(metaSource)) { + if (META_SOURCE_NEW.equals(metaSource)) { // New metadata flow: metaType and pageCode are required if (StrUtil.isEmpty(onlinePageDto.getMetaType())) { errorMessage = "数据验证失败,新建元数据时表类型(metaType)不能为空!"; @@ -117,7 +121,7 @@ public class OnlinePageController { OnlFormHead onlFormHead; - if ("new".equals(metaSource)) { + if (META_SOURCE_NEW.equals(metaSource)) { // === New branch: create fresh metadata === String metaType = onlinePageDto.getMetaType(); String tableName = onlinePageDto.getPageCode(); From e9c3b36512c7691f0de5a61182bb2f80d019277a Mon Sep 17 00:00:00 2001 From: chenchuchuan <13554600537@163.com> Date: Wed, 8 Jul 2026 14:39:38 +0800 Subject: [PATCH 7/9] =?UTF-8?q?feat(online):=20=E6=B7=BB=E5=8A=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=A1=A8=E5=AD=97=E6=AE=B5=E4=BF=9D=E5=AD=98=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 saveBySqlTable 方法用于保存新增数据表字段 - 添加字段注释逻辑处理,支持传入字段描述并设置默认值 - 集成 StringUtil 工具类进行字符串判空和比较操作 - 重构 OnlineFormController 中的字段创建逻辑,使用新方法替代原有实现 - 优化字段回填 columnId 到 widgetJson 的处理流程 --- .../online/controller/OnlineFormController.java | 14 ++----------- .../common/online/service/OnlineColumnService.java | 10 ++++++++++ .../service/impl/OnlineColumnServiceImpl.java | 23 ++++++++++++++++++++++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java index d075054..d64b2f6 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java @@ -793,23 +793,13 @@ public class OnlineFormController { for (String fieldName : validColumnNames) { SqlTableColumn sqlCol = columnMap.get(fieldName.toLowerCase()); if (sqlCol != null) { - OnlineColumn newCol = new OnlineColumn(); - newCol.setColumnName(sqlCol.getColumnName()); - newCol.setColumnType(sqlCol.getColumnType()); - newCol.setFullColumnType(sqlCol.getFullColumnType()); - if (sqlCol.getColumnDefault() != null) { - newCol.setColumnDefault(sqlCol.getColumnDefault().toString()); - } - newCol.setNullable(sqlCol.getNullable()); - newCol.setTableId(onlineTable.getTableId()); - onlineColumnService.save(newCol); - // 回填 columnId 到 widgetJson JSONObject widget = nameToWidget.get(fieldName); + long columnId = onlineColumnService.saveBySqlTable(sqlCol, onlineTable.getTableId(), widget.getString("showName")); if (widget != null) { JSONObject bindData2 = widget.getJSONObject("bindData"); if (bindData2 != null) { - bindData2.put("columnId", newCol.getColumnId()); + bindData2.put("columnId", columnId); bindData2.put("tableId", onlineTable.getTableId()); } } diff --git a/common/common-online/src/main/java/apelet/common/online/service/OnlineColumnService.java b/common/common-online/src/main/java/apelet/common/online/service/OnlineColumnService.java index 983a086..4832343 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/OnlineColumnService.java +++ b/common/common-online/src/main/java/apelet/common/online/service/OnlineColumnService.java @@ -27,6 +27,16 @@ public interface OnlineColumnService extends IBaseService { List saveNewList(List columnList, Long onlineTableId); /** + * 保存新增数据表字段。 + * + * @param sqlTableColumn 新增数据表字段对象。 + * @param tableId 在线表对象的主键Id。 + * @param columnComment 字段名。 + * @return 插入的在线表字段数据。 + */ + long saveBySqlTable(SqlTableColumn sqlTableColumn, Long tableId, String columnComment); + + /** * 更新数据对象。 * * @param onlineColumn 更新的对象。 diff --git a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java index c66e247..15c7a3c 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java +++ b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java @@ -31,6 +31,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.github.pagehelper.Page; import com.google.common.base.CaseFormat; +import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; @@ -106,6 +107,28 @@ public class OnlineColumnServiceImpl extends BaseService imp return onlineColumnList; } + + @Override + public long saveBySqlTable(SqlTableColumn sqlTableColumn, Long tableId, String columnComment) { + OnlineColumn onlineColumn = new OnlineColumn(); + BeanUtil.copyProperties(sqlTableColumn, onlineColumn, false); + onlineColumn.setColumnId(idGenerator.nextLongId()); + onlineColumn.setTableId(tableId); + // 传了描述,并且不等于原先的描述,并且原先的为空或者为"null",就赋值 + if (StringUtil.isNotBlank(columnComment) && !StringUtil.equals(columnComment, onlineColumn.getColumnComment()) + && (StringUtil.isBlank(onlineColumn.getColumnComment()) || StringUtil.equals("null", onlineColumn.getColumnComment()))) { + onlineColumn.setColumnComment(columnComment); + } + if (StringUtil.isBlank(onlineColumn.getColumnComment())) { + onlineColumn.setColumnComment(onlineColumn.getColumnName()); + } + this.setDefault(sqlTableColumn, onlineColumn); + if (super.save(onlineColumn)) { + return onlineColumn.getColumnId(); + } + return 0; + } + /** * 更新数据对象。 * From 6fc400ab7731423edaaf3d86c17c46c1b1b5ace3 Mon Sep 17 00:00:00 2001 From: chenchuchuan <13554600537@163.com> Date: Wed, 8 Jul 2026 15:31:31 +0800 Subject: [PATCH 8/9] =?UTF-8?q?feat(online):=20=E8=A1=A8=E5=8D=95=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E4=BF=9D=E5=AD=98=E6=97=B6=EF=BC=8C=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=A4=87=E6=B3=A8=E5=8F=96=E5=80=BC=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apelet/common/online/controller/OnlineFormController.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java index d64b2f6..1f622cb 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java @@ -17,15 +17,15 @@ import apelet.common.generator.model.OnlFormHead; import apelet.common.generator.service.IOnlFormFieldService; import apelet.common.generator.service.IOnlFormHeadService; import apelet.common.generator.utils.CustomUtil; -import apelet.common.online.util.WidgetFieldTypeMapping; import apelet.common.log.annotation.OperationLog; import apelet.common.log.model.constant.SysOperationLogType; import apelet.common.online.config.OnlineProperties; -import apelet.common.online.dto.*; import apelet.common.online.dto.OnlineEventPluginExecuteDto; +import apelet.common.online.dto.OnlineFormDto; import apelet.common.online.model.*; import apelet.common.online.service.*; import apelet.common.online.util.OnlineRedisKeyUtil; +import apelet.common.online.util.WidgetFieldTypeMapping; import apelet.common.online.vo.OnlineFormVo; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; @@ -51,7 +51,6 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.groups.Default; -import java.lang.reflect.Method; import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -771,6 +770,10 @@ public class OnlineFormController { if (bindData != null && bindData.containsKey("columnComment")) { field.setFieldRemark(bindData.getString("columnComment")); } + String showName = widget.getString("showName"); + if (StringUtils.isNotBlank(showName) && (StringUtils.isBlank(field.getFieldRemark()) || StringUtils.equals("null", field.getFieldRemark()))) { + field.setFieldRemark(showName); + } onlFormFieldService.save(field); } From 3104f1b0267d56f778a050acd53ffc52ed174499 Mon Sep 17 00:00:00 2001 From: chenchuchuan <13554600537@163.com> Date: Fri, 10 Jul 2026 17:49:27 +0800 Subject: [PATCH 9/9] =?UTF-8?q?refactor(common-generator):=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=9C=A8=E7=BA=BF=E8=A1=A8=E5=8D=95=E5=A4=B4=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在OnlFormHeadServiceImpl中设置sortFiled为parent_id - 重构OnlineColumnServiceImpl中的包导入 - 在OnlineColumnServiceImpl中将列名转换为小写存储 - 扩展OnlineDatasourceRelationService接口定义 - 实现完整的OnlineDatasourceRelationServiceImpl业务逻辑 - 在OnlineDatasourceServiceImpl中设置数据源名称 - 重构OnlineFormController中的字段保存逻辑 - 优化OnlineFormController中的子表处理流程 - 更新OnlinePageController中表名生成规则为小写前缀格式 - 添加必要的依赖注入和缓存清理操作 --- .../service/impl/OnlFormHeadServiceImpl.java | 1 + .../online/controller/OnlineFormController.java | 323 +++++++++++++++------ .../online/controller/OnlinePageController.java | 16 +- .../service/OnlineDatasourceRelationService.java | 17 ++ .../service/impl/OnlineColumnServiceImpl.java | 6 +- .../impl/OnlineDatasourceRelationServiceImpl.java | 218 ++++++++++++++ .../service/impl/OnlineDatasourceServiceImpl.java | 6 +- 7 files changed, 484 insertions(+), 103 deletions(-) diff --git a/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java b/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java index a6915a5..bb63a20 100644 --- a/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java +++ b/common/common-generator/src/main/java/apelet/common/generator/service/impl/OnlFormHeadServiceImpl.java @@ -1673,6 +1673,7 @@ public class OnlFormHeadServiceImpl extends ServiceImpl widgetSubTables = collectSubTableNames(widgetJson); - List existingSubTables = onlFormHeadService.list( - new LambdaQueryWrapper() - .eq(OnlFormHead::getSort, onlFormHead.getTableName()) - .eq(OnlFormHead::getLine, 1)); - Set existingSubTableNames = existingSubTables.stream() - .map(OnlFormHead::getTableName).collect(Collectors.toSet()); - Set newSubTableNames = new HashSet<>(widgetSubTables); - newSubTableNames.removeAll(existingSubTableNames); - - if (!newSubTableNames.isEmpty()) { - // 获取主表的主键字段(id)作为关联字段 - OnlineColumn masterPkColumn = onlineColumnService.getOne( - new LambdaQueryWrapper() - .eq(OnlineColumn::getTableId, onlineTable.getTableId()) - .eq(OnlineColumn::getColumnName, "id")); - - for (String subTableName : newSubTableNames) { - OnlFormHead subHead = onlFormHeadService.createMetaAndSync( - subTableName, - onlFormHead.getTableTxt() + "附表", - CustomUtil.MetaType_Entry, - onlFormHead.getTableName()); - - // 获取子表的 OnlineTable - OnlineTable subOnlineTable = onlineTableService.getOne( - new LambdaQueryWrapper() - .eq(OnlineTable::getTableName, subTableName.toLowerCase())); - if (subOnlineTable == null) { - // 从DB获取表结构并创建 OnlineTable - SqlTable subSqlTable = onlineDblinkService.getDblinkTable( - onlineDblinkService.getById(datasource.getDblinkId()), subTableName); - if (subSqlTable != null) { - subOnlineTable = onlineTableService.saveNewFromSqlTable(subSqlTable); - } - } + // 取 widgetList->bindData -> tableId 在去 zz_online_table 查询,这样就可以判断哪些是新增,哪些是 已有的表 + // 如果存在附表 + Map tableIdAndPropMap = collectSubTableAndPropMap(widgetJson); - // 创建子表数据源 - OnlineDatasource subDatasource = new OnlineDatasource(); - subDatasource.setDblinkId(datasource.getDblinkId()); - if (subOnlineTable != null) { - subDatasource.setMasterTableId(subOnlineTable.getTableId()); - } - onlineDatasourceService.save(subDatasource); - - // 创建 1:N 关系 - OnlineDatasourceRelation relation = new OnlineDatasourceRelation(); - relation.setDatasourceId(datasource.getDatasourceId()); - relation.setRelationType(1); - if (subOnlineTable != null) { - relation.setSlaveTableId(subOnlineTable.getTableId()); + if (MapUtil.isNotEmpty(tableIdAndPropMap)) { + //搜集的所有tableId, 要么是 tableId(已存在),要么是 tableName(不存在) + Set allTableIdSet = tableIdAndPropMap.keySet(); + Set newSubTableNames = new HashSet<>(); + Set existingSubTableIdSet = new HashSet<>(); + for (String tableId : allTableIdSet) { + if (tableId.matches("\\d+")) { + existingSubTableIdSet.add(Long.parseLong(tableId)); + } else { + newSubTableNames.add(tableId); } - if (masterPkColumn != null) { - relation.setMasterColumnId(masterPkColumn.getColumnId()); + } + //分两步, + //step1 : 看看存在的附表,是否存在不存在的字段 + if (!existingSubTableIdSet.isEmpty()) { + // 拿到tableId 下面的所有字段,先查询 zz_online_table ,在根据 tableName 查询 onl_form_head 表 + List tableList = onlineTableService.listByIds(existingSubTableIdSet); + Map tableIdAndNameMap = tableList.stream().collect(Collectors.toMap(OnlineTable::getTableId, OnlineTable::getTableName)); + List tableNames = tableList.stream().map(OnlineTable::getTableName).collect(Collectors.toList()); + List onlFormHeadList = onlFormHeadService.list(new LambdaQueryWrapper().in(OnlFormHead::getTableName, tableNames)); + Map tableNameAndHeadIdMap = onlFormHeadList.stream().collect(Collectors.toMap(OnlFormHead::getTableName, Function.identity())); + //因为这里是zz_online_column.column_id 的id和 列名的混合,我只要列名 + Map nameToWidget = mapColumnIdAndWidget(widgetJson); + Set newSubColumnNameSet = nameToWidget.keySet().stream().filter(s -> !s.matches("\\d+")).collect(Collectors.toSet()); + //这里要走 新增逻辑 + if (!newSubColumnNameSet.isEmpty()) { + // ALTER TABLE ADD COLUMN, 这里取第一个就行,因为绑定的是一个表 + JSONObject columnInfo = nameToWidget.values().iterator().next(); + Long tableId = columnInfo.getLong("tableId"); + String tableName = tableIdAndNameMap.get(tableId); + OnlFormHead entryHead = tableNameAndHeadIdMap.get(tableName); + for (String newSubColumnName : newSubColumnNameSet) { + //这里取出来的结构是 widgetList -》 props -》 tableColumnList + JSONObject columnInfoJson = nameToWidget.get(newSubColumnName); + //step 1 : 先保存 field 表 + String showName = columnInfoJson.getString("showName"); + // 默认是字符串类型 + this.saveField(750, showName, null, entryHead, newSubColumnName); + } + onlFormHeadService.syncDB(entryHead, 0L); + //step 2 :在保存 OnlineColumn 表 + OnlineDblink dblink = onlineDblinkService.getById(datasource.getDblinkId()); + List allColumns = onlineDblinkService.getDblinkTableColumnList(dblink, tableName); + Map columnMap = new HashMap<>(); + if (CollUtil.isNotEmpty(allColumns)) { + columnMap = allColumns.stream().collect(Collectors.toMap(SqlTableColumn::getColumnName, Function.identity())); + } + for (String fieldName : newSubColumnNameSet) { + SqlTableColumn sqlCol = columnMap.get(fieldName.toLowerCase()); + if (sqlCol != null) { + // 回填 columnId 到 widgetJson + JSONObject widget = nameToWidget.get(fieldName); + String showName = widget == null ? null : widget.getString("showName"); + long columnId = onlineColumnService.saveBySqlTable(sqlCol, tableId, showName); + if (widget != null) { + //step 3 :回填 columnId + showFieldName 到 json里面去 + widget.put("columnId", columnId); + widget.put("showFieldName", fieldName); + } + } + } + //step 4 :删除缓存 + redissonClient.getBucket(OnlineRedisKeyUtil.makeOnlineTableKey(tableId)).delete(); + redissonClient.getBucket(CacheKey.makeTableKey(tableName)).delete(); + redissonClient.getBucket(CacheKey.makeChildFieldListKey(entryHead.getId())).delete(); + metaCacheService.removeData(tableName); + changed = true; } - onlineDatasourceRelationService.save(relation); + } + //step2 : 不存在的附表,新增 + if (newSubTableNames.isEmpty()) { + //如果他为空,说明我们走tableId取值没取到,我们就去一下 tableName; + newSubTableNames = this.collectSubTableName(widgetJson); + } + if (!newSubTableNames.isEmpty()) { + + for (String subTableName : newSubTableNames) { + OnlFormHead subHead = onlFormHeadService.createMetaAndSync(subTableName, onlFormHead.getTableTxt() + "附表", CustomUtil.MetaType_Entry, onlFormHead.getTableName()); + // 获取子表的 OnlineTable + OnlineTable subOnlineTable = onlineTableService.getOne(new LambdaQueryWrapper().eq(OnlineTable::getTableName, subTableName.toLowerCase())); + if (subOnlineTable == null) { + // 从DB获取表结构并创建 OnlineTable + SqlTable subSqlTable = onlineDblinkService.getDblinkTable(onlineDblinkService.getById(datasource.getDblinkId()), subTableName); + if (subSqlTable != null) { + subOnlineTable = onlineTableService.saveNewFromSqlTable(subSqlTable); + } + } + OnlineDblink dblink = onlineDblinkService.getById(datasource.getDblinkId()); + onlineDatasourceRelationService.addOnlineDatasourceRelation(onlFormHead, datasource, null, dblink); - backfillRelationId(widgetJson, subTableName, relation.getRelationId()); + if (subOnlineTable != null) { + backfillRelationId(widgetJson, subTableName, subOnlineTable.getTableId()); + } + } + changed = true; } - changed = true; } - return changed ? widgetJson : null; } + + private void saveField(Integer widgetType, String columnComment, String showName, OnlFormHead onlFormHead, String fieldName) { + OnlFormField field = new OnlFormField(); + field.setHeadId(onlFormHead.getId()); + field.setFieldName(fieldName); + field.setFieldType(WidgetFieldTypeMapping.getFieldTypeId(widgetType)); + Integer length = WidgetFieldTypeMapping.getDefaultLength(widgetType); + if (length != null) { + field.setFieldLength(length); + } + field.setIsEmpty(1); + field.setIsDefault(0); + field.setRowDisabled(0); + field.setSyncFlag(0); + + // 从 widget 的 bindData.columnComment 设置字段备注 + field.setFieldRemark(columnComment); + if (StringUtils.isNotBlank(showName) && (StringUtils.isBlank(field.getFieldRemark()) || StringUtils.equals("null", field.getFieldRemark()))) { + field.setFieldRemark(showName); + } + onlFormFieldService.save(field); + } + /** * 遍历 pc/mobile 的 widget 树,收集所有 bindData.columnName 值。 */ @@ -895,22 +946,66 @@ public class OnlineFormController { } /** - * 遍历 pc/mobile 的 widget 树,收集 widgetType=403 (TableContainer) 的 props.tableName 值。 + * 遍历 pc/mobile 的 widget 树,收集 widgetType=100 (TableContainer) 的 bindData 下的 tableId */ - private Set collectSubTableNames(JSONObject widgetJson) { - Set names = new HashSet<>(); + private Map collectSubTableAndPropMap(JSONObject widgetJson) { + Map resultMap = new HashMap<>(); walkAllModes(widgetJson, widget -> { - if (widget.getInteger("widgetType") != null && 403 == widget.getInteger("widgetType")) { - JSONObject props = widget.getJSONObject("props"); - if (props != null && props.containsKey("tableName")) { - String tn = props.getString("tableName"); - if (StrUtil.isNotEmpty(tn)) { - names.add(tn); + JSONArray widgetList = widget.getJSONArray("widgetList"); + if (widgetList != null) { + for (int i = 0; i < widgetList.size(); i++) { + JSONObject childWidget = widgetList.getJSONObject(i); + // 只处理widgetType为100的子表 + Integer widgetType = childWidget.getInteger("widgetType"); + if (widgetType == null || widgetType != 100) { + continue; + } + + JSONObject bindData = childWidget.getJSONObject("bindData"); + if (bindData == null) { + continue; + } + + String tableId = bindData.getString("tableId"); + if (StrUtil.isBlank(tableId)) { + continue; + } + + JSONObject props = childWidget.getJSONObject("props"); + if (props != null) { + resultMap.put(tableId, props); } } } }); - return names; + return resultMap; + } + + private Set collectSubTableName(JSONObject widgetJson) { + Set tableNameSet = new HashSet<>(); + walkAllModes(widgetJson, widget -> { + JSONArray widgetList = widget.getJSONArray("widgetList"); + if (widgetList != null) { + for (int i = 0; i < widgetList.size(); i++) { + JSONObject childWidget = widgetList.getJSONObject(i); + // 只处理widgetType为100的子表 + Integer widgetType = childWidget.getInteger("widgetType"); + if (widgetType == null || widgetType != 100) { + continue; + } + + JSONObject bindData = childWidget.getJSONObject("bindData"); + if (bindData == null) { + continue; + } + + if (bindData.containsKey("tableName")) { + tableNameSet.add(bindData.getString("tableName")); + } + } + } + }); + return tableNameSet; } /** @@ -930,15 +1025,53 @@ public class OnlineFormController { return map; } + private Map mapColumnIdAndWidget(JSONObject widgetJson) { + Map resultMap = new HashMap<>(); + walkAllModes(widgetJson, widget -> { + JSONArray widgetList = widget.getJSONArray("widgetList"); + if (widgetList != null) { + for (int i = 0; i < widgetList.size(); i++) { + JSONObject childWidget = widgetList.getJSONObject(i); + // 只处理widgetType为100的子表 + Integer widgetType = childWidget.getInteger("widgetType"); + if (widgetType == null || widgetType != 100) { + continue; + } + + JSONObject bindData = childWidget.getJSONObject("bindData"); + if (bindData == null) { + continue; + } + + String tableId = bindData.getString("tableId"); + if (StrUtil.isBlank(tableId)) { + continue; + } + + JSONObject props = childWidget.getJSONObject("props"); + if (props == null) { + continue; + } + JSONArray tableColumnList = props.getJSONArray("tableColumnList"); + for (int j = 0; j < tableColumnList.size(); j++) { + JSONObject tableColumn = tableColumnList.getJSONObject(j); + resultMap.put(tableColumn.getString("columnId"), tableColumn); + } + + } + } + }); + return resultMap; + } /** - * 在 widgetJson 中查找匹配 tableName 的 TableContainer 控件,回填 relationId。 + * 在 widgetJson 中查找匹配 tableName 的 TableContainer 控件,回填 tableId。 */ - private void backfillRelationId(JSONObject widgetJson, String tableName, Long relationId) { + private void backfillRelationId(JSONObject widgetJson, String tableName, Long tableId) { walkAllModes(widgetJson, widget -> { - if (widget.getInteger("widgetType") != null && 403 == widget.getInteger("widgetType")) { - JSONObject props = widget.getJSONObject("props"); + if (widget.getInteger("widgetType") != null && 100 == widget.getInteger("widgetType")) { + JSONObject props = widget.getJSONObject("bindData"); if (props != null && tableName.equals(props.getString("tableName"))) { - props.put("relationId", relationId); + props.put("tableId", tableId); } } }); diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java index 1d928ae..8d137a7 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlinePageController.java @@ -16,7 +16,10 @@ import apelet.common.generator.service.IOnlFormHeadService; import apelet.common.generator.utils.CustomUtil; import apelet.common.log.annotation.OperationLog; import apelet.common.log.model.constant.SysOperationLogType; -import apelet.common.online.dto.*; +import apelet.common.online.dto.OnlineDatasourceDto; +import apelet.common.online.dto.OnlineDatasourceRelationDto; +import apelet.common.online.dto.OnlinePageDatasourceDto; +import apelet.common.online.dto.OnlinePageDto; import apelet.common.online.model.*; import apelet.common.online.model.constant.PageStatus; import apelet.common.online.service.*; @@ -124,7 +127,7 @@ public class OnlinePageController { if (META_SOURCE_NEW.equals(metaSource)) { // === New branch: create fresh metadata === String metaType = onlinePageDto.getMetaType(); - String tableName = onlinePageDto.getPageCode(); + String tableName = "t_" + onlinePageDto.getPageCode().toLowerCase(); String tableTxt = onlinePageDto.getPageName(); onlFormHead = iOnlFormHeadService.createMetaAndSync(tableName, tableTxt, metaType, null); @@ -179,16 +182,17 @@ public class OnlinePageController { * 创建数据表关联关系 先查出改元数据表的所有附表关系 * 一对多 */ - addOnlineDatasourceRelation(onlFormHead, onlineDatasource, errorMessage, onlineDblink); - + onlineDatasourceRelationService.addOnlineDatasourceRelation(onlFormHead, onlineDatasource, errorMessage, onlineDblink); + return ResponseResult.success(onlinePage); } /** *创建数据表关联关系 先查出改元数据表的所有附表关系 - * + * 方法迁移☞ onlineDatasourceRelationService.addOnlineDatasourceRelation */ + @Deprecated public ResponseResult addOnlineDatasourceRelation(OnlFormHead onlFormHead, OnlineDatasource onlineDatasource, String errorMessage, OnlineDblink onlineDblink) { //历史数据 --做比较新数据写入,已存在的不用管,不存在的删除 OnlineDatasourceRelation onlineDatasourceRelations = new OnlineDatasourceRelation(); @@ -442,7 +446,7 @@ public class OnlinePageController { onlineColumnService.saveNewList(sqlTableColumnList, onlineDatasourceList.get(0).getMasterTableId()); //写表关联关系 --一对多,一对一 onlineDatasourceService.getOnlineDatasourceListByPageId(onlinePageDto.getPageId(), null, null); - addOnlineDatasourceRelation(onlFormHeadList.get(0), onlineDatasourceList.get(0), errorMessage, onlineDblink); + onlineDatasourceRelationService.addOnlineDatasourceRelation(onlFormHeadList.get(0), onlineDatasourceList.get(0), errorMessage, onlineDblink); ArrayList onlineColumns = new ArrayList<>(); List filedByHeadIdCache = onlFormFieldService.getFiledByHeadIdCache(onlFormHeadList.get(0).getId()); diff --git a/common/common-online/src/main/java/apelet/common/online/service/OnlineDatasourceRelationService.java b/common/common-online/src/main/java/apelet/common/online/service/OnlineDatasourceRelationService.java index afd9931..8a5afe9 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/OnlineDatasourceRelationService.java +++ b/common/common-online/src/main/java/apelet/common/online/service/OnlineDatasourceRelationService.java @@ -1,9 +1,13 @@ package apelet.common.online.service; import apelet.common.core.base.service.IBaseService; +import apelet.common.core.object.ResponseResult; import apelet.common.dbutil.object.SqlTable; import apelet.common.dbutil.object.SqlTableColumn; +import apelet.common.generator.model.OnlFormHead; +import apelet.common.online.model.OnlineDatasource; import apelet.common.online.model.OnlineDatasourceRelation; +import apelet.common.online.model.OnlineDblink; import java.util.List; import java.util.Set; @@ -82,4 +86,17 @@ public interface OnlineDatasourceRelationService extends IBaseService getOnlineDatasourceRelationListWithRelation( OnlineDatasourceRelation filter, String orderBy); + + /*** + * 功能: 迁移 OnlinePageController#addOnlineDatasourceRelation(OnlFormHead, OnlineDatasource, String, OnlineDblink) + * 方法,创建数据表关联关系 先查出改元数据表的所有附表关系 + * + * @author ${chenchuchuan} + * @param onlFormHead 主表信息 + * @param onlineDatasource 数据库链接配置 + * @param errorMessage 错误描述 + * @param onlineDblink 数据库实际链接 + * @return ResponseResult + */ + ResponseResult addOnlineDatasourceRelation(OnlFormHead onlFormHead, OnlineDatasource onlineDatasource, String errorMessage, OnlineDblink onlineDblink); } diff --git a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java index 15c7a3c..2756598 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java +++ b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineColumnServiceImpl.java @@ -38,7 +38,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; /** * 字段数据数据操作服务类。 @@ -124,6 +127,7 @@ public class OnlineColumnServiceImpl extends BaseService imp } this.setDefault(sqlTableColumn, onlineColumn); if (super.save(onlineColumn)) { + sqlTableColumn.setColumnName(onlineColumn.getColumnName().toLowerCase()); return onlineColumn.getColumnId(); } return 0; diff --git a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java index 7dd4f38..799d821 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java +++ b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java @@ -4,21 +4,31 @@ import apelet.common.core.annotation.MyDataSourceResolver; import apelet.common.core.base.dao.BaseDaoMapper; import apelet.common.core.base.service.BaseService; import apelet.common.core.constant.ApplicationConstant; +import apelet.common.core.constant.ErrorCodeEnum; import apelet.common.core.object.CallResult; import apelet.common.core.object.MyRelationParam; +import apelet.common.core.object.ResponseResult; import apelet.common.core.object.TokenData; import apelet.common.core.util.DefaultDataSourceResolver; +import apelet.common.core.util.MyModelUtil; import apelet.common.dbutil.object.SqlTable; import apelet.common.dbutil.object.SqlTableColumn; +import apelet.common.generator.model.OnlFormField; +import apelet.common.generator.model.OnlFormHead; +import apelet.common.generator.service.IOnlFormFieldService; +import apelet.common.generator.service.IOnlFormHeadService; import apelet.common.online.dao.OnlineDatasourceRelationMapper; import apelet.common.online.dao.OnlineDatasourceTableMapper; +import apelet.common.online.dto.OnlineDatasourceRelationDto; import apelet.common.online.model.*; import apelet.common.online.service.*; import apelet.common.online.util.OnlineRedisKeyUtil; import apelet.common.redis.util.CommonRedisUtil; import apelet.common.sequence.wrapper.IdGeneratorWrapper; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.github.pagehelper.Page; @@ -30,6 +40,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.stream.Collectors; /** * 数据源关联数据操作服务类。 @@ -61,6 +72,14 @@ public class OnlineDatasourceRelationServiceImpl private RedissonClient redissonClient; @Autowired private CommonRedisUtil commonRedisUtil; + @Autowired + private OnlineDblinkService onlineDblinkService; + @Autowired + private IOnlFormHeadService iOnlFormHeadService; + @Autowired + private OnlineDatasourceRelationService onlineDatasourceRelationService; + @Autowired + private IOnlFormFieldService onlFormFieldService; /** * 返回当前Service的主表Mapper对象。 @@ -289,4 +308,203 @@ public class OnlineDatasourceRelationServiceImpl } return CallResult.ok(); } + + @Override + public ResponseResult addOnlineDatasourceRelation(OnlFormHead onlFormHead, OnlineDatasource onlineDatasource, String errorMessage, OnlineDblink onlineDblink) { + //历史数据 --做比较新数据写入,已存在的不用管,不存在的删除 + OnlineDatasourceRelation onlineDatasourceRelations = new OnlineDatasourceRelation(); + onlineDatasourceRelations.setDatasourceId(onlineDatasource.getDatasourceId()); + List onlineDatasourceRelationList = + onlineDatasourceRelationService.getOnlineDatasourceRelationListWithRelation(onlineDatasourceRelations, null); + Map oldmap01 = + onlineDatasourceRelationList.stream().collect(Collectors.toMap(obj -> obj.getMasterColumnId() + "_" + obj.getRelationType() + "_" + obj.getSlaveTableId(), obj -> obj, + (key1, key2) -> key1 + )); + //查出表单元数据的所有附表关系 + //主表id + List onlineTableList = onlineTableService.list(new LambdaQueryWrapper().eq(OnlineTable::getTableName, onlFormHead.getTableName().toLowerCase())); + //创建一对多关系:1 + List oneToMoreObjsList = iOnlFormHeadService.list(new LambdaQueryWrapper().eq(OnlFormHead::getLine, 1).eq(OnlFormHead::getSort, onlFormHead.getTableName())); + if (!oneToMoreObjsList.isEmpty()) { + List tableIdList = onlineTableList.stream().map(OnlineTable::getTableId).collect(Collectors.toList()); +// //主表列id对象 + OnlineColumn onlineColumn = onlineColumnService.getOne(new LambdaQueryWrapper() + .eq(OnlineColumn::getColumnName, "id") + .in(OnlineColumn::getTableId, tableIdList)); + for (OnlFormHead formHead : oneToMoreObjsList) { + List onlineTableListfu = onlineTableService.list(new LambdaQueryWrapper().eq(OnlineTable::getTableName, formHead.getTableName().toLowerCase())); + //附表关联的主表字段+附表id + if ((onlineTableListfu == null || onlineTableListfu.size() < 1) || !oldmap01.containsKey(onlineColumn.getColumnId() + "_1_" + onlineTableListfu.get(0).getTableId())) { + OnlineDatasourceRelationDto onlineDatasourceRelationDto = new OnlineDatasourceRelationDto(); + onlineDatasourceRelationDto.setDatasourceId(onlineDatasource.getDatasourceId()); + //关联名称 + onlineDatasourceRelationDto.setRelationName(onlFormHead.getTableName() + "_" + formHead.getTableName()); + //关联标识 + onlineDatasourceRelationDto.setVariableName(onlFormHead.getTableName() + "_" + formHead.getTableName()); + //关联类型 + onlineDatasourceRelationDto.setRelationType(1); + //主键字段id + onlineDatasourceRelationDto.setMasterColumnId(onlineColumn.getColumnId()); + //从表名称 + onlineDatasourceRelationDto.setSlaveTableName(formHead.getTableName()); + //从表字段名称 + onlineDatasourceRelationDto.setSlaveColumnName(formHead.getSortFiled()); + //是否级联删除 + onlineDatasourceRelationDto.setCascadeDelete(true); + //是否左连接查询 + onlineDatasourceRelationDto.setLeftJoin(false); + OnlineDatasourceRelation onlineDatasourceRelation = + MyModelUtil.copyTo(onlineDatasourceRelationDto, OnlineDatasourceRelation.class); + String appCode = TokenData.takeFromRequest().getAppCode(); + if (!StrUtil.equals(onlineDatasource.getAppCode(), appCode)) { + errorMessage = "数据验证失败,当前应用并不包含该数据源Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } +// OnlineDblink onlineDblink = onlineDblinkService.getById(onlineDatasource.getDblinkId()); + SqlTable slaveTable = onlineDblinkService.getDblinkTable( + onlineDblink, onlineDatasourceRelationDto.getSlaveTableName()); + if (slaveTable == null) { + errorMessage = "数据验证失败,指定的数据表不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SqlTableColumn slaveColumn = null; + for (SqlTableColumn column : slaveTable.getColumnList()) { + if (column.getColumnName().equals(onlineDatasourceRelationDto.getSlaveColumnName())) { + slaveColumn = column; + break; + } + } + if (slaveColumn == null) { + errorMessage = "数据验证失败,指定的数据表字段 [" + onlineDatasourceRelationDto.getSlaveColumnName() + "] 不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = + onlineDatasourceRelationService.verifyRelatedData(onlineDatasourceRelation, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + onlineDatasourceRelation = onlineDatasourceRelationService.saveNew(onlineDatasourceRelation, slaveTable, slaveColumn); + } else { + //更新表字段 + SqlTable slaveTable = onlineDblinkService.getDblinkTable( + onlineDblink, formHead.getTableName()); + if (slaveTable == null) { + errorMessage = "数据验证失败,指定的数据表不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + List sqlTableColumnList = slaveTable.getColumnList(); + Set tableids = new HashSet<>(); + tableids.add(onlineTableListfu.get(0).getTableId()); + List listColumn = onlineColumnService.getOnlineColumnListByTableIds(tableids); + List columnNames = listColumn.stream().map(OnlineColumn::getColumnName).collect(Collectors.toList()); + sqlTableColumnList = sqlTableColumnList.stream().filter(x -> !columnNames.contains(x.getColumnName().toLowerCase())).collect(Collectors.toList()); + onlineColumnService.saveNewList(sqlTableColumnList, onlineTableListfu.get(0).getTableId()); + } + } + } + //创建一对一关系:0 + List onlFormFieldList = onlFormFieldService.list(new LambdaQueryWrapper() + .eq(OnlFormField::getHeadId, onlFormHead.getId()).isNotNull(OnlFormField::getRefPropert)); + //List oneToMoreObjsList = iOnlFormHeadService.list(new LambdaQueryWrapper().eq(OnlFormHead::getLine, 1).eq(OnlFormHead::getSort, onlFormHead.getTableName())); + if (!onlFormFieldList.isEmpty()) { + Set updatedTable = new HashSet<>(); + //附表 + for (OnlFormField onlFormField : onlFormFieldList) { + //附表 + List onlFormHeadList = iOnlFormHeadService.list(new LambdaQueryWrapper().eq(OnlFormHead::getId, onlFormField.getRefPropert())); + if (onlFormHeadList.isEmpty()) { + continue; + } + OnlFormHead formHead = onlFormHeadList.get(0); + //根据表名去找在线附表 + List fuonlineTableList = onlineTableService.list(new LambdaQueryWrapper().eq(OnlineTable::getTableName, onlFormHeadList.get(0).getTableName())); + //主表id对象 + OnlineColumn onlineColumn = onlineColumnService.getOne(new LambdaQueryWrapper() + .eq(OnlineColumn::getColumnName, onlFormField.getFieldName()) + .in(OnlineColumn::getTableId, onlineTableList.get(0).getTableId())); + if (onlineColumn == null) { + onlineColumn = onlineColumnService.getOne(new LambdaQueryWrapper() + .eq(OnlineColumn::getColumnName, onlFormField.getFieldName().toLowerCase()) + .in(OnlineColumn::getTableId, onlineTableList.get(0).getTableId())); + } + //附表关联的主表字段+附表id + if (fuonlineTableList == null || fuonlineTableList.isEmpty() || (!oldmap01.containsKey(onlineColumn.getColumnId() + "_0_" + fuonlineTableList.get(0).getTableId()))) { + OnlineDatasourceRelationDto onlineDatasourceRelationDto = new OnlineDatasourceRelationDto(); + onlineDatasourceRelationDto.setDatasourceId(onlineDatasource.getDatasourceId()); + //关联名称 + onlineDatasourceRelationDto.setRelationName(onlFormHead.getTableName() + "_" + onlFormField.getFieldName() + "_" + formHead.getTableName()); + //关联标识 + onlineDatasourceRelationDto.setVariableName(onlFormHead.getTableName() + "_" + onlFormField.getFieldName() + "_" + formHead.getTableName()); + //关联类型 + onlineDatasourceRelationDto.setRelationType(0); + //主键字段id + onlineDatasourceRelationDto.setMasterColumnId(onlineColumn.getColumnId()); + //从表名称 + onlineDatasourceRelationDto.setSlaveTableName(formHead.getTableName()); + //从表字段名称 + onlineDatasourceRelationDto.setSlaveColumnName("id"); + //是否级联删除 + onlineDatasourceRelationDto.setCascadeDelete(true); + //是否左连接查询 + onlineDatasourceRelationDto.setLeftJoin(false); + + OnlineDatasourceRelation onlineDatasourceRelation = + MyModelUtil.copyTo(onlineDatasourceRelationDto, OnlineDatasourceRelation.class); + String appCode = TokenData.takeFromRequest().getAppCode(); + if (!StrUtil.equals(onlineDatasource.getAppCode(), appCode)) { + errorMessage = "数据验证失败,当前应用并不包含该数据源Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } +// OnlineDblink onlineDblink = onlineDblinkService.getById(onlineDatasource.getDblinkId()); + SqlTable slaveTable = onlineDblinkService.getDblinkTable( + onlineDblink, onlineDatasourceRelationDto.getSlaveTableName()); + if (slaveTable == null) { + errorMessage = "数据验证失败,指定的数据表不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SqlTableColumn slaveColumn = null; + for (SqlTableColumn column : slaveTable.getColumnList()) { + if (column.getColumnName().equals(onlineDatasourceRelationDto.getSlaveColumnName())) { + slaveColumn = column; + break; + } + } + if (slaveColumn == null) { + errorMessage = "数据验证失败,指定的数据表字段 [" + onlineDatasourceRelationDto.getSlaveColumnName() + "] 不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = + onlineDatasourceRelationService.verifyRelatedData(onlineDatasourceRelation, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + onlineDatasourceRelation = onlineDatasourceRelationService.saveNew(onlineDatasourceRelation, slaveTable, slaveColumn); + } else { + if (updatedTable.contains(formHead.getTableName())) { + continue; + } + updatedTable.add(formHead.getTableName()); + //更新表字段 + SqlTable slaveTable = onlineDblinkService.getDblinkTable( + onlineDblink, formHead.getTableName()); + if (slaveTable == null) { + errorMessage = "数据验证失败,指定的数据表不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + List sqlTableColumnList = slaveTable.getColumnList(); + Set tableids = new HashSet<>(); + tableids.add(fuonlineTableList.get(0).getTableId()); + List listColumn = onlineColumnService.getOnlineColumnListByTableIds(tableids); + List columnNames = listColumn.stream().map(OnlineColumn::getColumnName).collect(Collectors.toList()); + sqlTableColumnList = sqlTableColumnList.stream().filter(x -> !columnNames.contains(x.getColumnName().toLowerCase())).collect(Collectors.toList()); + onlineColumnService.saveNewList(sqlTableColumnList, fuonlineTableList.get(0).getTableId()); + } + } + } + return null; + } } diff --git a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceServiceImpl.java index 1009f9b..cfcd9f3 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceServiceImpl.java +++ b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineDatasourceServiceImpl.java @@ -11,7 +11,10 @@ import apelet.common.dbutil.object.SqlTable; import apelet.common.online.dao.OnlineDatasourceMapper; import apelet.common.online.dao.OnlineDatasourceTableMapper; import apelet.common.online.dao.OnlinePageDatasourceMapper; -import apelet.common.online.model.*; +import apelet.common.online.model.OnlineDatasource; +import apelet.common.online.model.OnlineDatasourceTable; +import apelet.common.online.model.OnlinePageDatasource; +import apelet.common.online.model.OnlineTable; import apelet.common.online.service.OnlineDatasourceRelationService; import apelet.common.online.service.OnlineDatasourceService; import apelet.common.online.service.OnlineTableService; @@ -83,6 +86,7 @@ public class OnlineDatasourceServiceImpl extends BaseService