From 82fdd7664b25d86625fb47b2e13a62f79e1f221e Mon Sep 17 00:00:00 2001 From: caozehui <2427765068@qq.com> Date: Tue, 16 Jun 2026 19:25:43 +0800 Subject: [PATCH] =?UTF-8?q?icd=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- detection/pom.xml | 7 +- .../icd/controller/PqIcdPathController.java | 62 ++- .../gather/icd/mapper/PqIcdPathMapper.java | 17 + .../icd/mapper/mapping/PqIcdPathMapper.xml | 107 ++++- .../icd/pojo/enums/IcdResponseEnum.java | 27 +- .../gather/icd/pojo/param/PqIcdPathParam.java | 73 +++- .../njcn/gather/icd/pojo/po/PqIcdPath.java | 57 ++- .../gather/icd/service/IPqIcdPathService.java | 27 +- .../service/impl/PqIcdPathServiceImpl.java | 396 +++++++++++------- .../service/support/IcdArchiveBuilder.java | 62 +++ .../service/support/IcdPayloadAssembler.java | 90 ++++ .../service/support/IcdPayloadValidator.java | 66 +++ entrance/src/main/resources/application.yml | 3 + 13 files changed, 793 insertions(+), 201 deletions(-) create mode 100644 detection/src/main/java/com/njcn/gather/icd/service/support/IcdArchiveBuilder.java create mode 100644 detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadAssembler.java create mode 100644 detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadValidator.java diff --git a/detection/pom.xml b/detection/pom.xml index 2ee75920..1a346a4d 100644 --- a/detection/pom.xml +++ b/detection/pom.xml @@ -145,7 +145,12 @@ activate-tool 1.0.0 + + org.springframework.boot + spring-boot-starter-test + test + - \ No newline at end of file + diff --git a/detection/src/main/java/com/njcn/gather/icd/controller/PqIcdPathController.java b/detection/src/main/java/com/njcn/gather/icd/controller/PqIcdPathController.java index f30566ca..d6a087f4 100644 --- a/detection/src/main/java/com/njcn/gather/icd/controller/PqIcdPathController.java +++ b/detection/src/main/java/com/njcn/gather/icd/controller/PqIcdPathController.java @@ -18,12 +18,18 @@ import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.util.UriUtils; +import javax.validation.Valid; +import java.nio.charset.StandardCharsets; import java.util.List; - /** * @author caozehui * @date 2025-02-10 @@ -38,7 +44,7 @@ public class PqIcdPathController extends BaseController { @OperateInfo(info = LogEnum.BUSINESS_COMMON) @GetMapping("/listAll") - @ApiOperation("获取所有icd") + @ApiOperation("获取全部icd") public HttpResult> listAll() { String methodDescribe = getMethodDescribe("listAll"); List result = pqIcdPathService.listAll(); @@ -60,7 +66,7 @@ public class PqIcdPathController extends BaseController { @PostMapping("/add") @ApiOperation("新增icd") @ApiImplicitParam(name = "param", value = "icd新增参数", required = true) - public HttpResult add(PqIcdPathParam param) { + public HttpResult add(@Validated PqIcdPathParam.CreateParam param) { String methodDescribe = getMethodDescribe("add"); LogUtil.njcnDebug(log, "{},新增数据为:{}", methodDescribe, param); @@ -72,11 +78,27 @@ public class PqIcdPathController extends BaseController { } } + @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD) + @PostMapping("/external/add") + @ApiOperation("外部系统新增icd") + @ApiImplicitParam(name = "param", value = "外部系统icd新增参数", required = true) + public HttpResult externalAdd(@RequestBody List param) { + String methodDescribe = getMethodDescribe("externalAdd"); + LogUtil.njcnDebug(log, "{},外部新增数据为:{}", methodDescribe, param); + + boolean result = pqIcdPathService.addUpstreamIcd(param); + if (result) { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe); + } else { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, false, methodDescribe); + } + } + @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.UPDATE) @PostMapping("/update") @ApiOperation("修改icd") @ApiImplicitParam(name = "param", value = "icd修改参数", required = true) - public HttpResult update(PqIcdPathParam.UpdateParam param) { + public HttpResult update(@Validated PqIcdPathParam.UpdateParam param) { String methodDescribe = getMethodDescribe("update"); LogUtil.njcnDebug(log, "{},修改数据为:{}", methodDescribe, param); @@ -88,6 +110,24 @@ public class PqIcdPathController extends BaseController { } } + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @GetMapping("/standard-list") + @ApiOperation("获取标准ICD列表") + public HttpResult> standardList() { + String methodDescribe = getMethodDescribe("standardList"); + List result = pqIcdPathService.listStandardIcd(); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe); + } + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @GetMapping("/getById") + @ApiOperation("根据id获取ICD详情") + public HttpResult getById(@RequestParam String id) { + String methodDescribe = getMethodDescribe("getById"); + PqIcdPath result = pqIcdPathService.getIcdById(id); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe); + } + @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.DELETE) @PostMapping("/delete") @ApiOperation("删除icd") @@ -103,5 +143,17 @@ public class PqIcdPathController extends BaseController { } } + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @GetMapping("/export/{id}") + @ApiOperation("导出icd") + public ResponseEntity export(@PathVariable String id) { + PqIcdPath detail = pqIcdPathService.getIcdById(id); + byte[] body = pqIcdPathService.exportIcd(id); + String fileName = UriUtils.encode(detail.getName() + ".zip", StandardCharsets.UTF_8); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + fileName) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .contentLength(body.length) + .body(new ByteArrayResource(body)); + } } - diff --git a/detection/src/main/java/com/njcn/gather/icd/mapper/PqIcdPathMapper.java b/detection/src/main/java/com/njcn/gather/icd/mapper/PqIcdPathMapper.java index 9072150a..c1616ecd 100644 --- a/detection/src/main/java/com/njcn/gather/icd/mapper/PqIcdPathMapper.java +++ b/detection/src/main/java/com/njcn/gather/icd/mapper/PqIcdPathMapper.java @@ -1,9 +1,12 @@ package com.njcn.gather.icd.mapper; import com.github.yulichang.base.MPJBaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.njcn.gather.icd.pojo.po.PqIcdPath; import org.apache.ibatis.annotations.Param; +import java.util.List; + /** * @author caozehui * @date 2025-02-10 @@ -17,5 +20,19 @@ public interface PqIcdPathMapper extends MPJBaseMapper { * @return */ PqIcdPath selectIcdByDevType(@Param("devTypeId") String devTypeId); + + List selectPageList(Page page, @Param("name") String name); + + List selectStandardList(); + + PqIcdPath selectStandardByName(@Param("name") String name); + + List selectByIdsWithoutBlob(@Param("ids") List ids); + + Long countActiveReferencesToStandards(@Param("standardIds") List standardIds); + + PqIcdPath selectDetailById(@Param("id") String id); + + PqIcdPath selectExportById(@Param("id") String id); } diff --git a/detection/src/main/java/com/njcn/gather/icd/mapper/mapping/PqIcdPathMapper.xml b/detection/src/main/java/com/njcn/gather/icd/mapper/mapping/PqIcdPathMapper.xml index ec38e399..759c3a28 100644 --- a/detection/src/main/java/com/njcn/gather/icd/mapper/mapping/PqIcdPathMapper.xml +++ b/detection/src/main/java/com/njcn/gather/icd/mapper/mapping/PqIcdPathMapper.xml @@ -4,10 +4,115 @@ + + + + + + + + + + + + + + diff --git a/detection/src/main/java/com/njcn/gather/icd/pojo/enums/IcdResponseEnum.java b/detection/src/main/java/com/njcn/gather/icd/pojo/enums/IcdResponseEnum.java index 770e853c..ba7ead7a 100644 --- a/detection/src/main/java/com/njcn/gather/icd/pojo/enums/IcdResponseEnum.java +++ b/detection/src/main/java/com/njcn/gather/icd/pojo/enums/IcdResponseEnum.java @@ -1,16 +1,37 @@ package com.njcn.gather.icd.pojo.enums; +import lombok.Getter; + /** * @author caozehui * @data 2025-11-11 */ +@Getter public enum IcdResponseEnum { FILE_NOT_NULL("A018001", "映射文件不能为空"), FILE_TYPE_ERROR("A018002", "映射文件类型错误"), - FILE_SIZE_ERROR("A018003", "映射文件大小超出限制"); + FILE_SIZE_ERROR("A018003", "映射文件大小超出限制"), + ICD_FILE_NOT_NULL("A018004", "ICD原始文件不能为空"), + ICD_FILE_TYPE_ERROR("A018005", "ICD原始文件类型错误"), + ICD_FILE_READ_ERROR("A018006", "ICD原始文件读取失败"), + JSON_FORMAT_ERROR("A018007", "JSON格式错误"), + XML_FORMAT_ERROR("A018008", "XML格式错误"), + STANDARD_ICD_IN_USE("A018009", "该标准ICD已被非标准ICD引用,禁止删除"), + ICD_FILE_NOT_FOUND("A018010", "ICD原始文件不存在"), + ICD_EXPORT_FAILED("A018011", "ICD导出失败"), + ICD_NOT_FOUND("A018012", "ICD不存在"), + RESULT_NOT_NULL("A018013", "结论不能为空"), + MSG_NOT_BLANK("A018014", "当结论为否时,描述不能为空"), + TYPE_NOT_NULL("A018015", "ICD类型不能为空"), + TYPE_VALUE_ERROR("A018016", "ICD类型取值错误"), + REFERENCE_ICD_NOT_BLANK("A018017", "非标准ICD必须选择参照标准ICD"), + REFERENCE_ICD_INVALID("A018018", "参照标准ICD无效"), + GENERATE_FILE("A018019", "文件生成失败"), + ICD_TXT_SYNC_FAILED("A018020", "ICD txt文件同步失败"), + REFERENCE_STANDARD_ICD_NAME_NOT_FOUND("A018021", "参照标准ICD名称不存在"); - private String code; - private String message; + private final String code; + private final String message; IcdResponseEnum(String code, String message) { this.code = code; diff --git a/detection/src/main/java/com/njcn/gather/icd/pojo/param/PqIcdPathParam.java b/detection/src/main/java/com/njcn/gather/icd/pojo/param/PqIcdPathParam.java index ebcc884f..ef926b85 100644 --- a/detection/src/main/java/com/njcn/gather/icd/pojo/param/PqIcdPathParam.java +++ b/detection/src/main/java/com/njcn/gather/icd/pojo/param/PqIcdPathParam.java @@ -17,39 +17,63 @@ import javax.validation.constraints.Pattern; */ @Data public class PqIcdPathParam { - @ApiModelProperty(value = "名称", required = true) - @NotBlank(message = DetectionValidMessage.NAME_NOT_BLANK) - @Pattern(regexp = PatternRegex.ICD_NAME_REGEX, message = DetectionValidMessage.ICD_NAME_FORMAT_ERROR) - private String name; - - @ApiModelProperty(value = "存储路径", required = true) - @NotBlank(message = DetectionValidMessage.ICD_PATH_NOT_BLANK) - @Pattern(regexp = PatternRegex.ICD_PATH_REGEX, message = DetectionValidMessage.ICD_PATH_FORMAT_ERROR) - private String path; - - @ApiModelProperty(value = "是否支持电压相角、电流相角指标,0表示否,1表示是", required = true) + @ApiModelProperty(value = "angle", required = true) private Integer angle; - @ApiModelProperty(value = "角型接线时是否使用相别的指标来进行检测,0表示否,1表示是", required = true) + @ApiModelProperty(value = "usePhaseIndex", required = true) private Integer usePhaseIndex; - @ApiModelProperty(value = "映射文件", required = true) - private MultipartFile mappingFile; + @ApiModelProperty(value = "jsonStr") + private String jsonStr; + + @ApiModelProperty(value = "xmlStr") + private String xmlStr; + + @ApiModelProperty(value = "result") + private Integer result; + + @ApiModelProperty(value = "msg") + private String msg; + + @ApiModelProperty(value = "type") + private Integer type; + + @ApiModelProperty(value = "referenceIcdId") + private String referenceIcdId; - /** - * 分页查询实体 - */ @Data @EqualsAndHashCode(callSuper = true) public static class QueryParam extends BaseParam { - @ApiModelProperty(value = "名称", required = true) + @ApiModelProperty(value = "name", required = true) private String name; } + @Data + @EqualsAndHashCode(callSuper = true) + public static class CreateParam extends PqIcdPathParam { + @ApiModelProperty(value = "icdFile", required = true) + private MultipartFile icdFile; + } + + @Data + @EqualsAndHashCode(callSuper = true) + public static class ExternalCreateParam extends PqIcdPathParam { + @ApiModelProperty(value = "id", required = true) + @NotBlank(message = DetectionValidMessage.ID_NOT_BLANK) + @Pattern(regexp = PatternRegex.SYSTEM_ID, message = DetectionValidMessage.ID_FORMAT_ERROR) + private String id; + + @ApiModelProperty(value = "name", required = true) + @NotBlank(message = DetectionValidMessage.NAME_NOT_BLANK) + @Pattern(regexp = PatternRegex.SCRIPT_NAME_REGEX, message = DetectionValidMessage.ICD_NAME_FORMAT_ERROR) + private String name; + + @ApiModelProperty(value = "icdFile", required = true) + @NotBlank(message = IcdExternalValidMessage.ICD_FILE_NOT_BLANK) + private String icdFile; + + } - /** - * 更新参数 - */ @Data @EqualsAndHashCode(callSuper = true) public static class UpdateParam extends PqIcdPathParam { @@ -57,5 +81,12 @@ public class PqIcdPathParam { @NotBlank(message = DetectionValidMessage.ID_NOT_BLANK) @Pattern(regexp = PatternRegex.SYSTEM_ID, message = DetectionValidMessage.ID_FORMAT_ERROR) private String id; + + @ApiModelProperty(value = "icdFile") + private MultipartFile icdFile; + } + + private interface IcdExternalValidMessage { + String ICD_FILE_NOT_BLANK = "ICD原始文件不能为空"; } } diff --git a/detection/src/main/java/com/njcn/gather/icd/pojo/po/PqIcdPath.java b/detection/src/main/java/com/njcn/gather/icd/pojo/po/PqIcdPath.java index b59c962d..1e10c615 100644 --- a/detection/src/main/java/com/njcn/gather/icd/pojo/po/PqIcdPath.java +++ b/detection/src/main/java/com/njcn/gather/icd/pojo/po/PqIcdPath.java @@ -28,11 +28,6 @@ public class PqIcdPath extends BaseEntity implements Serializable { */ private String name; - /** - * icd存储地址 - */ - private String path; - /** * 状态:0-删除 1-正常 */ @@ -46,19 +41,55 @@ public class PqIcdPath extends BaseEntity implements Serializable { /** * 角型接线时是否使用相别的指标来进行检测,0表示否,1表示是 */ + @TableField("use_phase_index") private Integer usePhaseIndex; /** - * 映射文件路径 + * 解析后的json字符串 */ + @TableField("Json_Str") + private String jsonStr; + + /** + * 解析后的xml字符串 + */ + @TableField("Xml_Str") + private String xmlStr; + + /** + * ICD原始文件二进制 + */ + @TableField("Icd") + private byte[] icd; + + /** + * 结论 + */ + @TableField("Result") + private Integer result; + + /** + * 结论描述 + */ + @TableField("Msg") + private String msg; + + /** + * ICD类型 + */ + @TableField("Type") + private Integer type; + + /** + * 参照标准ICD + */ + @TableField("Reference_Icd_Id") + private String referenceIcdId; + @TableField(exist = false) - private FileVO mappingFile; + private String referenceIcdName; - @Data - public static class FileVO{ - private String name; - - private String url; - } + @TableField(exist = false) + private Boolean hasIcdFile; } diff --git a/detection/src/main/java/com/njcn/gather/icd/service/IPqIcdPathService.java b/detection/src/main/java/com/njcn/gather/icd/service/IPqIcdPathService.java index e0272b98..e5f4d5f8 100644 --- a/detection/src/main/java/com/njcn/gather/icd/service/IPqIcdPathService.java +++ b/detection/src/main/java/com/njcn/gather/icd/service/IPqIcdPathService.java @@ -28,13 +28,22 @@ public interface IPqIcdPathService extends IService { */ Page listIcd(PqIcdPathParam.QueryParam param); + /** + * 获取所有标准ICD + * + * @return 标准ICD列表 + */ + List listStandardIcd(); + /** * 新增Icd * * @param param 新增Icd参数 * @return 成功返回true,失败返回false */ - boolean addIcd(PqIcdPathParam param); + boolean addIcd(PqIcdPathParam.CreateParam param); + + boolean addUpstreamIcd(List param); /** * 修改Icd @@ -52,6 +61,22 @@ public interface IPqIcdPathService extends IService { */ boolean deleteIcd(List ids); + /** + * 根据id获取ICD详情 + * + * @param id ICD id + * @return ICD详情 + */ + PqIcdPath getIcdById(String id); + + /** + * 导出ICD压缩包 + * + * @param id ICD id + * @return zip字节数组 + */ + byte[] exportIcd(String id); + /** * 根据设备类型id获取Icd * diff --git a/detection/src/main/java/com/njcn/gather/icd/service/impl/PqIcdPathServiceImpl.java b/detection/src/main/java/com/njcn/gather/icd/service/impl/PqIcdPathServiceImpl.java index b66fb5f4..1b6fc628 100644 --- a/detection/src/main/java/com/njcn/gather/icd/service/impl/PqIcdPathServiceImpl.java +++ b/detection/src/main/java/com/njcn/gather/icd/service/impl/PqIcdPathServiceImpl.java @@ -1,5 +1,6 @@ package com.njcn.gather.icd.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -12,23 +13,26 @@ import com.njcn.gather.icd.pojo.enums.IcdResponseEnum; import com.njcn.gather.icd.pojo.param.PqIcdPathParam; import com.njcn.gather.icd.pojo.po.PqIcdPath; import com.njcn.gather.icd.service.IPqIcdPathService; +import com.njcn.gather.icd.service.support.IcdArchiveBuilder; +import com.njcn.gather.icd.service.support.IcdPayloadAssembler; import com.njcn.gather.pojo.enums.DetectionResponseEnum; -import com.njcn.gather.report.pojo.enums.ReportResponseEnum; import com.njcn.web.factory.PageFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * @author caozehui @@ -38,174 +42,147 @@ import java.util.List; @Service @RequiredArgsConstructor public class PqIcdPathServiceImpl extends ServiceImpl implements IPqIcdPathService { + // 手动录入标准ICD + private static final int TYPE_STANDARD = 1; + // 手动录入非标准ICD + private static final int TYPE_NON_STANDARD = 2; + // 上游录入的标准ICD + private static final int TYPE_UPSTREAM_STANDARD = 3; + + // 上游录入的非标准ICD + private static final int TYPE_UPSTREAM_NON_STANDARD = 4; + private static final int RESULT_NO = 0; + private static final int RESULT_YES = 1; + + @Value("${icd.txt-dir}") + private String icdTxtDir; + + private final IcdPayloadAssembler icdPayloadAssembler; + private final IcdArchiveBuilder icdArchiveBuilder; @Override public List listAll() { - return this.lambdaQuery().eq(PqIcdPath::getState, DataStateEnum.ENABLE.getCode()).list(); + return this.lambdaQuery() + .select(PqIcdPath::getId, PqIcdPath::getName, PqIcdPath::getType, PqIcdPath::getReferenceIcdId) + .eq(PqIcdPath::getState, DataStateEnum.ENABLE.getCode()) + .orderByDesc(PqIcdPath::getCreateTime) + .list(); + } + + @Override + public List listStandardIcd() { + return this.baseMapper.selectStandardList(); } @Override public Page listIcd(PqIcdPathParam.QueryParam param) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(PqIcdPath::getState, DataStateEnum.ENABLE.getCode()) - .like(StrUtil.isNotBlank(param.getName()), PqIcdPath::getName, param.getName()) - .orderByDesc(PqIcdPath::getCreateTime); - Page page = this.page(new Page<>(PageFactory.getPageNum(param), PageFactory.getPageSize(param)), wrapper); - String commInstallPath = this.getCommInstallPath(); - page.getRecords().forEach(pqIcdPath -> { - PqIcdPath.FileVO fileVO = new PqIcdPath.FileVO(); - fileVO.setUrl(commInstallPath + "\\DeviceControl\\Config\\" + pqIcdPath.getName() + ".txt"); - fileVO.setName(pqIcdPath.getName() + ".txt"); - pqIcdPath.setMappingFile(fileVO); - }); + Page page = new Page<>(PageFactory.getPageNum(param), PageFactory.getPageSize(param)); + page.setRecords(this.baseMapper.selectPageList(page, StrUtil.trim(param.getName()))); return page; } @Override @Transactional - public boolean addIcd(PqIcdPathParam param) { - param.setName(param.getName().trim()); - this.checkRepeat(param, false); - PqIcdPath pqIcdPath = new PqIcdPath(); - BeanUtils.copyProperties(param, pqIcdPath); - pqIcdPath.setState(DataStateEnum.ENABLE.getCode()); - - String commInstallPath = this.getCommInstallPath(); - System.out.println("commInstallPath = " + commInstallPath); - long FILE_SIZE_LIMIT = 1 * 1024 * 1024; - MultipartFile mappingFile = param.getMappingFile(); - - System.out.println("mappingFile = " + ObjectUtil.isNotNull(mappingFile) + " " + !mappingFile.isEmpty()); - if (ObjectUtil.isNotNull(mappingFile) && !mappingFile.isEmpty()) { - String mappingFilename = mappingFile.getOriginalFilename(); - - if (!mappingFilename.endsWith(".txt")) { - throw new BusinessException(IcdResponseEnum.FILE_TYPE_ERROR); - } - if (mappingFile.getSize() > FILE_SIZE_LIMIT) { - throw new BusinessException(IcdResponseEnum.FILE_SIZE_ERROR); - } - - try { - // 如果文件存在,则先删除 - String mappingFilePath = commInstallPath + "\\DeviceControl\\Config\\" + mappingFilename; - System.out.println("mappingFilePath = " + mappingFilePath); - Path path = Paths.get(mappingFilePath); - File file = path.toFile(); - if (file.exists()) { - file.delete(); - } - - // 保存文件 - byte[] bytes = mappingFile.getBytes(); - BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(mappingFilePath)); - bufferedOutputStream.write(bytes); - bufferedOutputStream.flush(); - - bufferedOutputStream.close(); - System.out.println("File saved successfully"); - } catch (IOException e) { - throw new BusinessException(ReportResponseEnum.FILE_UPLOAD_FAILED); - } - } else { - System.out.println("mappingFile is null or empty"); - throw new BusinessException(IcdResponseEnum.FILE_NOT_NULL); + public boolean addIcd(PqIcdPathParam.CreateParam param) { + validateBusinessFields(param, null); + PqIcdPath pqIcdPath = icdPayloadAssembler.fromCreate(param); + validateReferenceIcd(pqIcdPath.getType(), pqIcdPath.getReferenceIcdId(), null); + boolean saved = this.save(pqIcdPath); + if (saved) { + writeIcdTextFile(resolveIcdTxtDir(), pqIcdPath.getName(), pqIcdPath.getJsonStr()); } - - //this.executeRestartCmd(commInstallPath); - - return this.save(pqIcdPath); + return saved; } -// /** -// * 执行重启通讯服务脚本 -// * -// * @param commInstallPath -// */ -// private void executeRestartCmd(String commInstallPath) { -// // 以管理员身份运行bat脚本 -// String batFilePath = commInstallPath + "\\重启所有服务.bat"; -// try { -// Runtime.getRuntime().exec(batFilePath); -// } catch (IOException e) { -// log.error("重启通讯服务失败", e); -// } -// } - - private String getCommInstallPath() { - String workDir = System.getProperty("user.dir"); -// String workDir = "D:\\program\\CN_Gather"; - // 获取映射文件存放文件夹 - String dirPath = workDir + "\\9100"; - int index = workDir.indexOf("\\resources\\extraResources\\java"); - if (index != -1) { - dirPath = workDir.substring(0, workDir.indexOf("\\resources\\extraResources\\java")) + "\\9100"; + @Override + @Transactional + public boolean addUpstreamIcd(List param) { + if (CollUtil.isEmpty(param)) { + return true; } - return dirPath; + Set requestStandardIds = collectRequestStandardIds(param); + boolean allSaved = true; + Path directory = resolveIcdTxtDir(); + for (PqIcdPathParam.ExternalCreateParam item : param) { + validateBusinessFields(item, null); + PqIcdPath current = this.baseMapper.selectById(item.getId()); + PqIcdPath pqIcdPath = icdPayloadAssembler.fromExternalCreate(item, item.getType(), item.getAngle(), item.getUsePhaseIndex()); + String currentId = current == null ? null : current.getId(); + String oldName = current == null ? null : current.getName(); + validateExternalReferenceIcd(pqIcdPath.getType(), pqIcdPath.getReferenceIcdId(), currentId, requestStandardIds); + boolean saved = current == null ? this.save(pqIcdPath) : this.updateById(pqIcdPath); + if (!saved) { + allSaved = false; + break; + } + if (current == null) { + writeIcdTextFile(directory, pqIcdPath.getName(), pqIcdPath.getJsonStr()); + } else { + syncUpdatedIcdTextFile(directory, oldName, pqIcdPath.getName(), pqIcdPath.getJsonStr()); + } + } + return allSaved; } @Override @Transactional public boolean updateIcd(PqIcdPathParam.UpdateParam param) { - param.setName(param.getName().trim()); - this.checkRepeat(param, true); - PqIcdPath pqIcdPath = new PqIcdPath(); - BeanUtils.copyProperties(param, pqIcdPath); - - String commInstallPath = this.getCommInstallPath(); - long FILE_SIZE_LIMIT = 1 * 1024 * 1024; - MultipartFile mappingFile = param.getMappingFile(); - if (ObjectUtil.isNotNull(mappingFile) && !mappingFile.isEmpty()) { - String mappingFilename = mappingFile.getOriginalFilename(); - - if (!mappingFilename.endsWith(".txt")) { - throw new BusinessException(IcdResponseEnum.FILE_TYPE_ERROR); - } - if (mappingFile.getSize() > FILE_SIZE_LIMIT) { - throw new BusinessException(IcdResponseEnum.FILE_SIZE_ERROR); - } - - try { - // 如果文件存在,则先删除 - String mappingFilePath = commInstallPath + "\\DeviceControl\\Config\\" + mappingFilename; - Path path = Paths.get(mappingFilePath); - File file = path.toFile(); - if (file.exists()) { - file.delete(); - } - - // 保存文件 - byte[] bytes = mappingFile.getBytes(); - BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(mappingFilePath)); - bufferedOutputStream.write(bytes); - bufferedOutputStream.flush(); - - bufferedOutputStream.close(); - } catch (IOException e) { - throw new BusinessException(ReportResponseEnum.FILE_UPLOAD_FAILED); - } + PqIcdPath current = getActiveEntity(param.getId()); + String oldName = current.getName(); + validateBusinessFields(param, current.getId()); + PqIcdPath pqIcdPath = icdPayloadAssembler.merge(current, param); + validateReferenceIcd(pqIcdPath.getType(), pqIcdPath.getReferenceIcdId(), current.getId()); + boolean updated = this.updateById(pqIcdPath); + if (updated) { + syncUpdatedIcdTextFile(resolveIcdTxtDir(), oldName, pqIcdPath.getName(), pqIcdPath.getJsonStr()); } - - //this.executeRestartCmd(commInstallPath); - - return this.updateById(pqIcdPath); + return updated; } @Override @Transactional public boolean deleteIcd(List ids) { - List pqIcdPaths = this.listByIds(ids); - String commInstallPath = this.getCommInstallPath(); - pqIcdPaths.forEach(pqIcdPath -> { - String mappingFilePath = commInstallPath + "\\DeviceControl\\Config\\" + pqIcdPath.getName() + ".txt"; - Path path = Paths.get(mappingFilePath); - File file = path.toFile(); - if (file.exists()) { - file.delete(); + if (CollUtil.isEmpty(ids)) { + return true; + } + List pqIcdPaths = this.baseMapper.selectByIdsWithoutBlob(ids); + List standardIds = pqIcdPaths.stream() + .filter(pqIcdPath -> ObjectUtil.equals(pqIcdPath.getType(), TYPE_STANDARD)) + .map(PqIcdPath::getId) + .collect(Collectors.toList()); + if (!standardIds.isEmpty()) { + Long count = this.baseMapper.countActiveReferencesToStandards(standardIds); + if (ObjectUtil.isNotNull(count) && count > 0) { + throw new BusinessException(IcdResponseEnum.STANDARD_ICD_IN_USE); } - }); + } - return this.lambdaUpdate().in(PqIcdPath::getId, ids).set(PqIcdPath::getState, DataStateEnum.DELETED.getCode()).update(); + boolean deleted = this.lambdaUpdate().in(PqIcdPath::getId, ids).set(PqIcdPath::getState, DataStateEnum.DELETED.getCode()).update(); + if (deleted) { + Path directory = resolveIcdTxtDir(); + for (PqIcdPath pqIcdPath : pqIcdPaths) { + deleteIcdTextFile(directory, pqIcdPath.getName()); + } + } + return deleted; + } + + @Override + public PqIcdPath getIcdById(String id) { + PqIcdPath detail = this.baseMapper.selectDetailById(id); + if (ObjectUtil.isNull(detail)) { + throw new BusinessException(IcdResponseEnum.ICD_NOT_FOUND); + } + return detail; + } + + @Override + public byte[] exportIcd(String id) { + PqIcdPath detail = this.baseMapper.selectExportById(id); + if (ObjectUtil.isNull(detail)) { + throw new BusinessException(IcdResponseEnum.ICD_NOT_FOUND); + } + return icdArchiveBuilder.build(detail); } @Override @@ -213,18 +190,125 @@ public class PqIcdPathServiceImpl extends ServiceImpl wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(PqIcdPath::getName, param.getName()) - .eq(PqIcdPath::getState, DataStateEnum.ENABLE.getCode()); - if (isExcludeSelf) { - if (param instanceof PqIcdPathParam.UpdateParam) { - wrapper.ne(PqIcdPath::getId, ((PqIcdPathParam.UpdateParam) param).getId()); - } + private void validateBusinessFields(PqIcdPathParam param, String currentId) { + if (ObjectUtil.isNull(param.getResult())) { + throw new BusinessException(IcdResponseEnum.RESULT_NOT_NULL); } - int count = this.count(wrapper); - if (count > 0) { - throw new BusinessException(DetectionResponseEnum.ICD_PATH_NAME_REPEAT); + if (ObjectUtil.equals(param.getResult(), RESULT_NO) && StrUtil.isBlank(param.getMsg())) { + throw new BusinessException(IcdResponseEnum.MSG_NOT_BLANK); + } + if (ObjectUtil.isNull(param.getType())) { + throw new BusinessException(IcdResponseEnum.TYPE_NOT_NULL); + } + if (!ObjectUtil.equals(param.getType(), TYPE_STANDARD) + && !ObjectUtil.equals(param.getType(), TYPE_NON_STANDARD) + && !ObjectUtil.equals(param.getType(), TYPE_UPSTREAM_STANDARD) + && !ObjectUtil.equals(param.getType(), TYPE_UPSTREAM_NON_STANDARD)) { + throw new BusinessException(IcdResponseEnum.TYPE_VALUE_ERROR); + } + if (requiresReferenceIcd(param.getType()) && StrUtil.isBlank(param.getReferenceIcdId())) { + throw new BusinessException(IcdResponseEnum.REFERENCE_ICD_NOT_BLANK); + } + if (StrUtil.isNotBlank(currentId) && StrUtil.equals(currentId, StrUtil.trim(param.getReferenceIcdId()))) { + throw new BusinessException(IcdResponseEnum.REFERENCE_ICD_INVALID); } } + + private void validateReferenceIcd(Integer type, String referenceIcdId, String currentId) { + if (!requiresReferenceIcd(type)) { + return; + } + if (StrUtil.isNotBlank(currentId) && StrUtil.equals(currentId, referenceIcdId)) { + throw new BusinessException(IcdResponseEnum.REFERENCE_ICD_INVALID); + } + long count = this.lambdaQuery() + .eq(PqIcdPath::getId, referenceIcdId) + .in(PqIcdPath::getType, TYPE_STANDARD, TYPE_UPSTREAM_STANDARD) + .eq(PqIcdPath::getState, DataStateEnum.ENABLE.getCode()) + .count(); + if (count <= 0L) { + throw new BusinessException(IcdResponseEnum.REFERENCE_ICD_INVALID); + } + } + + private void validateExternalReferenceIcd(Integer type, String referenceIcdId, String currentId, Set requestStandardIds) { + if (!requiresReferenceIcd(type)) { + return; + } + String trimmedReferenceId = StrUtil.trim(referenceIcdId); + if (StrUtil.isNotBlank(currentId) && StrUtil.equals(currentId, trimmedReferenceId)) { + throw new BusinessException(IcdResponseEnum.REFERENCE_ICD_INVALID); + } + if (StrUtil.isNotBlank(trimmedReferenceId) && requestStandardIds.contains(trimmedReferenceId)) { + return; + } + validateReferenceIcd(type, trimmedReferenceId, currentId); + } + + private Set collectRequestStandardIds(List params) { + Set ids = new HashSet<>(); + for (PqIcdPathParam.ExternalCreateParam param : params) { + if (isStandardType(param.getType()) && StrUtil.isNotBlank(param.getId())) { + ids.add(StrUtil.trim(param.getId())); + } + } + return ids; + } + + private boolean requiresReferenceIcd(Integer type) { + return ObjectUtil.equals(type, TYPE_NON_STANDARD) || ObjectUtil.equals(type, TYPE_UPSTREAM_NON_STANDARD); + } + + private boolean isStandardType(Integer type) { + return ObjectUtil.equals(type, TYPE_STANDARD) || ObjectUtil.equals(type, TYPE_UPSTREAM_STANDARD); + } + + private PqIcdPath getActiveEntity(String id) { + PqIcdPath current = this.lambdaQuery() + .eq(PqIcdPath::getId, id) + .eq(PqIcdPath::getState, DataStateEnum.ENABLE.getCode()) + .one(); + if (ObjectUtil.isNull(current)) { + throw new BusinessException(IcdResponseEnum.ICD_NOT_FOUND); + } + return current; + } + + Path resolveIcdTxtDir() { + if (StrUtil.isBlank(icdTxtDir)) { + throw new BusinessException(IcdResponseEnum.ICD_TXT_SYNC_FAILED); + } + return Paths.get(icdTxtDir.trim()); + } + + void writeIcdTextFile(Path directory, String name, String jsonStr) { + try { + Files.createDirectories(directory); + Files.write(resolveTxtFile(directory, name), StrUtil.nullToDefault(jsonStr, "").getBytes(StandardCharsets.UTF_8), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); + } catch (IOException ex) { + log.error("sync icd txt file failed, name={}", name, ex); + throw new BusinessException(IcdResponseEnum.ICD_TXT_SYNC_FAILED); + } + } + + void syncUpdatedIcdTextFile(Path directory, String oldName, String newName, String jsonStr) { + if (StrUtil.isNotBlank(oldName) && !StrUtil.equals(oldName, newName)) { + deleteIcdTextFile(directory, oldName); + } + writeIcdTextFile(directory, newName, jsonStr); + } + + void deleteIcdTextFile(Path directory, String name) { + try { + Files.deleteIfExists(resolveTxtFile(directory, name)); + } catch (IOException ex) { + log.error("delete icd txt file failed, name={}", name, ex); + throw new BusinessException(IcdResponseEnum.ICD_TXT_SYNC_FAILED); + } + } + + private Path resolveTxtFile(Path directory, String name) { + return directory.resolve(name + ".txt"); + } } diff --git a/detection/src/main/java/com/njcn/gather/icd/service/support/IcdArchiveBuilder.java b/detection/src/main/java/com/njcn/gather/icd/service/support/IcdArchiveBuilder.java new file mode 100644 index 00000000..ee856f63 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/icd/service/support/IcdArchiveBuilder.java @@ -0,0 +1,62 @@ +package com.njcn.gather.icd.service.support; + +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.gather.icd.pojo.enums.IcdResponseEnum; +import com.njcn.gather.icd.pojo.po.PqIcdPath; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +@Component +public class IcdArchiveBuilder { + + public byte[] build(PqIcdPath item) { + if (item == null || item.getIcd() == null || item.getIcd().length == 0) { + throw new BusinessException(IcdResponseEnum.ICD_FILE_NOT_FOUND); + } + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(bos, StandardCharsets.UTF_8)) { + writeTextEntry(zos, item.getName() + ".json", item.getJsonStr()); + writeTextEntry(zos, item.getName() + ".xml", item.getXmlStr()); + writeBinaryEntry(zos, item.getName() + ".icd", item.getIcd()); + zos.finish(); + return bos.toByteArray(); + } catch (IOException ex) { + throw new BusinessException(IcdResponseEnum.ICD_EXPORT_FAILED); + } + } + + /** + * 向ZIP流中写入文本条目 + * + * @param zos ZIP输出流 + * @param name 条目名称(文件路径) + * @param value 文本内容,如果为null则写入空字节数组 + * @throws IOException 写入异常 + */ + private void writeTextEntry(ZipOutputStream zos, String name, String value) throws IOException { + // 将文本转换为UTF-8编码的字节数组,null值转换为空数组 + writeBinaryEntry(zos, name, value == null ? new byte[0] : value.getBytes(StandardCharsets.UTF_8)); + } + + /** + * 向ZIP流中写入二进制条目 + * + * @param zos ZIP输出流 + * @param name 条目名称(文件路径) + * @param data 二进制数据 + * @throws IOException 写入异常 + */ + private void writeBinaryEntry(ZipOutputStream zos, String name, byte[] data) throws IOException { + // 创建新的ZIP条目并设置文件名 + zos.putNextEntry(new ZipEntry(name)); + // 写入二进制数据 + zos.write(data); + // 关闭当前条目,准备写入下一个条目 + zos.closeEntry(); + } +} diff --git a/detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadAssembler.java b/detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadAssembler.java new file mode 100644 index 00000000..2618353d --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadAssembler.java @@ -0,0 +1,90 @@ +package com.njcn.gather.icd.service.support; + +import cn.hutool.core.util.StrUtil; +import com.njcn.common.pojo.enums.common.DataStateEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.gather.icd.pojo.enums.IcdResponseEnum; +import com.njcn.gather.icd.pojo.param.PqIcdPathParam; +import com.njcn.gather.icd.pojo.po.PqIcdPath; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +@Component +@RequiredArgsConstructor +public class IcdPayloadAssembler { + + private final IcdPayloadValidator validator; + + public PqIcdPath fromCreate(PqIcdPathParam.CreateParam param) { + MultipartFile file = validator.validateIcdFile(param.getIcdFile(), true); + validator.validateJson(param.getJsonStr()); + validator.validateXml(param.getXmlStr()); + + PqIcdPath entity = new PqIcdPath(); + applyCommonFields(entity, param); + entity.setName(validator.extractName(file.getOriginalFilename())); + entity.setIcd(getBytes(file)); + entity.setState(DataStateEnum.ENABLE.getCode()); + return entity; + } + + public PqIcdPath fromExternalCreate(PqIcdPathParam.ExternalCreateParam param, int type, int angle, int usePhaseIndex) { + byte[] fileBytes = validator.decodeExternalIcdFile(param.getIcdFile()); + validator.validateJson(param.getJsonStr()); + validator.validateXml(param.getXmlStr()); + + PqIcdPath entity = new PqIcdPath(); + entity.setId(normalizeNullableText(param.getId())); + param.setType(type); + param.setAngle(angle); + param.setUsePhaseIndex(usePhaseIndex); + applyCommonFields(entity, param); + entity.setName(normalizeNullableText(param.getName())); + entity.setIcd(fileBytes); + entity.setState(DataStateEnum.ENABLE.getCode()); + return entity; + } + + public PqIcdPath merge(PqIcdPath current, PqIcdPathParam.UpdateParam param) { + MultipartFile file = validator.validateIcdFile(param.getIcdFile(), false); + validator.validateJson(param.getJsonStr()); + validator.validateXml(param.getXmlStr()); + + applyCommonFields(current, param); + if (file != null && !file.isEmpty()) { + current.setName(validator.extractName(file.getOriginalFilename())); + current.setIcd(getBytes(file)); + } + return current; + } + + private void applyCommonFields(PqIcdPath entity, PqIcdPathParam param) { + entity.setAngle(param.getAngle()); + entity.setUsePhaseIndex(param.getUsePhaseIndex()); + entity.setJsonStr(param.getJsonStr()); + entity.setXmlStr(param.getXmlStr()); + entity.setResult(param.getResult()); + entity.setMsg(param.getResult() != null && param.getResult() == 1 ? null : normalizeNullableText(param.getMsg())); + entity.setType(param.getType()); + entity.setReferenceIcdId(requiresReferenceIcd(param.getType()) ? normalizeNullableText(param.getReferenceIcdId()) : null); + } + + private String normalizeNullableText(String value) { + return StrUtil.emptyToNull(StrUtil.trim(value)); + } + + private boolean requiresReferenceIcd(Integer type) { + return type != null && (type == 2 || type == 4); + } + + private byte[] getBytes(MultipartFile file) { + try { + return file.getBytes(); + } catch (IOException ex) { + throw new BusinessException(IcdResponseEnum.ICD_FILE_READ_ERROR); + } + } +} diff --git a/detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadValidator.java b/detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadValidator.java new file mode 100644 index 00000000..90e06f69 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/icd/service/support/IcdPayloadValidator.java @@ -0,0 +1,66 @@ +package com.njcn.gather.icd.service.support; + +import com.alibaba.fastjson.JSON; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.gather.icd.pojo.enums.IcdResponseEnum; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import org.xml.sax.InputSource; + +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.StringReader; +import java.util.Base64; +import java.util.Locale; + +@Component +public class IcdPayloadValidator { + + public MultipartFile validateIcdFile(MultipartFile file, boolean required) { + if ((file == null || file.isEmpty()) && required) { + throw new BusinessException(IcdResponseEnum.ICD_FILE_NOT_NULL); + } + if (file == null || file.isEmpty()) { + return null; + } + String originalName = file.getOriginalFilename(); + if (originalName == null || !originalName.toLowerCase(Locale.ROOT).endsWith(".icd")) { + throw new BusinessException(IcdResponseEnum.ICD_FILE_TYPE_ERROR); + } + return file; + } + + public String extractName(String originalName) { + int suffixIndex = originalName.toLowerCase(Locale.ROOT).lastIndexOf(".icd"); + return suffixIndex >= 0 ? originalName.substring(0, suffixIndex) : originalName; + } + + public byte[] decodeExternalIcdFile(String base64Content) { + if (base64Content == null || base64Content.trim().isEmpty()) { + throw new BusinessException(IcdResponseEnum.ICD_FILE_NOT_NULL); + } + try { + return Base64.getDecoder().decode(base64Content.trim()); + } catch (IllegalArgumentException ex) { + throw new BusinessException(IcdResponseEnum.ICD_FILE_READ_ERROR); + } + } + + public void validateJson(String jsonStr) { + try { + JSON.parse(jsonStr); + } catch (Exception ex) { + throw new BusinessException(IcdResponseEnum.JSON_FORMAT_ERROR); + } + } + + public void validateXml(String xmlStr) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + // 禁用 DOCTYPE 声明 + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + factory.newDocumentBuilder().parse(new InputSource(new StringReader(xmlStr))); + } catch (Exception ex) { + throw new BusinessException(IcdResponseEnum.XML_FORMAT_ERROR); + } + } +} diff --git a/entrance/src/main/resources/application.yml b/entrance/src/main/resources/application.yml index d826bb7b..7e5208f9 100644 --- a/entrance/src/main/resources/application.yml +++ b/entrance/src/main/resources/application.yml @@ -109,6 +109,9 @@ qr: db: type: mysql +icd: + txt-dir: D:\icd-txt + # 比对录波需要的配置,晚点再做优化 # 系统配置