From 77c91162ba904ccc7a54b6828b816d56089b2b3e Mon Sep 17 00:00:00 2001 From: Wang Jason Date: Sat, 17 Jan 2026 16:52:03 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8A=9B=E5=87=BA?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98=E5=92=8C=E9=9D=9Ertc?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FrontendProjectDeployer.java | 73 ++++++++++++++----- .../generate/FrontendProjectGenerate.java | 2 +- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java index 4fcae329..e44b6b48 100644 --- a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java @@ -16,8 +16,6 @@ package com.inspur.edp.web.frontendproject; -import com.inspur.edp.ide.setting.api.entity.Deployment; -import com.inspur.edp.lcm.debugger.api.service.DebuggerService; import com.inspur.edp.lcm.metadata.api.entity.GspProject; import com.inspur.edp.web.common.JITEngineConstants; import com.inspur.edp.web.common.constant.FrontendProjectConstant; @@ -31,6 +29,10 @@ import com.inspur.edp.web.frontendproject.deploy.FrontMetadataDeployer; import com.inspur.edp.web.frontendproject.deploy.ProjectDeployerToPublish; import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.rpc.api.service.RpcClient; + +import java.lang.reflect.Method; +import java.util.LinkedHashMap; /** @@ -157,8 +159,7 @@ public class FrontendProjectDeployer { String targetDeployBasePath = ""; // 获取默认的部署环境信息 - DebuggerService debuggerService = SpringBeanUtils.getBean(DebuggerService.class); - Deployment defaultDebuggerDeployment = debuggerService.getDefaultDebugServerStatus(); + Object defaultDebuggerDeployment = getDefaultDebugServerStatusByRpc(); GspProject projectInfo = GspProjectUtility.getProjectInformation(projectPath); String serverDeployPath = getDeployServerPath(defaultDebuggerDeployment); @@ -168,26 +169,61 @@ public class FrontendProjectDeployer { return targetDeployBasePath; } + /** + * 通过RPC获取默认调试服务器状态 + * @return Deployment对象 + */ + private Object getDefaultDebugServerStatusByRpc() { + RpcClient client = SpringBeanUtils.getBean(RpcClient.class); + LinkedHashMap parameterHashMap = new LinkedHashMap<>(); + try { + return client.invoke(Object.class, + "com.inspur.edp.lcm.debugger.api.service.DebuggerService.getDefaultDebugServerStatus", + "main", + parameterHashMap, + null); + } catch (Exception e) { + throw new WebCustomException("Failed to get default debug server status via RPC", e); + } + } + /** * 获取部署位置 * - * @param defaultDebuggerDeployment - * @return + * @param defaultDebuggerDeployment Deployment对象 + * @return 服务器部署路径 */ - private String getDeployServerPath(Deployment defaultDebuggerDeployment) { + private String getDeployServerPath(Object defaultDebuggerDeployment) { String serverRootPath = ""; - if (defaultDebuggerDeployment == null || - "localhost".equalsIgnoreCase(defaultDebuggerDeployment.getName()) || - "current server".equalsIgnoreCase(defaultDebuggerDeployment.getName())) { - // 获取服务器端部署目录 + if (defaultDebuggerDeployment == null) { serverRootPath = FileUtility.getCurrentWorkPath(false); - - } else { - if (StringUtility.isNullOrEmpty(defaultDebuggerDeployment.getServerPath())) { - throw new WebCustomException("默认环境未设置路径"); + return serverRootPath; + } + + try { + // 调用getName()方法 + Method getNameMethod = defaultDebuggerDeployment.getClass().getMethod("getName"); + String deploymentName = (String) getNameMethod.invoke(defaultDebuggerDeployment); + + if (deploymentName == null || + "localhost".equalsIgnoreCase(deploymentName) || + "current server".equalsIgnoreCase(deploymentName)) { + // 获取服务器端部署目录 + serverRootPath = FileUtility.getCurrentWorkPath(false); + + } else { + // 调用getServerPath()方法 + Method getServerPathMethod = defaultDebuggerDeployment.getClass().getMethod("getServerPath"); + String serverPath = (String) getServerPathMethod.invoke(defaultDebuggerDeployment); + + if (StringUtility.isNullOrEmpty(serverPath)) { + throw new WebCustomException("默认环境未设置路径"); + } + WebLogger.Instance.debug("use default debugger deploy,the path is " + serverPath, FrontendProjectDeployer.class.getName()); + serverRootPath = serverPath; } - WebLogger.Instance.debug("use default debugger deploy,the path is " + defaultDebuggerDeployment.getServerPath(), FrontendProjectDeployer.class.getName()); - serverRootPath = defaultDebuggerDeployment.getServerPath(); + } catch (Exception e) { + throw new WebCustomException("Failed to access Deployment object via reflection", e); } return serverRootPath; } @@ -207,8 +243,7 @@ public class FrontendProjectDeployer { String targetBaseDeployPath = ""; // 获取默认的部署环境信息 - DebuggerService debuggerService = SpringBeanUtils.getBean(DebuggerService.class); - Deployment defaultDebuggerDeployment = debuggerService.getDefaultDebugServerStatus(); + Object defaultDebuggerDeployment = getDefaultDebugServerStatusByRpc(); GspProject projectInfo = GspProjectUtility.getProjectInformation(projectPath); String deployServerPath = this.getDeployServerPath(defaultDebuggerDeployment); diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java index ab234b84..0e5de3cf 100644 --- a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java @@ -147,7 +147,7 @@ public class FrontendProjectGenerate { try { FileUtility.writeFile(targetPackageJsonPath, mapper.writerWithDefaultPrettyPrinter().writeValueAsString(targetPackageJson)); } catch (JsonProcessingException e) { - throw new RuntimeException(e); + throw new WebCustomException("Failed to serialize package.json", e); } } -- Gitee From 7ce679effe4657114bc815ebae42bf8e9df1b0b8 Mon Sep 17 00:00:00 2001 From: Wang Jason Date: Wed, 11 Feb 2026 11:21:41 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9F=A5=E6=89=BE=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=96=B0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/dto/MetadataFullLoadResponseDto.java | 67 ++++ .../api/dto/MetadataWithDependenciesDto.java | 123 +++++++ .../config/FormMetadataConfiguration.java | 23 +- .../webservice/MetadataFullLoadWebApi.java | 315 ++++++++++++++++++ .../MetadataRuntimeFullLoadWebApi.java | 310 +++++++++++++++++ 5 files changed, 837 insertions(+), 1 deletion(-) create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataFullLoadResponseDto.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataWithDependenciesDto.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataFullLoadWebApi.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataRuntimeFullLoadWebApi.java diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataFullLoadResponseDto.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataFullLoadResponseDto.java new file mode 100644 index 00000000..33163ec6 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataFullLoadResponseDto.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.inspur.edp.web.formmetadata.api.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * 表单元数据完整加载响应 DTO + * 将主元数据与依赖信息拆分,避免在主元数据对象中加入 dependencies 字段, + * 以保持原有 /metadatas/load 响应结构的一致性。 + * + * { + * "metadata": { ... 原始 MetadataDto 结构 ... }, + * "dependencies": { + * "webcmds": [ ... ], + * "stateMachines": [ ... ], + * "externalForms": [ ... ] + * } + * } + * + * @author Auto Generated + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class MetadataFullLoadResponseDto { + + /** + * 主表单元数据(保持与原有 MetadataDto 结构兼容) + */ + private MetadataWithDependenciesDto metadata; + + /** + * 依赖数据(命令构件、状态机等) + */ + private MetadataWithDependenciesDto.DependenciesDto dependencies; + + public MetadataWithDependenciesDto getMetadata() { + return metadata; + } + + public void setMetadata(MetadataWithDependenciesDto metadata) { + this.metadata = metadata; + } + + public MetadataWithDependenciesDto.DependenciesDto getDependencies() { + return dependencies; + } + + public void setDependencies(MetadataWithDependenciesDto.DependenciesDto dependencies) { + this.dependencies = dependencies; + } +} + + diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataWithDependenciesDto.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataWithDependenciesDto.java new file mode 100644 index 00000000..bd87097f --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/api/dto/MetadataWithDependenciesDto.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.inspur.edp.web.formmetadata.api.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; + +import java.util.List; + +/** + * 包含依赖的元数据DTO + * 用于返回主表单及其所有依赖的完整元数据 + * + * @author Auto Generated + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class MetadataWithDependenciesDto extends MetadataDto { + + /** + * 依赖数据 + */ + private DependenciesDto dependencies; + + public DependenciesDto getDependencies() { + return dependencies; + } + + public void setDependencies(DependenciesDto dependencies) { + this.dependencies = dependencies; + } + + /** + * 依赖数据结构 + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class DependenciesDto { + /** + * 命令构件完整元数据列表 + */ + private List webcmds; + + /** + * 状态机完整元数据列表 + */ + private List stateMachines; + + /** + * 外部表单及其依赖(递归) + */ + private List externalForms; + + public List getWebcmds() { + return webcmds; + } + + public void setWebcmds(List webcmds) { + this.webcmds = webcmds; + } + + public List getStateMachines() { + return stateMachines; + } + + public void setStateMachines(List stateMachines) { + this.stateMachines = stateMachines; + } + + public List getExternalForms() { + return externalForms; + } + + public void setExternalForms(List externalForms) { + this.externalForms = externalForms; + } + } + + /** + * 外部表单DTO + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ExternalFormDto { + /** + * 容器ID(external-container组件的ID) + */ + private String containerId; + + /** + * 外部表单元数据(包含其依赖) + */ + private MetadataWithDependenciesDto metadata; + + public String getContainerId() { + return containerId; + } + + public void setContainerId(String containerId) { + this.containerId = containerId; + } + + public MetadataWithDependenciesDto getMetadata() { + return metadata; + } + + public void setMetadata(MetadataWithDependenciesDto metadata) { + this.metadata = metadata; + } + } +} + diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java index 1fa9f8df..d088a293 100644 --- a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java @@ -23,11 +23,12 @@ import com.inspur.edp.web.formmetadata.formresource.FormResourceManager; import com.inspur.edp.web.formmetadata.lic.FormMetadataCreateLicControlListener; import com.inspur.edp.web.formmetadata.service.*; import com.inspur.edp.web.formmetadata.webservice.FormMetadataWebServiceImpl; +import com.inspur.edp.web.formmetadata.webservice.MetadataFullLoadWebApi; +import com.inspur.edp.web.formmetadata.webservice.MetadataRuntimeFullLoadWebApi; import io.iec.edp.caf.rest.RESTEndpoint; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; @Configuration("com.inspur.edp.web.formmetadata.config.FormMetadataConfiguration") public class FormMetadataConfiguration { @@ -36,6 +37,26 @@ public class FormMetadataConfiguration { return new RESTEndpoint("/dev/main/v1.0/form-metadata", new FormMetadataWebServiceImpl()); } + /** + * 元数据完整加载接口 + * 提供一次性加载主表单及其所有依赖的接口 + * 使用不同的路径避免与LCM的/metadatas接口冲突 + */ + @Bean() + public RESTEndpoint metadataFullLoadWebapiEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/form-metadata-full-load", new MetadataFullLoadWebApi()); + } + + /** + * 运行时元数据完整加载接口 + * 根据运行时元数据ID,一次性加载主表单及其依赖 + * 使用 /runtime/lcm/v1.0 前缀,避免与 LCM 自带的 /rt-metadatas 路径冲突 + */ + @Bean() + public RESTEndpoint metadataRuntimeFullLoadWebapiEndPoint() { + return new RESTEndpoint("/runtime/lcm/v1.0/form-metadata-full-load", new MetadataRuntimeFullLoadWebApi()); + } + @Bean public FormMetadataRTService formMetadataRTService() { return new FormMetadataRTService(); diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataFullLoadWebApi.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataFullLoadWebApi.java new file mode 100644 index 00000000..4f6d6025 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataFullLoadWebApi.java @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.inspur.edp.web.formmetadata.webservice; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; +import com.inspur.edp.web.common.customexception.WebCustomException; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.logger.WebLogger; +import com.inspur.edp.web.common.metadata.MetadataGetterParameter; +import com.inspur.edp.web.common.metadata.MetadataTypeEnum; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.api.dto.MetadataWithDependenciesDto; +import com.inspur.edp.web.formmetadata.api.dto.MetadataFullLoadResponseDto; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.formmetadata.metadatamanager.MetadataManagerParameter; +import com.inspur.edp.web.formmetadata.metadatamanager.StateMachineMetadataManager; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +/** + * 元数据完整加载WebApi + * 提供一次性加载主表单及其所有依赖的接口 + * + * @author Auto Generated + */ +@Path("/") +public class MetadataFullLoadWebApi { + + /** + * 加载表单元数据及其所有依赖 + * + * @param metadataFullPath 元数据完整路径(格式:projectPath/formPath/fileName.frm) + * @return 包含主表单和所有依赖的元数据DTO + */ + @GET + @Path("/loadMetadataWithDependencies") + @Produces(MediaType.APPLICATION_JSON) + public MetadataFullLoadResponseDto loadMetadataWithDependencies(@QueryParam("metadataFullPath") String metadataFullPath) { + if (StringUtility.isNullOrEmpty(metadataFullPath)) { + throw new WebCustomException("metadataFullPath参数不能为空"); + } + + try { + // 1. 解析路径,获取fileName和relativePath + String[] pathParts = parseMetadataPath(metadataFullPath); + String fileName = pathParts[0]; + String relativePath = pathParts[1]; + + // 2. 加载主表单元数据 + GspMetadata mainFormMetadata = MetadataUtility.getInstance() + .getMetadataWithDesign(fileName, relativePath); + + if (mainFormMetadata == null) { + throw new WebCustomException("未找到元数据: " + metadataFullPath); + } + + // 3. 转换为主元数据 DTO(不包含依赖信息) + MetadataWithDependenciesDto metadataDto = convertToDto(mainFormMetadata); + + // 4. 加载依赖信息 + MetadataWithDependenciesDto.DependenciesDto dependencies = + loadDependenciesInParallel(mainFormMetadata, new HashSet<>()); + + // 5. 组装响应对象:metadata 与 dependencies 分离 + MetadataFullLoadResponseDto responseDto = new MetadataFullLoadResponseDto(); + responseDto.setMetadata(metadataDto); + responseDto.setDependencies(dependencies); + + return responseDto; + } catch (WebCustomException e) { + WebLogger.Instance.error("加载元数据及其依赖失败: " + metadataFullPath, e.getMessage()); + throw e; + } catch (Exception e) { + String errorMessage = e.getMessage(); + if (StringUtility.isNullOrEmpty(errorMessage)) { + errorMessage = e.getClass().getSimpleName(); + } + WebLogger.Instance.error("加载元数据及其依赖失败: " + metadataFullPath, errorMessage); + throw new WebCustomException("加载元数据及其依赖失败: " + errorMessage, e); + } + } + + /** + * 解析元数据路径 + * + * @param metadataFullPath 完整路径,如:project/form/fileName.frm + * @return [fileName, relativePath] + */ + private String[] parseMetadataPath(String metadataFullPath) { + int lastSlash = metadataFullPath.lastIndexOf('/'); + if (lastSlash < 0) { + throw new WebCustomException("无效的元数据路径格式: " + metadataFullPath); + } + String fileName = metadataFullPath.substring(lastSlash + 1); + String relativePath = metadataFullPath.substring(0, lastSlash); + return new String[]{fileName, relativePath}; + } + + /** + * 将GspMetadata转换为MetadataWithDependenciesDto + */ + private MetadataWithDependenciesDto convertToDto(GspMetadata metadata) { + MetadataWithDependenciesDto dto = new MetadataWithDependenciesDto(); + + // 设置基本信息(只设置确实存在的字段) + dto.setId(metadata.getHeader().getId()); + dto.setCode(metadata.getHeader().getCode()); + dto.setName(metadata.getHeader().getName()); + dto.setRelativePath(metadata.getRelativePath()); + dto.setFileName(metadata.getHeader().getFileName()); + dto.setType(metadata.getHeader().getType()); + dto.setBizobjectID(metadata.getHeader().getBizobjectID()); + + // 设置nameLanguage(如果存在) + if (metadata.getHeader().getNameLanguage() != null) { + dto.setNameLanguage(metadata.getHeader().getNameLanguage()); + } + + // 设置content - MetadataDto的content是String类型,需要序列化 + if (metadata.getContent() != null) { + try { + com.inspur.edp.web.common.serialize.SerializeUtility serializeUtility = + com.inspur.edp.web.common.serialize.SerializeUtility.getInstance(); + String contentJson = serializeUtility.getDefaultObjectMapper() + .writeValueAsString(metadata.getContent()); + dto.setContent(contentJson); + } catch (Exception e) { + WebLogger.Instance.error("序列化元数据content失败", e.getMessage()); + dto.setContent("{}"); // 设置默认值,避免序列化失败 + } + } else { + dto.setContent("{}"); + } + + // 设置refs - 前端需要这个字段,如果不存在则设置为空数组的JSON字符串 + // 注意:MetadataHeader可能没有getRefs方法,直接设置为空数组 + dto.setRefs("[]"); + + return dto; + } + + /** + * 并行加载所有依赖 + * + * @param metadata 主表单元数据 + * @param visitedPaths 已访问的路径集合,用于防止循环引用 + * @return 依赖数据 + */ + private MetadataWithDependenciesDto.DependenciesDto loadDependenciesInParallel( + GspMetadata metadata, Set visitedPaths) { + + String metadataPath = metadata.getRelativePath() + "/" + metadata.getHeader().getFileName(); + + // 防止循环引用 + if (visitedPaths.contains(metadataPath)) { + WebLogger.Instance.warn("检测到循环引用,跳过: " + metadataPath); + return new MetadataWithDependenciesDto.DependenciesDto(); + } + visitedPaths.add(metadataPath); + + MetadataWithDependenciesDto.DependenciesDto dependencies = + new MetadataWithDependenciesDto.DependenciesDto(); + + try { + // 解析表单内容 + FormMetadataContent formContent = (FormMetadataContent) metadata.getContent(); + FormDOM formDOM = FormMetadataContentService.getInstance().getFormContent(formContent); + + if (formDOM == null || formDOM.getModule() == null) { + return dependencies; + } + + // 1. 并行加载命令构件 + List> webcmdFutures = new ArrayList<>(); + if (formDOM.getModule().getWebcmds() != null) { + for (HashMap webcmdInfo : formDOM.getModule().getWebcmds()) { + Object webcmdId = webcmdInfo.get("id"); + if (webcmdId != null) { + webcmdFutures.add(CompletableFuture.supplyAsync(() -> + loadWebCmdMetadata(metadata.getRelativePath(), webcmdId.toString()))); + } + } + } + + // 2. 并行加载状态机 + List> stateMachineFutures = new ArrayList<>(); + if (formDOM.getModule().getStateMachines() != null && !formDOM.getModule().getStateMachines().isEmpty()) { + Map firstStateMachine = formDOM.getModule().getStateMachines().get(0); + Object smUri = firstStateMachine.get("uri"); + if (smUri != null) { + stateMachineFutures.add(CompletableFuture.supplyAsync(() -> + loadStateMachineMetadata(metadata.getRelativePath(), smUri.toString(), firstStateMachine))); + } + } + + // 等待所有查询完成 + List> allFutures = new ArrayList<>(); + allFutures.addAll(webcmdFutures); + allFutures.addAll(stateMachineFutures); + CompletableFuture.allOf(allFutures.toArray(new CompletableFuture[0])).join(); + + // 组装返回结果 + dependencies.setWebcmds(webcmdFutures.stream() + .map(future -> { + try { + return future.get(); + } catch (Exception e) { + WebLogger.Instance.error("加载命令构件失败: " + e.getMessage()); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList())); + + dependencies.setStateMachines(stateMachineFutures.stream() + .map(future -> { + try { + return future.get(); + } catch (Exception e) { + WebLogger.Instance.error("加载状态机失败: " + e.getMessage()); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList())); + + // 运行时接口暂不考虑外部表单依赖,externalForms 统一返回空列表 + dependencies.setExternalForms(Collections.emptyList()); + + } catch (Exception e) { + WebLogger.Instance.error("加载依赖失败: " + e.getMessage()); + } finally { + visitedPaths.remove(metadataPath); + } + + return dependencies; + } + + /** + * 加载命令构件元数据 + */ + private MetadataDto loadWebCmdMetadata(String relativePath, String webcmdId) { + try { + MetadataGetterParameter parameter = MetadataGetterParameter.getNewInstance( + webcmdId, relativePath, MetadataTypeEnum.Command); + GspMetadata webcmdMetadata = MetadataUtility.getInstance().getMetadataWithDesign(parameter); + + if (webcmdMetadata == null) { + return null; + } + + return convertToDto(webcmdMetadata); + } catch (Exception e) { + WebLogger.Instance.error("加载命令构件元数据失败: " + webcmdId + ", " + e.getMessage()); + return null; + } + } + + /** + * 加载状态机元数据 + */ + private MetadataDto loadStateMachineMetadata(String relativePath, String stateMachineUri, + Map stateMachineInfo) { + try { + StateMachineMetadataManager stateMachineMetadataManager = + new StateMachineMetadataManager(ExecuteEnvironment.Design, false, relativePath); + + MetadataManagerParameter parameter = MetadataManagerParameter.init( + stateMachineUri, + StringUtility.getOrDefaultEmpty(stateMachineInfo.get("code")), + StringUtility.getOrDefaultEmpty(stateMachineInfo.get("name")), + StringUtility.getOrDefaultEmpty(stateMachineInfo.get("nameSpace"))); + + GspMetadata stateMachineMetadata = stateMachineMetadataManager.getStateMachine(parameter); + + if (stateMachineMetadata == null) { + return null; + } + + return convertToDto(stateMachineMetadata); + } catch (Exception e) { + WebLogger.Instance.error("加载状态机元数据失败: " + stateMachineUri + ", " + e.getMessage()); + return null; + } + } + +} + diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataRuntimeFullLoadWebApi.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataRuntimeFullLoadWebApi.java new file mode 100644 index 00000000..f7e3a0ae --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/MetadataRuntimeFullLoadWebApi.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.inspur.edp.web.formmetadata.webservice; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; +import com.inspur.edp.web.common.customexception.WebCustomException; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.logger.WebLogger; +import com.inspur.edp.web.common.metadata.MetadataGetterParameter; +import com.inspur.edp.web.common.metadata.MetadataTypeEnum; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.api.dto.MetadataFullLoadResponseDto; +import com.inspur.edp.web.formmetadata.api.dto.MetadataWithDependenciesDto; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.formmetadata.metadatamanager.MetadataManagerParameter; +import com.inspur.edp.web.formmetadata.metadatamanager.StateMachineMetadataManager; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +/** + * 元数据运行时完整加载 WebApi + * 根据元数据ID,一次性加载运行时主表单及其依赖(命令构件、状态机)。 + * + * 路径建议: + * /runtime/lcm/v1.0/form-metadata-full-load/loadMetadataWithDependenciesById?metadataId=... + * + * 返回结构: + * { + * "metadata": MetadataDto, + * "dependencies": { + * "webcmds": MetadataDto[], + * "stateMachines": MetadataDto[], + * "externalForms": [] // 运行时暂不处理外部表单 + * } + * } + * + * @author Auto Generated + */ +@Path("/") +public class MetadataRuntimeFullLoadWebApi { + + /** + * 根据元数据ID加载运行时表单及其依赖 + * + * @param metadataId 运行时元数据ID(发布后使用的 baseMetadataId / metadataId) + * @return 包含主表单和依赖信息的响应对象 + */ + @GET + @Path("/loadMetadataWithDependenciesById") + @Produces(MediaType.APPLICATION_JSON) + public MetadataFullLoadResponseDto loadMetadataWithDependenciesById(@QueryParam("metadataId") String metadataId) { + if (StringUtility.isNullOrEmpty(metadataId)) { + throw new WebCustomException("metadataId参数不能为空"); + } + + try { + // 1. 运行时加载主表单元数据 + GspMetadata mainFormMetadata = MetadataUtility.getInstance().getMetadataWithRuntime(metadataId); + + if (mainFormMetadata == null) { + throw new WebCustomException("在运行时未找到元数据: " + metadataId); + } + + // 2. 转换为主元数据 DTO + MetadataWithDependenciesDto metadataDto = convertToDto(mainFormMetadata); + + // 3. 加载依赖(命令构件、状态机) + MetadataWithDependenciesDto.DependenciesDto dependencies = + loadDependencies(mainFormMetadata, new HashSet<>()); + + // 4. 组装响应结果 + MetadataFullLoadResponseDto responseDto = new MetadataFullLoadResponseDto(); + responseDto.setMetadata(metadataDto); + responseDto.setDependencies(dependencies); + + return responseDto; + } catch (WebCustomException e) { + WebLogger.Instance.error("运行时加载元数据及其依赖失败: " + metadataId, e.getMessage()); + throw e; + } catch (Exception e) { + String errorMessage = e.getMessage(); + if (StringUtility.isNullOrEmpty(errorMessage)) { + errorMessage = e.getClass().getSimpleName(); + } + WebLogger.Instance.error("运行时加载元数据及其依赖失败: " + metadataId, errorMessage); + throw new WebCustomException("运行时加载元数据及其依赖失败: " + errorMessage, e); + } + } + + /** + * 将GspMetadata转换为MetadataWithDependenciesDto + * (与设计时接口保持一致的主元数据结构) + */ + private MetadataWithDependenciesDto convertToDto(GspMetadata metadata) { + MetadataWithDependenciesDto dto = new MetadataWithDependenciesDto(); + + // 设置基本信息 + dto.setId(metadata.getHeader().getId()); + dto.setCode(metadata.getHeader().getCode()); + dto.setName(metadata.getHeader().getName()); + dto.setRelativePath(metadata.getRelativePath()); + dto.setFileName(metadata.getHeader().getFileName()); + dto.setType(metadata.getHeader().getType()); + dto.setBizobjectID(metadata.getHeader().getBizobjectID()); + + // 设置nameLanguage(如果存在) + if (metadata.getHeader().getNameLanguage() != null) { + dto.setNameLanguage(metadata.getHeader().getNameLanguage()); + } + + // 设置content - MetadataDto的content是String类型,需要序列化 + if (metadata.getContent() != null) { + try { + com.inspur.edp.web.common.serialize.SerializeUtility serializeUtility = + com.inspur.edp.web.common.serialize.SerializeUtility.getInstance(); + String contentJson = serializeUtility.getDefaultObjectMapper() + .writeValueAsString(metadata.getContent()); + dto.setContent(contentJson); + } catch (Exception e) { + WebLogger.Instance.error("序列化运行时元数据content失败", e.getMessage()); + dto.setContent("{}"); // 设置默认值,避免序列化失败 + } + } else { + dto.setContent("{}"); + } + + // refs - 运行时场景下暂不使用,统一设置为空数组 + dto.setRefs("[]"); + + return dto; + } + + /** + * 加载依赖数据(命令构件、状态机) + * + * @param metadata 主表单元数据(运行时) + * @param visitedPaths 已访问的路径集合,用于防止循环引用 + * @return 依赖数据 + */ + private MetadataWithDependenciesDto.DependenciesDto loadDependencies( + GspMetadata metadata, Set visitedPaths) { + + String metadataPath = metadata.getRelativePath() + "/" + metadata.getHeader().getFileName(); + + // 防止循环引用 + if (visitedPaths.contains(metadataPath)) { + WebLogger.Instance.warn("运行时检测到循环引用,跳过: " + metadataPath); + return new MetadataWithDependenciesDto.DependenciesDto(); + } + visitedPaths.add(metadataPath); + + MetadataWithDependenciesDto.DependenciesDto dependencies = + new MetadataWithDependenciesDto.DependenciesDto(); + + try { + // 解析表单内容 + FormMetadataContent formContent = (FormMetadataContent) metadata.getContent(); + FormDOM formDOM = FormMetadataContentService.getInstance().getFormContent(formContent); + + if (formDOM == null || formDOM.getModule() == null) { + return dependencies; + } + + // 1. 并行加载命令构件(使用设计时元数据服务加载命令构件元数据) + List> webcmdFutures = new ArrayList<>(); + if (formDOM.getModule().getWebcmds() != null) { + for (HashMap webcmdInfo : formDOM.getModule().getWebcmds()) { + Object webcmdId = webcmdInfo.get("id"); + if (webcmdId != null) { + webcmdFutures.add(CompletableFuture.supplyAsync(() -> + loadWebCmdMetadata(metadata.getRelativePath(), webcmdId.toString()))); + } + } + } + + // 2. 并行加载状态机(运行时场景,依旧复用状态机元数据管理器) + List> stateMachineFutures = new ArrayList<>(); + if (formDOM.getModule().getStateMachines() != null && !formDOM.getModule().getStateMachines().isEmpty()) { + Map firstStateMachine = formDOM.getModule().getStateMachines().get(0); + Object smUri = firstStateMachine.get("uri"); + if (smUri != null) { + stateMachineFutures.add(CompletableFuture.supplyAsync(() -> + loadStateMachineMetadata(metadata.getRelativePath(), smUri.toString(), firstStateMachine))); + } + } + + // 等待所有查询完成 + List> allFutures = new ArrayList<>(); + allFutures.addAll(webcmdFutures); + allFutures.addAll(stateMachineFutures); + CompletableFuture.allOf(allFutures.toArray(new CompletableFuture[0])).join(); + + // 组装返回结果 + dependencies.setWebcmds(webcmdFutures.stream() + .map(future -> { + try { + return future.get(); + } catch (Exception e) { + WebLogger.Instance.error("运行时加载命令构件失败: " + e.getMessage()); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList())); + + dependencies.setStateMachines(stateMachineFutures.stream() + .map(future -> { + try { + return future.get(); + } catch (Exception e) { + WebLogger.Instance.error("运行时加载状态机失败: " + e.getMessage()); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList())); + + // 运行时接口暂不处理外部表单依赖,统一返回空列表 + dependencies.setExternalForms(new ArrayList<>()); + + } catch (Exception e) { + WebLogger.Instance.error("运行时加载依赖失败: " + e.getMessage()); + } finally { + visitedPaths.remove(metadataPath); + } + + return dependencies; + } + + /** + * 加载命令构件元数据(设计时元数据服务) + */ + private MetadataDto loadWebCmdMetadata(String relativePath, String webcmdId) { + try { + MetadataGetterParameter parameter = MetadataGetterParameter.getNewInstance( + webcmdId, relativePath, MetadataTypeEnum.Command); + GspMetadata webcmdMetadata = MetadataUtility.getInstance().getMetadataWithDesign(parameter); + + if (webcmdMetadata == null) { + return null; + } + + return convertToDto(webcmdMetadata); + } catch (Exception e) { + WebLogger.Instance.error("运行时加载命令构件元数据失败: " + webcmdId + ", " + e.getMessage()); + return null; + } + } + + /** + * 加载状态机元数据(复用 StateMachineMetadataManager) + */ + private MetadataDto loadStateMachineMetadata(String relativePath, String stateMachineUri, + Map stateMachineInfo) { + try { + StateMachineMetadataManager stateMachineMetadataManager = + new StateMachineMetadataManager(ExecuteEnvironment.Design, false, relativePath); + + MetadataManagerParameter parameter = MetadataManagerParameter.init( + stateMachineUri, + StringUtility.getOrDefaultEmpty(stateMachineInfo.get("code")), + StringUtility.getOrDefaultEmpty(stateMachineInfo.get("name")), + StringUtility.getOrDefaultEmpty(stateMachineInfo.get("nameSpace"))); + + GspMetadata stateMachineMetadata = stateMachineMetadataManager.getStateMachine(parameter); + + if (stateMachineMetadata == null) { + return null; + } + + return convertToDto(stateMachineMetadata); + } catch (Exception e) { + WebLogger.Instance.error("运行时加载状态机元数据失败: " + stateMachineUri + ", " + e.getMessage()); + return null; + } + } +} + + -- Gitee