docs(mms-mapping): 移除过时的 API 调试文档并优化代码注释

- 删除了过时的 getIcdMmsJson 标准 API 调试文档
- 为 GenerateMappingFromIcdRequest 类添加 Swagger 注解和 API 模型描述
- 更新 IndexBindingRequest、IndexCandidateReportItemResponse、IndexCandidateResponse
  和 IndexSelectionGroupRequest 类的注释和 Swagger 注解
- 为 IcdToXmlResponse 类添加完整的 Swagger 注解和 getter/setter 方法
- 在 MappingController 中添加新的 API 接口注释和参数说明
- 为 JsonToXmlRequest 类添加 API 模型注解和参数说明
- 在调试工具中增加 indexCandidates JSON 输出功能便于复制使用
This commit is contained in:
2026-05-06 11:40:52 +08:00
parent f69eed857f
commit f57fd45b47
14 changed files with 296 additions and 484 deletions

View File

@@ -1,371 +0,0 @@
# getIcdMmsJson 标准 API 调试文档
## 1. 文档范围
本文档用于说明 `mms-mapping` 模块统一调试接口 `getIcdMmsJson` 的标准调用方式、请求结构、响应规则和联调注意事项。
本文档内容以当前源码为准,主要对照以下实现:
- `tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/MappingController.java`
- `tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/MappingRequestConverter.java`
- `tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/MappingResponseConverter.java`
- `tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/service/impl/MappingTaskServiceImpl.java`
- `tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/MappingGenerationService.java`
- `tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/param/GenerateMappingFromIcdRequest.java`
- `tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/vo/MappingTaskResponse.java`
说明:
- 本文档仅描述接口契约和调试方式,不改动业务代码。
- 本次未执行 `mvn` 编译、打包或真实接口联调。
- 如文档与运行结果冲突,以源码和实际部署配置为准。
## 2. 接口基本信息
| 项 | 说明 |
| --- | --- |
| 接口名称 | `getIcdMmsJson` |
| 请求方法 | `POST` |
| 请求路径 | `/api/mms-mapping/get-icd-mms-json` |
| Content-Type | `multipart/form-data` |
| 控制器入口 | `MappingController#getIcdMmsJson` |
| 请求组成 | `icdFile` 文件 Part + `request` JSON Part |
| 正常业务响应体 | `MappingTaskResponse` |
## 3. 接口职责
该接口是 `mms-mapping` 模块的统一调试入口,串联以下两个阶段:
1. 上传 ICD 文件并完成解析,生成 `icdDocument``indexCandidates`
2. 根据 `request.indexSelection` 判断是否继续生成正式 `mappingJson`
接口行为分为三种典型结果:
1. `request.indexSelection` 未传或为空
返回 `NEED_INDEX_SELECTION`,用于引导前端或调试人员先确认标签与 `lnInst` 的绑定关系。
2. `request.indexSelection` 已传但校验不通过
返回 `NEED_INDEX_SELECTION`,同时通过 `problems` 给出不合法原因,要求重新选择。
3. `request.indexSelection` 校验通过
返回 `SUCCESS`,输出正式 `mappingJson`,必要时同时落盘并返回 `savedPath`
补充说明:
- 该接口每次都会重新解析上传的 ICD 文件,因此第二次调试仍然必须重新上传 ICD 文件。
- 该接口正常进入业务编排后,返回体类型为 `MappingTaskResponse`
- 如果异常发生在控制器参数绑定或请求转换阶段例如文件为空、Part 缺失、JSON Part 解析失败,则由全局异常处理器统一包装为 `HttpResult<String>`,而不是 `MappingTaskResponse`
## 4. 请求规范
### 4.1 multipart/form-data Part 说明
| Part 名称 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `icdFile` | File | 是 | ICD 文件,不能为空 |
| `request` | JSON Part | 是 | 生成参数,必须按 `application/json` 发送 |
说明:
- `request` Part 不能省略。即使第一次只想拿候选结果,也必须传一个最小 JSON。
- `request.indexSelection` 可以省略或传空数组,此时接口只返回候选结果,不生成正式映射。
### 4.2 request JSON 结构
```json
{
"version": "2026-04-22",
"author": "debug-user",
"saveToDisk": false,
"prettyJson": true,
"outputDir": "D:/temp/mms-output",
"indexSelection": [
{
"groupKey": "harm",
"groupDesc": "谐波数据",
"bindings": [
{
"reportName": "brcbStHarm",
"dataSetName": "dsStHarm",
"label": "A相",
"lnInst": "1"
}
]
}
]
}
```
### 4.3 request 字段说明
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `version` | String | 否 | 输出版本号。未传或空白时,后端按当天日期补齐,格式为 `yyyy-MM-dd` |
| `author` | String | 否 | 作者。未传或空白时,回退到配置项 `icd.mapping.default-author`,默认值为 `system` |
| `saveToDisk` | boolean | 否 | 是否将生成结果写入磁盘 |
| `prettyJson` | boolean | 否 | 是否输出格式化 JSON。`true` 为美化 JSON`false` 为紧凑 JSON |
| `outputDir` | String | 否 | 输出目录。未传或空白时,先回退到配置项 `icd.mapping.default-output-dir`;如果配置也为空,最终落到当前工作目录 |
| `indexSelection` | Array | 否 | 标签与 `lnInst` 的最终绑定关系。未传或为空时,只返回候选结果 |
### 4.4 indexSelection 字段说明
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `groupKey` | String | 是 | 分组唯一键,必须使用第一次响应里返回的原值 |
| `groupDesc` | String | 否 | 分组中文描述,便于调试查看 |
| `bindings` | Array | 是 | 当前业务分组下最终确认的绑定关系列表 |
### 4.5 bindings 字段说明
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `reportName` | String | 是 | 绑定发生在哪个报告上,例如 `brcbStHarm` |
| `dataSetName` | String | 是 | 绑定发生在哪个数据集上,例如 `dsStHarm` |
| `label` | String | 是 | 业务标签,例如 `A相``最大值``实时数据` |
| `lnInst` | String | 是 | 标签最终绑定到的逻辑节点实例值,例如 `1``2``3` |
## 5. 标准调试流程
### 5.1 第一次调试:只获取候选结果
用途:
- 上传 ICD 文件
- 获取 `icdDocument`
- 获取 `indexCandidates`
- 确认每个业务分组下可选的 `reportName``dataSetName``availableLnInstValues`
调用要求:
- `request` Part 仍然必须传
- `request.indexSelection` 可以不传,或传空数组
预期结果:
- `status = NEED_INDEX_SELECTION`
- 响应中返回 `icdDocument`
- 响应中返回 `indexCandidates`
### 5.2 第二次调试:带索引绑定生成正式结果
用途:
- 根据第一次返回的 `indexCandidates` 组装 `request.indexSelection`
- 再次上传同一个 ICD 文件
- 生成正式 `mappingJson`
调用要求:
- 必须继续上传 `icdFile`
- `groupKey` 必须沿用第一次返回值
- `reportName``dataSetName``lnInst` 必须与第一次返回的候选结果匹配
预期结果:
- `status = SUCCESS`
- 响应中返回 `mappingJson`
-`saveToDisk = true` 时,响应中额外返回 `savedPath`
### 5.3 第二次调试但绑定不合法
适用场景:
- `groupKey` 与候选结果不匹配
- `reportName``dataSetName` 不在候选集中
- `lnInst` 不在 `availableLnInstValues`
- 绑定关系缺失、不完整或结构错误
预期结果:
- `status = NEED_INDEX_SELECTION`
- 响应中仍然返回 `icdDocument``indexCandidates`
- `problems` 返回具体问题列表,要求重新确认绑定关系
## 6. 响应规范
### 6.1 正常业务响应体
接口正常进入业务编排后,统一返回 `MappingTaskResponse`。该对象使用了 `@JsonInclude(JsonInclude.Include.NON_EMPTY)`,空字段和空集合不会参与序列化。
基础字段说明:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `status` | Enum | 本次处理状态,可能为 `SUCCESS``NEED_INDEX_SELECTION``FAILED` |
| `message` | String | 状态说明或错误提示 |
| `icdDocument` | Object | 需要重新选择索引时返回的 ICD 解析结果 |
| `mappingJson` | String | 正式生成成功后的映射 JSON 文本 |
| `savedPath` | String | 结果已落盘时返回的绝对路径 |
| `indexCandidates` | Array | 待绑定状态下返回的索引候选分组 |
| `problems` | Array | 模板校验、候选分析或绑定校验问题 |
字段出现规则:
| 状态 | 必有字段 | 可能出现字段 |
| --- | --- | --- |
| `SUCCESS` | `status``message``mappingJson` | `savedPath``problems` |
| `NEED_INDEX_SELECTION` | `status``message``icdDocument``indexCandidates` | `problems` |
| `FAILED` | `status``message` | `problems` |
### 6.2 NEED_INDEX_SELECTION 响应示例
```json
{
"status": "NEED_INDEX_SELECTION",
"message": "索引配置缺失,请根据候选信息完成标签与数字索引的绑定后重新提交",
"icdDocument": {
"fileName": "demo.icd",
"iedName": "IED1",
"ldInst": "LD0",
"ldPrefix": "LD",
"logicalNodes": [
{
"lnInst": "1"
}
]
},
"indexCandidates": [
{
"groupKey": "harm",
"groupDesc": "谐波数据",
"reportCount": 1,
"templateLabels": [
"A相",
"B相",
"C相"
],
"reports": [
{
"reportName": "brcbStHarm",
"dataSetName": "dsStHarm",
"reportDesc": "谐波报告",
"availableLnInstValues": [
"1",
"2",
"3"
]
}
]
}
]
}
```
说明:
- `icdDocument` 实际字段可能比示例更多。
- 如果本次是“索引配置不合法”而不是“索引配置缺失”,通常还会返回 `problems`
### 6.3 SUCCESS 响应示例
```json
{
"status": "SUCCESS",
"message": "映射生成成功",
"mappingJson": "{\n \"version\": \"2026-04-22\",\n \"author\": \"debug-user\",\n \"ied\": \"IED1\",\n \"ld\": \"LD\",\n \"instList\": []\n}"
}
```
说明:
- `mappingJson` 是字符串字段,字段值本身是一段 JSON 文本。
-`saveToDisk = true` 时,响应中还会额外返回 `savedPath`
### 6.4 FAILED 响应示例
```json
{
"status": "FAILED",
"message": "映射生成失败:加载 DefaultCfg.txt 失败默认模板文件不存在template/DefaultCfg.txt",
"problems": [
"加载 DefaultCfg.txt 失败默认模板文件不存在template/DefaultCfg.txt"
]
}
```
说明:
- `FAILED` 主要对应服务编排阶段捕获到的运行异常,例如 ICD 解析、模板加载、映射生成、序列化或落盘失败。
- 并非所有错误都会进入 `FAILED`。如果异常发生在控制器参数绑定或请求转换阶段,会走全局异常处理器,而不是这里的业务响应结构。
## 7. 全局异常响应说明
以下场景通常不会返回 `MappingTaskResponse`,而是由 `GlobalBusinessExceptionHandler` 统一包装:
- `icdFile` 缺失或为空
- `request` Part 缺失
- `request` Part 的 `Content-Type` 不是 `application/json`
- `multipart/form-data` 结构不合法
- JSON 反序列化失败或框架参数绑定失败
这类异常最终会包装为统一的 `HttpResult<String>` 响应,具体字段结构以全局公共响应定义为准,本文不展开其完整协议,只强调:
- 不能把这类错误等同理解为 `MappingTaskResponse.status = FAILED`
- 联调时应先区分“业务响应体”与“全局异常包装”
## 8. 调试示例
### 8.1 curl 示例:第一次调用,只获取候选结果
```powershell
curl.exe -X POST "http://localhost:8080/api/mms-mapping/get-icd-mms-json" `
-H "Accept: application/json" `
-F 'icdFile=@D:/data/demo.icd' `
-F 'request={"prettyJson":true,"saveToDisk":false};type=application/json'
```
### 8.2 curl 示例:第二次调用,带索引绑定直接生成 MMS JSON
```powershell
curl.exe -X POST "http://localhost:8080/api/mms-mapping/get-icd-mms-json" `
-H "Accept: application/json" `
-F 'icdFile=@D:/data/demo.icd' `
-F 'request={"version":"2026-04-22","author":"debug-user","prettyJson":true,"saveToDisk":false,"indexSelection":[{"groupKey":"harm","groupDesc":"谐波数据","bindings":[{"reportName":"brcbStHarm","dataSetName":"dsStHarm","label":"A相","lnInst":"1"},{"reportName":"brcbStHarm","dataSetName":"dsStHarm","label":"B相","lnInst":"2"},{"reportName":"brcbStHarm","dataSetName":"dsStHarm","label":"C相","lnInst":"3"}]}]};type=application/json'
```
## 9. Postman 调试要点
1. `Body` 选择 `form-data`
2. `icdFile` 类型选择 `File`
3. `request` 保持文本输入,但该 Part 的 `Content-Type` 必须显式设置为 `application/json`
4. 第一次调试不要省略 `request` Part只是不传 `indexSelection`
5. 第二次调试时必须继续上传 ICD 文件,并严格按第一次返回的候选结果组装绑定关系
## 10. 常见问题
### 10.1 为什么第一次调试也必须传 `request`
因为控制器方法签名使用的是 `@RequestPart("request") GenerateMappingFromIcdRequest request`,该 Part 本身就是必填参数。第一次调试可以只传最小 JSON但不能完全省略。
### 10.2 为什么没有传 `indexSelection`,却没有返回 `FAILED`
这是接口设计的正常行为。`indexSelection` 缺失或为空时,业务语义不是“接口执行失败”,而是“还需要前端继续确认索引绑定”,因此返回的是 `NEED_INDEX_SELECTION`
### 10.3 `saveToDisk=true` 但没有传 `outputDir`,结果会保存到哪里
处理顺序如下:
1. 先读取请求中的 `outputDir`
2. 如果请求空白,则回退到配置项 `icd.mapping.default-output-dir`
3. 如果配置项也为空,则最终落到当前工作目录
### 10.4 `version` 不传时会变成什么
后端在正式生成映射文档时,会把空白 `version` 自动补成当天日期,格式为 `yyyy-MM-dd`
### 10.5 `mappingJson` 为什么是字符串,不是嵌套对象
因为当前响应结构中 `mappingJson` 定义为 `String`,接口返回的是一段已经序列化好的 JSON 文本,而不是再次展开后的对象结构。
### 10.6 什么情况下会返回 `problems`
`problems` 主要用于承载以下问题:
- 默认模板校验问题
- 索引候选分析问题
- `indexSelection` 绑定校验问题
- 服务编排阶段捕获到的异常原因
## 11. 当前边界
- 当前文档仅覆盖 `getIcdMmsJson` 接口,不覆盖 `get-icd``get-mms-json` 的独立接口文档
- 当前文档重点描述业务返回体与调试方式,不展开全局 `HttpResult` 的完整协议
- 示例中的 `icdDocument``indexCandidates``mappingJson` 为结构化示意,实际字段数量与内容以运行结果为准

