feat(mms-mapping): test中添加XML字符串返回功能并优化JSON转XML性能测试

- 在IcdToXmlGenerateResult和IcdToXmlResponse中新增mappingXml字段存储生成的XML字符串
- 修改IcdToXmlResponseConverter将XML内容从savedPath改为mappingXml字段
- 更新IcdToXmlTaskAppService将XML转换结果从保存路径改为直接返回XML内容
- 重构JsonToXmlConversionService移除临时文件创建,直接返回XML字符串
- 在JsonToXmlConversionService中添加性能监控日志输出
- 新增JsonToXmlDebugRunner用于本地调试JSON转XML功能
This commit is contained in:
周宇 蔡
2026-05-06 14:31:18 +08:00
parent b3e679249b
commit ddadf26837
6 changed files with 341 additions and 19 deletions

View File

@@ -20,7 +20,7 @@ public class IcdToXmlResponseConverter {
response.setLdInst(result.getLdInst()); response.setLdInst(result.getLdInst());
response.setSavedPath(result.getSavedPath()); response.setSavedPath(result.getSavedPath());
response.getProblems().addAll(result.getProblems()); response.getProblems().addAll(result.getProblems());
response.setMappingXml(result.getMappingXml());
if (result.getIndexAnalysis() != null && result.getIndexAnalysis().getCandidates() != null) { if (result.getIndexAnalysis() != null && result.getIndexAnalysis().getCandidates() != null) {
for (IndexCandidate candidate : result.getIndexAnalysis().getCandidates()) { for (IndexCandidate candidate : result.getIndexAnalysis().getCandidates()) {
IndexCandidateResponse candidateResponse = new IndexCandidateResponse(); IndexCandidateResponse candidateResponse = new IndexCandidateResponse();

View File

@@ -55,37 +55,58 @@ public class JsonToXmlConversionService {
List<InputStream> ruleStreams, List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
// 1. 反序列化JSON为MappingDocument对象 long startTime = System.currentTimeMillis();
MappingDocument mappingDocument = objectMapper.readValue(mappingJson, MappingDocument.class); System.out.println("[JSON转XML] 开始转换...");
// 2. 使用现有的规则引擎生成XML try {
// 注意这里复用RuleBasedXmlMappingService的核心逻辑 MappingDocument mappingDocument = objectMapper.readValue(mappingJson, MappingDocument.class);
// 但数据来源从ICD直接解析改为从MappingDocument提取
String xmlContent = buildXmlFromMapping(mappingDocument, templateStream, ruleStreams, indexMapping);
// 3. 保存为临时文件 long parseTime = System.currentTimeMillis();
Path tempPath = Files.createTempFile("converted_", ".xml"); System.out.println("[JSON转XML] JSON解析完成耗时: " + (parseTime - startTime) + " ms");
Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8));
return tempPath.toString(); String xmlContent = buildXmlFromMapping(mappingDocument, templateStream, ruleStreams, indexMapping);
long totalTime = System.currentTimeMillis() - startTime;
System.out.println("[JSON转XML] 转换完成,总耗时: " + totalTime + " ms");
return xmlContent;
} catch (Exception e) {
long totalTime = System.currentTimeMillis() - startTime;
System.err.println("[JSON转XML] 转换失败,已耗时: " + totalTime + " ms错误: " + e.getMessage());
throw e;
}
} }
/**
* 从MappingDocument构建XML内容
*/
private String buildXmlFromMapping(MappingDocument mappingDocument, private String buildXmlFromMapping(MappingDocument mappingDocument,
InputStream templateStream, InputStream templateStream,
List<InputStream> ruleStreams, List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
long stepStart = System.currentTimeMillis();
String templateContent = readInputStreamToString(templateStream); String templateContent = readInputStreamToString(templateStream);
long templateTime = System.currentTimeMillis();
System.out.println(" [步骤1] 读取模板完成,耗时: " + (templateTime - stepStart) + " ms");
String xmlContent = fillIedInfo(templateContent, mappingDocument); String xmlContent = fillIedInfo(templateContent, mappingDocument);
long iedTime = System.currentTimeMillis();
System.out.println(" [步骤2] 填充IED信息完成耗时: " + (iedTime - templateTime) + " ms");
xmlContent = fillReportControlsFromMapping(xmlContent, mappingDocument); xmlContent = fillReportControlsFromMapping(xmlContent, mappingDocument);
long reportTime = System.currentTimeMillis();
System.out.println(" [步骤3] 填充ReportControl完成耗时: " + (reportTime - iedTime) + " ms");
xmlContent = applyRulesFromMapping(xmlContent, mappingDocument, ruleStreams, indexMapping); xmlContent = applyRulesFromMapping(xmlContent, mappingDocument, ruleStreams, indexMapping);
long rulesTime = System.currentTimeMillis();
System.out.println(" [步骤4] 应用规则完成,耗时: " + (rulesTime - reportTime) + " ms");
long totalStepTime = System.currentTimeMillis() - stepStart;
System.out.println(" [buildXmlFromMapping] 总计耗时: " + totalStepTime + " ms");
return xmlContent; return xmlContent;
} }
@@ -219,21 +240,40 @@ public class JsonToXmlConversionService {
List<InputStream> ruleStreams, List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
long stepStart = System.currentTimeMillis();
var mergedRules = mergeAllRulesDesc(ruleStreams, indexMapping); var mergedRules = mergeAllRulesDesc(ruleStreams, indexMapping);
long mergeTime = System.currentTimeMillis();
System.out.println(" [规则合并] 耗时: " + (mergeTime - stepStart) + " ms规则数: " + mergedRules.size());
var mappingMetrics = extractMetricsFromMapping(mappingDocument); var mappingMetrics = extractMetricsFromMapping(mappingDocument);
long extractTime = System.currentTimeMillis();
System.out.println(" [指标提取] 耗时: " + (extractTime - mergeTime) + " ms指标数: " + mappingMetrics.size());
System.out.println("========== 开始从JSON匹配规则 =========="); System.out.println("========== 开始从JSON匹配规则 ==========");
System.out.println("规则总数: " + mergedRules.size()); System.out.println("规则总数: " + mergedRules.size());
System.out.println("JSON中指标总数: " + mappingMetrics.size()); System.out.println("JSON中指标总数: " + mappingMetrics.size());
var applicableRules = findApplicableRulesDesc(mergedRules, mappingMetrics); var applicableRules = findApplicableRulesDesc(mergedRules, mappingMetrics);
long matchTime = System.currentTimeMillis();
System.out.println(" [规则匹配] 耗时: " + (matchTime - extractTime) + " ms");
System.out.println("匹配成功: " + applicableRules.size() + " 条规则"); System.out.println("匹配成功: " + applicableRules.size() + " 条规则");
System.out.println("匹配失败: " + (mergedRules.size() - applicableRules.size()) + " 条规则"); System.out.println("匹配失败: " + (mergedRules.size() - applicableRules.size()) + " 条规则");
String resultXml = applyRulesToXml(xmlContent, applicableRules);
long applyTime = System.currentTimeMillis();
System.out.println(" [规则应用] 耗时: " + (applyTime - matchTime) + " ms");
long totalApplyTime = System.currentTimeMillis() - stepStart;
System.out.println(" [applyRulesFromMapping] 总计耗时: " + totalApplyTime + " ms");
System.out.println("========== JSON规则匹配结束 ==========\n"); System.out.println("========== JSON规则匹配结束 ==========\n");
return applyRulesToXml(xmlContent, applicableRules); return resultXml;
} }
/** /**

View File

@@ -18,6 +18,17 @@ public class IcdToXmlGenerateResult {
private MappingDocument mappingDocument; private MappingDocument mappingDocument;
private String savedPath; private String savedPath;
private List<String> problems = new ArrayList<String>(); private List<String> problems = new ArrayList<String>();
/** 生成成功后的 Xml 字符串。 */
private String mappingXml;
public String getMappingXml() {
return mappingXml;
}
public void setMappingXml(String mappingXml) {
this.mappingXml = mappingXml;
}
public GenerateStatus getStatus() { return status; } public GenerateStatus getStatus() { return status; }
public void setStatus(GenerateStatus status) { this.status = status; } public void setStatus(GenerateStatus status) { this.status = status; }

View File

@@ -16,6 +16,16 @@ public class IcdToXmlResponse {
private MappingDocumentResponse mappingDocument; private MappingDocumentResponse mappingDocument;
private List<IndexCandidateResponse> indexCandidates = new ArrayList<IndexCandidateResponse>(); private List<IndexCandidateResponse> indexCandidates = new ArrayList<IndexCandidateResponse>();
private List<String> problems = new ArrayList<String>(); private List<String> problems = new ArrayList<String>();
/** 生成成功后的 Xml 字符串。 */
private String mappingXml;
public String getMappingXml() {
return mappingXml;
}
public void setMappingXml(String mappingXml) {
this.mappingXml = mappingXml;
}
public GenerateStatus getStatus() { return status; } public GenerateStatus getStatus() { return status; }
public void setStatus(GenerateStatus status) { this.status = status; } public void setStatus(GenerateStatus status) { this.status = status; }
public String getMessage() { return message; } public String getMessage() { return message; }

View File

@@ -160,14 +160,14 @@ public class IcdToXmlTaskAppService {
// 3. 从 JSON 转换为 XML // 3. 从 JSON 转换为 XML
String xmlPath = jsonToXmlConversionService.convertFromJson( String xmlContent = jsonToXmlConversionService.convertFromJson(
mappingJson, mappingJson,
templateStream, templateStream,
ruleStreams, ruleStreams,
icdToXmlMappingService.getIndexMapping() icdToXmlMappingService.getIndexMapping()
); );
result.setSavedPath(xmlPath); result.setMappingXml(xmlContent);
result.setStatus(GenerateStatus.SUCCESS); result.setStatus(GenerateStatus.SUCCESS);
result.setMessage("XML 生成成功"); result.setMessage("XML 生成成功");
return result; return result;

View File

@@ -0,0 +1,261 @@
package com.njcn.gather.icd.mapping.debug;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.njcn.gather.icd.mapping.component.IcdToXmlResponseConverter;
import com.njcn.gather.icd.mapping.pojo.bo.IcdToXmlGenerateResult;
import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus;
import com.njcn.gather.icd.mapping.service.impl.IcdToXmlTaskAppService;
import org.springframework.boot.Banner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* JSON 转 XML 本地调试入口。
*
* 使用方式:
* 1. 先通过 GetIcdMmsJsonDebugRunner 获取 mappingJson或使用已有的 JSON 文件。
* 2. 修改 MMS_JSON_FILE_PATH 指向包含 mappingJson 的文件路径。
* 3. 直接运行 main查看生成的 XML 内容。
* 4. 可选:设置 SAVE_XML_TO_DISK = true 将 XML 保存到磁盘。
*/
public class JsonToXmlDebugRunner {
/**
* 包含 mappingJson 的文件路径。
* 文件格式:纯文本,内容为 getIcdMmsJson 接口返回的 mappingJson 字段值。
* 或者完整的 MappingTaskResponse JSON会自动提取 mappingJson 字段)。
*/
private static final String MMS_JSON_FILE_PATH = "D:/temp/mms-output/mapping.json";
/** 是否输出格式化 XML便于人工查看。 */
private static final boolean PRETTY_XML = true;
/** 是否把生成的 XML 写入磁盘。 */
private static final boolean SAVE_XML_TO_DISK = true;
/** saveXmlToDisk=true 时使用的输出文件路径。 */
private static final String OUTPUT_XML_PATH = "D:/temp/mms-output/generated-config.xml";
/** 是否打印详细的转换过程日志。 */
private static final boolean VERBOSE_LOG = true;
public static void main(String[] args) {
try (ConfigurableApplicationContext context = new SpringApplicationBuilder(DebugApplication.class)
.web(WebApplicationType.NONE)
.bannerMode(Banner.Mode.OFF)
.logStartupInfo(false)
.run(args)) {
IcdToXmlTaskAppService icdToXmlTaskAppService = context.getBean(IcdToXmlTaskAppService.class);
IcdToXmlResponseConverter responseConverter = context.getBean(IcdToXmlResponseConverter.class);
ObjectMapper objectMapper = createObjectMapper();
if (VERBOSE_LOG) {
System.out.println("========== JSON 转 XML 调试开始 ==========");
System.out.println("输入文件: " + MMS_JSON_FILE_PATH);
System.out.println("输出文件: " + (SAVE_XML_TO_DISK ? OUTPUT_XML_PATH : "(不保存)"));
System.out.println();
}
// 读取 JSON 文件
String jsonContent = readJsonFile();
if (VERBOSE_LOG) {
System.out.println("✓ JSON 文件读取成功,长度: " + jsonContent.length() + " 字符");
}
// 提取 mappingJson可能是完整响应或纯 mappingJson
String mappingJson = extractMappingJson(jsonContent, objectMapper);
if (VERBOSE_LOG) {
System.out.println("✓ MappingJSON 提取成功,长度: " + mappingJson.length() + " 字符");
System.out.println();
}
// 调用服务生成 XML
if (VERBOSE_LOG) {
System.out.println("正在转换 JSON 为 XML...");
}
IcdToXmlGenerateResult result = icdToXmlTaskAppService.generateXmlFromJson(mappingJson);
// 输出结果
printResult(result, objectMapper);
// 保存 XML 到磁盘
if (SAVE_XML_TO_DISK && result.getStatus() == GenerateStatus.SUCCESS) {
saveXmlToDisk(result.getMappingXml());
}
if (VERBOSE_LOG) {
System.out.println();
System.out.println("========== JSON 转 XML 调试结束 ==========");
}
} catch (Exception ex) {
throw new IllegalStateException("JSON 转 XML 调试失败:" + ex.getMessage(), ex);
}
}
/**
* 读取 JSON 文件内容。
*/
private static String readJsonFile() {
Path jsonPath = Paths.get(MMS_JSON_FILE_PATH);
if (!Files.exists(jsonPath)) {
throw new IllegalArgumentException("JSON 文件不存在:" + jsonPath.toAbsolutePath());
}
try {
byte[] bytes = Files.readAllBytes(jsonPath);
return new String(bytes, StandardCharsets.UTF_8);
} catch (Exception ex) {
throw new IllegalArgumentException("读取 JSON 文件失败:" + ex.getMessage(), ex);
}
}
/**
* 从 JSON 内容中提取 mappingJson。
* 支持两种格式:
* 1. 完整的 MappingTaskResponse JSON包含 mappingJson 字段)
* 2. 纯 mappingJson 字符串
*/
private static String extractMappingJson(String jsonContent, ObjectMapper objectMapper) {
try {
// 尝试解析为对象,看是否包含 mappingJson 字段
if (jsonContent.trim().startsWith("{")) {
java.util.Map<String, Object> jsonMap = objectMapper.readValue(
jsonContent,
java.util.Map.class
);
if (jsonMap.containsKey("mappingJson")) {
Object mappingJsonObj = jsonMap.get("mappingJson");
if (mappingJsonObj != null) {
return mappingJsonObj.toString();
}
}
}
// 如果不是对象或不包含 mappingJson则假设整个内容就是 mappingJson
return jsonContent;
} catch (Exception ex) {
// 如果解析失败,也假设整个内容就是 mappingJson
return jsonContent;
}
}
/**
* 打印转换结果。
*/
private static void printResult(IcdToXmlGenerateResult result, ObjectMapper objectMapper) {
System.out.println();
System.out.println("===== 转换结果 =====");
System.out.println("状态: " + result.getStatus());
System.out.println("消息: " + result.getMessage());
if (result.getProblems() != null && !result.getProblems().isEmpty()) {
System.out.println("问题列表:");
for (String problem : result.getProblems()) {
System.out.println(" - " + problem);
}
}
if (result.getStatus() == GenerateStatus.SUCCESS) {
System.out.println();
System.out.println("----- 生成的 XML 内容 -----");
String xmlContent = result.getMappingXml();
if (PRETTY_XML) {
// 简单格式化:每个标签独占一行
xmlContent = formatXml(xmlContent);
}
System.out.println(xmlContent);
System.out.println("--------------------------");
System.out.println();
System.out.println("XML 长度: " + result.getMappingXml().length() + " 字符");
}
}
/**
* 简单的 XML 格式化。
*/
private static String formatXml(String xml) {
if (xml == null || xml.isEmpty()) {
return xml;
}
// 在标签前后添加换行
String formatted = xml.replaceAll(">", ">\n")
.replaceAll("<", "\n<")
.replaceAll("\n\n", "\n");
// 简单的缩进处理
StringBuilder result = new StringBuilder();
int indentLevel = 0;
String[] lines = formatted.split("\n");
for (String line : lines) {
line = line.trim();
if (line.isEmpty()) {
continue;
}
// 如果是闭合标签,减少缩进
if (line.startsWith("</") && !line.endsWith("/>")) {
indentLevel = Math.max(0, indentLevel - 1);
}
// 添加缩进
for (int i = 0; i < indentLevel; i++) {
result.append(" ");
}
result.append(line).append("\n");
// 如果是开始标签且不是自闭合,增加缩进
if (line.startsWith("<") && !line.startsWith("</")
&& !line.endsWith("/>") && !line.endsWith(">")) {
indentLevel++;
}
}
return result.toString();
}
/**
* 保存 XML 到磁盘。
*/
private static void saveXmlToDisk(String xmlContent) {
try {
Path outputPath = Paths.get(OUTPUT_XML_PATH);
// 创建父目录
if (outputPath.getParent() != null && !Files.exists(outputPath.getParent())) {
Files.createDirectories(outputPath.getParent());
}
Files.write(outputPath, xmlContent.getBytes(StandardCharsets.UTF_8));
System.out.println("✓ XML 已保存到: " + outputPath.toAbsolutePath());
System.out.println(" 文件大小: " + Files.size(outputPath) + " 字节");
} catch (Exception ex) {
throw new IllegalStateException("保存 XML 文件失败:" + ex.getMessage(), ex);
}
}
private static ObjectMapper createObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
return objectMapper;
}
@SpringBootApplication(scanBasePackages = "com.njcn.gather.icd.mapping")
public static class DebugApplication {
}
}