View File

@@ -2,6 +2,11 @@
`mms-mapping` 模块负责解析 ICD 文件并生成 MMS 映射数据。当前统一调试入口为 `getIcdMmsJson`,该接口同时覆盖“先解析 ICD 获取索引候选”和“确认索引后生成正式 MMS JSON”两类场景。
## 0. 调试文档
- `getIcdMmsJson``API-getIcdMmsJson.md`
- `buildIndexConfirmData` / `buildIndexSelection``API-buildIndexDebug.md`
## 1. 接口信息
- 路径:`POST /api/mms-mapping/get-icd-mms-json`

View File

@@ -2,26 +2,36 @@ package com.njcn.gather.icd.mapping.controller;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.LogUtil;
import com.njcn.gather.icd.mapping.component.IcdToXmlRequestConverter;
import com.njcn.gather.icd.mapping.component.IcdToXmlResponseConverter;
import com.njcn.gather.icd.mapping.component.IndexSelectionBuildService;
import com.njcn.gather.icd.mapping.component.MappingRequestConverter;
import com.njcn.gather.icd.mapping.component.MappingResponseConverter;
import com.njcn.gather.icd.mapping.pojo.bo.GenerateMappingResult;
import com.njcn.gather.icd.mapping.pojo.bo.IcdToXmlGenerateResult;
import com.njcn.gather.icd.mapping.pojo.dto.GenerateFromIcdCommand;
import com.njcn.gather.icd.mapping.pojo.dto.IcdToXmlGenerateCommand;
import com.njcn.gather.icd.mapping.pojo.param.BuildIndexSelectionRequest;
import com.njcn.gather.icd.mapping.pojo.param.GenerateMappingFromIcdRequest;
import com.njcn.gather.icd.mapping.pojo.param.IcdToXmlGenerateRequest;
import com.njcn.gather.icd.mapping.pojo.param.IndexCandidateRequest;
import com.njcn.gather.icd.mapping.pojo.param.JsonToXmlRequest;
import com.njcn.gather.icd.mapping.pojo.param.SubmitIndexSelectionRequest;
import com.njcn.gather.icd.mapping.pojo.vo.IcdToXmlResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexConfirmGroupResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexSelectionGroupResponse;
import com.njcn.gather.icd.mapping.pojo.vo.MappingTaskResponse;
import com.njcn.gather.icd.mapping.service.MappingTaskService;
import com.njcn.gather.icd.mapping.service.impl.IcdToXmlTaskAppService;
import com.njcn.gather.icd.mapping.utils.DateUtils;
import com.njcn.web.controller.BaseController;
import com.njcn.web.utils.HttpResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -33,6 +43,8 @@ import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* ICD 映射接口入口。
*/
@@ -61,11 +73,15 @@ public class MappingController extends BaseController {
/** 响应转换器,按接口阶段裁剪最小返回字段。 */
private final IcdToXmlTaskAppService icdToXmlTaskAppService;
/** ICD 结构确认弹窗结果组装服务。 */
private final IndexSelectionBuildService indexSelectionBuildService;
/**
* 上传 ICD 文件,返回候选结果和可编辑的 ICD 解析结果。
*/
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("上传 ICD 文件并生成索引候选")
@ApiImplicitParam(name = "icdFile", value = "ICD 文件", required = true, dataType = "__file", paramType = "form")
@PostMapping(value = "/get-icd", consumes = {"multipart/form-data"})
public MappingTaskResponse getICD(@RequestPart("icdFile") MultipartFile icdFile) {
String methodDescribe = getMethodDescribe("getICD");
@@ -80,6 +96,7 @@ public class MappingController extends BaseController {
*/
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("获取 MMS JSON")
@ApiImplicitParam(name = "request", value = "索引确认后生成 MMS JSON 参数", required = true, dataType = "SubmitIndexSelectionRequest")
@PostMapping("/get-mms-json")
public MappingTaskResponse getMmsJson(@Validated @RequestBody SubmitIndexSelectionRequest request) {
String methodDescribe = getMethodDescribe("getMmsJson");
@@ -95,6 +112,10 @@ public class MappingController extends BaseController {
*/
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("上传 ICD 后直接获取 MMS JSON")
@ApiImplicitParams({
@ApiImplicitParam(name = "icdFile", value = "ICD 文件", required = true, dataType = "__file", paramType = "form"),
@ApiImplicitParam(name = "request", value = "上传 ICD 后直接生成映射参数", required = true, dataType = "GenerateMappingFromIcdRequest", paramType = "form")
})
@PostMapping(value = "/get-icd-mms-json", consumes = {"multipart/form-data"})
public MappingTaskResponse getIcdMmsJson(@RequestPart("icdFile") MultipartFile icdFile,
@Validated @RequestPart("request") GenerateMappingFromIcdRequest request) {
@@ -107,12 +128,45 @@ public class MappingController extends BaseController {
return responseConverter.fromSubmitResult(result);
}
/**
* 根据页面回传的 indexCandidates 生成弹窗确认模型。
*/
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("根据 indexCandidates 生成确认数据")
@ApiImplicitParam(name = "indexCandidates", value = "索引候选分组列表", required = true, dataType = "List")
@PostMapping("/build-index-confirm-data")
public HttpResult<List<IndexConfirmGroupResponse>> buildIndexConfirmData(@RequestBody List<IndexCandidateRequest> indexCandidates) {
String methodDescribe = getMethodDescribe("buildIndexConfirmData");
LogUtil.njcnDebug(log, "{},开始根据 indexCandidates 生成确认数据candidateCount={}",
methodDescribe, indexCandidates == null ? 0 : indexCandidates.size());
List<IndexConfirmGroupResponse> result = indexSelectionBuildService.buildConfirmData(indexCandidates);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
}
/**
* 根据前端确认后的结果生成最终 indexSelection。
*/
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("根据确认结果生成 indexSelection")
@ApiImplicitParam(name = "request", value = "根据确认结果生成 indexSelection 参数", required = true, dataType = "BuildIndexSelectionRequest")
@PostMapping("/build-index-selection")
public HttpResult<List<IndexSelectionGroupResponse>> buildIndexSelection(@RequestBody BuildIndexSelectionRequest request) {
String methodDescribe = getMethodDescribe("buildIndexSelection");
LogUtil.njcnDebug(log, "{},开始根据确认结果生成 indexSelectionconfirmGroupCount={}, confirmedGroupCount={}",
methodDescribe,
request == null || request.getConfirmData() == null ? 0 : request.getConfirmData().size(),
request == null || request.getConfirmedData() == null ? 0 : request.getConfirmedData().size());
List<IndexSelectionGroupResponse> result = indexSelectionBuildService.buildIndexSelection(request);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
}
/**
* 直接将 MMS JSON 转换为 XML 文件。
* 适用于已经通过 getIcdMmsJson 获得 JSON 后,单独进行 XML 转换的场景。
*/
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("MMS JSON 转 XML")
@ApiImplicitParam(name = "request", value = "MMS JSON 转 XML 参数", required = true, dataType = "JsonToXmlRequest")
@PostMapping("/get-xml-from-json")
public IcdToXmlResponse getXmlFromJson(@Validated @RequestPart("request") JsonToXmlRequest request) {
String methodDescribe = getMethodDescribe("getXmlFromJson");

View File

@@ -1,38 +1,43 @@
package com.njcn.gather.icd.mapping.pojo.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 候选接口请求体
*
* 当前主要承载输出版本、作者、落盘选项等基础参数。
* 为兼容旧调用,仍保留 indexSelection 字段,但候选接口本身不依赖该字段。
* 上传 ICD 后直接生成映射的请求参数
*/
@Data
@ApiModel("上传 ICD 后直接生成映射的请求参数")
public class GenerateMappingFromIcdRequest {
/** 输出版本号。为空时后端默认补当天日期。 */
/** 映射版本号。 */
@ApiModelProperty("映射版本号,空时默认使用当天日期")
private String version;
/** 作者。为空时使用模块默认作者。 */
/** 映射作者。 */
@ApiModelProperty("映射作者,空时使用模块默认作者")
private String author;
/** 是否保存到磁盘。 */
/** 是否盘。 */
@ApiModelProperty("是否将生成结果落盘保存")
private boolean saveToDisk;
/** 是否返回格式化 JSON。 */
/** 是否格式化 JSON。 */
@ApiModelProperty("是否返回格式化后的 JSON")
private boolean prettyJson;
/** 输出目录。saveToDisk=true 时才会用到。 */
/** 输出目录。 */
@ApiModelProperty("输出目录,仅在 saveToDisk=true 时生效")
private String outputDir;
/**
* 兼容保留的索引选择结果。
*
* 当前候选接口会直接返回 indexCandidates 和 icdDocument
* 正式提交时请改用 get-mms-json 接口。
* 兼容保留的索引绑定结果。
* 正式提交流程建议改用 get-mms-json 接口。
*/
@ApiModelProperty("兼容保留的索引绑定结果,正式提交建议改用 get-mms-json 接口")
private List<IndexSelectionGroupRequest> indexSelection = new ArrayList<IndexSelectionGroupRequest>();
}
}

View File

@@ -1,24 +1,29 @@
package com.njcn.gather.icd.mapping.pojo.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 单条索引绑定请求。
*
* 一条绑定只表达一个最小关系:
* 某个报告 reportName 下,使用某个标签 label 与某个 lnInst 数字做绑定。
* 单条索引绑定请求
*/
@Data
@ApiModel("单条索引绑定请求项")
public class IndexBindingRequest {
/** 绑定发生在哪个报告上,例如 brcbStHarm。 */
/** 报告名称。 */
@ApiModelProperty("报告名称")
private String reportName;
/** 绑定发生在哪个数据集上,例如 dsStHarm。 */
/** 数据集名称。 */
@ApiModelProperty("数据集名称")
private String dataSetName;
/** 业务标签,例如最大值、最小值、实时数据。 */
/** 模板标签。 */
@ApiModelProperty("模板标签")
private String label;
/** 当前标签最终绑定的 lnInst 数字,例如 1、2、3。 */
/** 最终绑定的 lnInst 。 */
@ApiModelProperty("最终绑定的 lnInst 值")
private String lnInst;
}
}

View File

@@ -1,28 +1,28 @@
package com.njcn.gather.icd.mapping.pojo.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 单个业务分组的索引选择请求。
*
* 用于回传某个业务分组下,前端最终确认的多条绑定关系。
* 单个业务分组的索引选择请求参数
*/
@Data
@ApiModel("单个业务分组的索引选择请求参数")
public class IndexSelectionGroupRequest {
/**
* 分组唯一键。
*
* 该值由后端在 NEED_INDEX_SELECTION 场景返回,前端应原样回传,
* 避免仅依赖中文描述做匹配。
*/
/** 分组唯一键。 */
@ApiModelProperty("分组唯一键,需原样回传后端返回值")
private String groupKey;
/** 分组中文描述,例如“实时数据”“统计数据”。 */
/** 分组中文描述。 */
@ApiModelProperty("分组中文描述")
private String groupDesc;
/** 当前业务分组下,用户最终确认的绑定关系。 */
/** 当前分组最终确认的绑定关系。 */
@ApiModelProperty("当前分组最终确认的绑定关系")
private List<IndexBindingRequest> bindings = new ArrayList<IndexBindingRequest>();
}
}

View File

@@ -1,25 +1,18 @@
package com.njcn.gather.icd.mapping.pojo.param;
import java.util.ArrayList;
import java.util.List;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* JSON 转 XML 请求参数。
* MMS JSON 转 XML 请求参数。
*/
@ApiModel("MMS JSON 转 XML 的请求参数")
public class JsonToXmlRequest {
/**
* MMS 映射 JSON 字符串。
* 由 getIcdMmsJson 接口返回的 mappingJson 字段提供。
*/
/** MMS 映射 JSON 字符串。 */
@ApiModelProperty(value = "MMS 映射 JSON 字符串", required = true)
private String mappingJson;
/**
* 索引选择结果(用于重建索引映射配置)。
* 如果提供了 indexSelection则会重新构建索引映射
* 如果为空,则使用默认的索引映射配置。
*/
public String getMappingJson() {
return mappingJson;
}
@@ -27,6 +20,4 @@ public class JsonToXmlRequest {
public void setMappingJson(String mappingJson) {
this.mappingJson = mappingJson;
}
}

View File

@@ -1,37 +1,45 @@
package com.njcn.gather.icd.mapping.pojo.param;
import lombok.Data;
import com.njcn.gather.icd.mapping.pojo.bo.icd.IcdDocument;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 提交索引绑定并生成映射的请求
*
* 第二个接口不再重复上传 ICD 文件,而是直接接收前端确认或修改后的 ICD 解析结果。
* 提交索引绑定并生成 MMS JSON 的请求参数
*/
@Data
@ApiModel("提交索引绑定并生成 MMS JSON 的请求参数")
public class SubmitIndexSelectionRequest {
/** 前端基于候选接口返回值确认或修改后的 ICD 解析结果。 */
/** ICD 解析结果。 */
@ApiModelProperty("ICD 解析结果,通常来自候选接口返回")
private IcdDocument icdDocument;
/** 输出版本号。为空时后端默认补当天日期。 */
/** 映射版本号。 */
@ApiModelProperty("映射版本号,空时默认使用当天日期")
private String version;
/** 作者。为空时使用模块默认作者。 */
/** 映射作者。 */
@ApiModelProperty("映射作者,空时使用模块默认作者")
private String author;
/** 是否保存到磁盘。 */
/** 是否盘。 */
@ApiModelProperty("是否将生成结果落盘保存")
private boolean saveToDisk;
/** 是否返回格式化 JSON。 */
/** 是否格式化 JSON。 */
@ApiModelProperty("是否返回格式化后的 JSON")
private boolean prettyJson;
/** 输出目录。saveToDisk=true 时才会用到。 */
/** 输出目录。 */
@ApiModelProperty("输出目录,仅在 saveToDisk=true 时生效")
private String outputDir;
/** 用户最终确认的索引绑定关系。 */
@ApiModelProperty("用户最终确认的索引绑定关系")
private List<IndexSelectionGroupRequest> indexSelection = new ArrayList<IndexSelectionGroupRequest>();
}
}

View File

@@ -1,36 +1,103 @@
package com.njcn.gather.icd.mapping.pojo.vo;
import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.ArrayList;
import java.util.List;
// 手动写getter/setter避免Lombok依赖问题
/**
* MMS JSON 转 XML 的响应。
*/
@ApiModel("MMS JSON 转 XML 的响应")
public class IcdToXmlResponse {
private GenerateStatus status;
private String message;
private String iedName;
private String ldInst;
private String savedPath;
private MappingDocumentResponse mappingDocument;
private List<IndexCandidateResponse> indexCandidates = new ArrayList<IndexCandidateResponse>();
private List<String> problems = new ArrayList<String>();
public GenerateStatus getStatus() { return status; }
public void setStatus(GenerateStatus status) { this.status = status; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public String getIedName() { return iedName; }
public void setIedName(String iedName) { this.iedName = iedName; }
public String getLdInst() { return ldInst; }
public void setLdInst(String ldInst) { this.ldInst = ldInst; }
public String getSavedPath() { return savedPath; }
public void setSavedPath(String savedPath) { this.savedPath = savedPath; }
public MappingDocumentResponse getMappingDocument() { return mappingDocument; }
public void setMappingDocument(MappingDocumentResponse mappingDocument) { this.mappingDocument = mappingDocument; }
public List<IndexCandidateResponse> getIndexCandidates() { return indexCandidates; }
public void setIndexCandidates(List<IndexCandidateResponse> indexCandidates) { this.indexCandidates = indexCandidates; }
public List<String> getProblems() { return problems; }
public void setProblems(List<String> problems) { this.problems = problems; }
}
@ApiModelProperty("本次接口处理状态")
private GenerateStatus status;
@ApiModelProperty("状态说明或错误提示")
private String message;
@ApiModelProperty("IED 名称")
private String iedName;
@ApiModelProperty("逻辑设备实例名")
private String ldInst;
@ApiModelProperty("落盘后的绝对路径")
private String savedPath;
@ApiModelProperty("生成后的映射文档摘要")
private MappingDocumentResponse mappingDocument;
@ApiModelProperty("索引候选分组,存在待确认场景时返回")
private List<IndexCandidateResponse> indexCandidates = new ArrayList<IndexCandidateResponse>();
@ApiModelProperty("处理过程中发现的问题列表")
private List<String> problems = new ArrayList<String>();
public GenerateStatus getStatus() {
return status;
}
public void setStatus(GenerateStatus status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getIedName() {
return iedName;
}
public void setIedName(String iedName) {
this.iedName = iedName;
}
public String getLdInst() {
return ldInst;
}
public void setLdInst(String ldInst) {
this.ldInst = ldInst;
}
public String getSavedPath() {
return savedPath;
}
public void setSavedPath(String savedPath) {
this.savedPath = savedPath;
}
public MappingDocumentResponse getMappingDocument() {
return mappingDocument;
}
public void setMappingDocument(MappingDocumentResponse mappingDocument) {
this.mappingDocument = mappingDocument;
}
public List<IndexCandidateResponse> getIndexCandidates() {
return indexCandidates;
}
public void setIndexCandidates(List<IndexCandidateResponse> indexCandidates) {
this.indexCandidates = indexCandidates;
}
public List<String> getProblems() {
return problems;
}
public void setProblems(List<String> problems) {
this.problems = problems;
}
}

View File

@@ -1,27 +1,34 @@
package com.njcn.gather.icd.mapping.pojo.vo;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 业务分组下的单个报告候选响应。
* 索引候选中的单个报告响应
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModel("索引候选中的单个报告响应项")
public class IndexCandidateReportItemResponse {
/** 报告名称。 */
@ApiModelProperty("报告名称")
private String reportName;
/** 数据集名称。 */
@ApiModelProperty("数据集名称")
private String dataSetName;
/** 报告描述。 */
@ApiModelProperty("报告描述")
private String reportDesc;
/** 当前报告可选的 `lnInst` 数值。 */
/** 当前报告可选的 lnInst 值列表。 */
@ApiModelProperty("当前报告可选的 lnInst 值列表")
private List<String> availableLnInstValues = new ArrayList<String>();
}
}

View File

@@ -1,33 +1,38 @@
package com.njcn.gather.icd.mapping.pojo.vo;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 索引候选响应对象
*
* 一个候选对应一个业务分组,分组下可包含多个报告,
* 前端据此完成模板标签与 `lnInst` 的人工绑定。
* 索引候选分组响应。
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModel("索引候选分组响应")
public class IndexCandidateResponse {
/** 分组唯一键。 */
@ApiModelProperty("分组唯一键")
private String groupKey;
/** 分组中文描述。 */
@ApiModelProperty("分组中文描述")
private String groupDesc;
/** 当前分组包含的报告数。 */
/** 当前分组包含的报告数。 */
@ApiModelProperty("当前分组包含的报告数量")
private int reportCount;
/** 模板配置的可选标签。 */
/** 模板配置的可选标签。 */
@ApiModelProperty("模板中配置的可选标签")
private List<String> templateLabels = new ArrayList<String>();
/** 当前分组下的报告候选列表。 */
@ApiModelProperty("当前分组下的报告候选列表")
private List<IndexCandidateReportItemResponse> reports = new ArrayList<IndexCandidateReportItemResponse>();
}
}

View File

@@ -1,28 +1,37 @@
package com.njcn.gather.icd.mapping.pojo.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 映射文档摘要响应。
*
* 用于返回最终映射结果中的关键信息摘要。
*/
@Data
@ApiModel("映射文档摘要响应")
public class MappingDocumentResponse {
/** 映射文档版本。 */
@ApiModelProperty("映射文档版本")
private String version;
/** 映射文档作者。 */
@ApiModelProperty("映射文档作者")
private String author;
/** 输出 JSON 中的 IED。 */
@ApiModelProperty("输出 JSON 中的 IED")
private String ied;
/** 输出 JSON 中的 LD。 */
@ApiModelProperty("输出 JSON 中的 LD")
private String ld;
/** ReportMap 条目数量。 */
@ApiModelProperty("ReportMap 条目数量")
private int reportCount;
/** DataSetList 分组数量。 */
@ApiModelProperty("DataSetList 分组数量")
private int dataSetCount;
}

View File

@@ -1,39 +1,48 @@
package com.njcn.gather.icd.mapping.pojo.vo;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.njcn.gather.icd.mapping.pojo.bo.icd.IcdDocument;
import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* ICD 映射接口统一响应。
*
* 按接口阶段仅返回当前场景必需字段;空字段和空集合不参与序列化。
* ICD 映射统一响应。
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModel("ICD 映射统一响应")
public class MappingTaskResponse {
/** 本次接口处理状态。 */
@ApiModelProperty("本次接口处理状态")
private GenerateStatus status;
/** 状态说明或错误提示。 */
@ApiModelProperty("状态说明或错误提示")
private String message;
/** 候选接口或需要重新选择索引时返回的 ICD 解析结果。 */
/** ICD 解析结果。 */
@ApiModelProperty("ICD 解析结果,在需要确认索引时返回")
private IcdDocument icdDocument;
/** 正式生成成功后的完整映射 JSON。 */
@ApiModelProperty("正式生成成功后的完整映射 JSON")
private String mappingJson;
/** 生成文件落盘后的绝对路径。 */
/** 落盘后的绝对路径。 */
@ApiModelProperty("落盘后的绝对路径")
private String savedPath;
/** 待绑定状态下返回的索引候选分组。 */
@ApiModelProperty("待绑定状态下返回的索引候选分组")
private List<IndexCandidateResponse> indexCandidates = new ArrayList<IndexCandidateResponse>();
/** 模板校验、候选分析或绑定校验问题。 */
@ApiModelProperty("模板校验、候选分析或绑定校验问题")
private List<String> problems = new ArrayList<String>();
}
}

View File

@@ -69,6 +69,7 @@ public class GetIcdMmsJsonDebugRunner {
MappingTaskResponse firstResponse = debugNeedIndexSelection(mappingTaskService, responseConverter);
printResponse("第一次调试:获取索引候选", firstResponse, objectMapper);
printIndexCandidatesJson(firstResponse, objectMapper);
printIndexCandidateSummary(firstResponse);
if (!RUN_SECOND_STEP) {
@@ -192,6 +193,23 @@ public class GetIcdMmsJsonDebugRunner {
}
}
/**
* 单独输出 indexCandidates 的 JSON便于直接复制做第二次调试绑定。
*/
private static void printIndexCandidatesJson(MappingTaskResponse response, ObjectMapper objectMapper) {
try {
System.out.println();
System.out.println("===== indexCandidates JSON =====");
if (response == null) {
System.out.println("null");
return;
}
System.out.println(objectMapper.writeValueAsString(response.getIndexCandidates()));
} catch (Exception ex) {
throw new IllegalArgumentException("print indexCandidates JSON failed: " + ex.getMessage(), ex);
}
}
private static void printResponse(String title, MappingTaskResponse response, ObjectMapper objectMapper) {
try {
System.out.println();