feat(icd): 完善ICD映射管理功能
- 在AuthGlobalFilter中添加稳态检验相关接口的免认证路径 - 修改CsDevTypeMapper.xml移除icdPath字段返回避免数据冗余 - 在CsIcdPathController中新增查询参照ICD列表和ICD校验详情接口 - 更新CsIcdPathMapper添加selectReferenceIcdPathList等方法实现 - 移除CsIcdPath相关实体和参数中的path字段简化数据结构 - 扩展ICD类型定义支持手动录入和上游解析的标准/非标准分类 - 重构激活标准ICD逻辑支持不同类型间的正确转换 - 新增ICD一致性校验排除规则跳过特定描述的DOI项检查 - 优化报告映射规则应用逻辑提升校验准确性 - 添加去除重复DOI项功能确保数据唯一性
This commit is contained in:
@@ -20,6 +20,12 @@
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>mybatis-plus</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>spingboot2.3.12</artifactId>
|
||||
@@ -74,6 +80,14 @@
|
||||
<exclude>pqdif-samples/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
|
||||
<!-- Mapper XML 按当前项目约定放在 Java 包路径下,需要显式复制到 classpath。 -->
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.njcn.gather.tool.parsepqdif.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
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.tool.parsepqdif.pojo.param.CsPqdifPathParam;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.param.PqdifParseResultSaveParam;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathDetailVO;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathVO;
|
||||
import com.njcn.gather.tool.parsepqdif.service.CsPqdifPathService;
|
||||
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.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PQDIF 存储记录维护入口。
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "PQDIF存储记录管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/parse-pqdif/pqdif-paths")
|
||||
@RequiredArgsConstructor
|
||||
public class CsPqdifPathController extends BaseController {
|
||||
|
||||
private final CsPqdifPathService csPqdifPathService;
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询PQDIF存储记录列表")
|
||||
@PostMapping("/list")
|
||||
public HttpResult<List<CsPqdifPathVO>> list(@RequestBody(required = false) CsPqdifPathParam.ListParam param) {
|
||||
String methodDescribe = getMethodDescribe("list");
|
||||
LogUtil.njcnDebug(log, "{},开始查询PQDIF存储记录列表", methodDescribe);
|
||||
List<CsPqdifPathVO> result = csPqdifPathService.listPqdifPaths(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("新增PQDIF存储记录")
|
||||
@PostMapping(value = "/add", consumes = {"application/json"})
|
||||
public HttpResult<Boolean> add(@RequestBody @Validated CsPqdifPathParam param) {
|
||||
String methodDescribe = getMethodDescribe("add");
|
||||
LogUtil.njcnDebug(log, "{},开始新增PQDIF存储记录", methodDescribe);
|
||||
boolean result = csPqdifPathService.addPqdifPath(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("上传并新增PQDIF存储记录")
|
||||
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
|
||||
public HttpResult<Boolean> addWithFile(@RequestPart("pqdifFile") MultipartFile pqdifFile,
|
||||
@RequestPart("request") @Validated CsPqdifPathParam param) {
|
||||
String methodDescribe = getMethodDescribe("addWithFile");
|
||||
LogUtil.njcnDebug(log, "{},开始上传并新增PQDIF存储记录,fileName={}", methodDescribe, resolveFileName(pqdifFile));
|
||||
fillPqdifFile(param, pqdifFile);
|
||||
boolean result = csPqdifPathService.addPqdifPath(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("编辑PQDIF存储记录")
|
||||
@PostMapping(value = "/update", consumes = {"application/json"})
|
||||
public HttpResult<Boolean> update(@RequestBody @Validated CsPqdifPathParam.UpdateParam param) {
|
||||
String methodDescribe = getMethodDescribe("update");
|
||||
LogUtil.njcnDebug(log, "{},开始编辑PQDIF存储记录,pqdifId={}", methodDescribe, param.getId());
|
||||
boolean result = csPqdifPathService.updatePqdifPath(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("上传并编辑PQDIF存储记录")
|
||||
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
|
||||
public HttpResult<Boolean> updateWithFile(@RequestPart("pqdifFile") MultipartFile pqdifFile,
|
||||
@RequestPart("request") @Validated CsPqdifPathParam.UpdateParam param) {
|
||||
String methodDescribe = getMethodDescribe("updateWithFile");
|
||||
LogUtil.njcnDebug(log, "{},开始上传并编辑PQDIF存储记录,pqdifId={},fileName={}",
|
||||
methodDescribe, param.getId(), resolveFileName(pqdifFile));
|
||||
fillPqdifFile(param, pqdifFile);
|
||||
boolean result = csPqdifPathService.updatePqdifPath(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("删除PQDIF存储记录")
|
||||
@PostMapping("/delete")
|
||||
public HttpResult<Boolean> delete(@RequestBody List<String> ids) {
|
||||
String methodDescribe = getMethodDescribe("delete");
|
||||
LogUtil.njcnDebug(log, "{},开始删除PQDIF存储记录,ids={}", methodDescribe, ids);
|
||||
boolean result = csPqdifPathService.deletePqdifPath(ids);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询PQDIF解析结果详情")
|
||||
@ApiImplicitParam(name = "id", value = "PQDIF记录ID", required = true)
|
||||
@PostMapping("/{id}/parse-msg")
|
||||
public HttpResult<JsonNode> getPqdifParseMsg(@PathVariable("id") String id) {
|
||||
String methodDescribe = getMethodDescribe("getPqdifParseMsg");
|
||||
LogUtil.njcnDebug(log, "{},开始查询PQDIF解析结果详情,pqdifId={}", methodDescribe, id);
|
||||
JsonNode result = csPqdifPathService.getPqdifParseMsg(id);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询PQDIF文件和解析结果详情")
|
||||
@ApiImplicitParam(name = "id", value = "PQDIF记录ID", required = true)
|
||||
@PostMapping("/{id}/parse-detail")
|
||||
public HttpResult<CsPqdifPathDetailVO> getPqdifParseDetail(@PathVariable("id") String id) {
|
||||
String methodDescribe = getMethodDescribe("getPqdifParseDetail");
|
||||
LogUtil.njcnDebug(log, "{},开始查询PQDIF文件和解析结果详情,pqdifId={}", methodDescribe, id);
|
||||
CsPqdifPathDetailVO result = csPqdifPathService.getPqdifParseDetail(id);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("保存PQDIF解析结果")
|
||||
@ApiImplicitParam(name = "id", value = "PQDIF记录ID", required = true)
|
||||
@PostMapping(value = "/{id}/parse-result", consumes = {"application/json"})
|
||||
public HttpResult<Boolean> savePqdifParseResult(@PathVariable("id") String id,
|
||||
@RequestBody PqdifParseResultSaveParam param) {
|
||||
String methodDescribe = getMethodDescribe("savePqdifParseResult");
|
||||
LogUtil.njcnDebug(log, "{},开始保存PQDIF解析结果,pqdifId={}", methodDescribe, id);
|
||||
boolean result = csPqdifPathService.savePqdifParseResult(id, param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
private void fillPqdifFile(CsPqdifPathParam param, MultipartFile pqdifFile) {
|
||||
if (pqdifFile == null || pqdifFile.isEmpty()) {
|
||||
throw new IllegalArgumentException("PQDIF文件不能为空");
|
||||
}
|
||||
try {
|
||||
param.setPqdifContent(pqdifFile.getBytes());
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalArgumentException("读取PQDIF文件失败:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveFileName(MultipartFile pqdifFile) {
|
||||
if (pqdifFile == null || pqdifFile.getOriginalFilename() == null) {
|
||||
return null;
|
||||
}
|
||||
String fileName = pqdifFile.getOriginalFilename().trim();
|
||||
return fileName.isEmpty() ? null : fileName;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
@RestController
|
||||
@RequestMapping("/api/parse-pqdif")
|
||||
@RequiredArgsConstructor
|
||||
public class ParsePqdifController extends BaseController {
|
||||
public class ParsePqdifController extends BaseController {
|
||||
|
||||
private final ParsePqdifService parsePqdifService;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ParsePqdifController extends BaseController {
|
||||
@PostMapping(value = "/parse", consumes = {"multipart/form-data"})
|
||||
public HttpResult<PqdifParseResponse> parse(@RequestPart("pqdifFile") MultipartFile pqdifFile) {
|
||||
String methodDescribe = getMethodDescribe("parse");
|
||||
LogUtil.njcnDebug(log, "{},PQDIF解析预留入口,fileName={}",
|
||||
LogUtil.njcnDebug(log, "{},PQDIF解析入口,fileName={}",
|
||||
methodDescribe, pqdifFile == null ? null : pqdifFile.getOriginalFilename());
|
||||
PqdifParseResponse result = parsePqdifService.parse(pqdifFile);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.njcn.gather.tool.parsepqdif.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.po.CsPqdifPathPO;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathDetailVO;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CsPqdifPathMapper extends BaseMapper<CsPqdifPathPO> {
|
||||
|
||||
List<CsPqdifPathVO> selectPqdifPathList(@Param("keyword") String keyword,
|
||||
@Param("result") Integer result);
|
||||
|
||||
CsPqdifPathVO selectPqdifParseMsgById(@Param("id") String id);
|
||||
|
||||
CsPqdifPathDetailVO selectPqdifPathDetailById(@Param("id") String id);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.tool.parsepqdif.mapper.CsPqdifPathMapper">
|
||||
|
||||
<resultMap id="CsPqdifPathVOResultMap"
|
||||
type="com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathVO">
|
||||
<id column="id" property="id"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="nativeVersion" property="nativeVersion"/>
|
||||
<result column="recordCount" property="recordCount"/>
|
||||
<result column="observationCount" property="observationCount"/>
|
||||
<result column="sampleValueCount" property="sampleValueCount"/>
|
||||
<result column="state" property="state"/>
|
||||
<result column="result" property="result"/>
|
||||
<result column="msg" property="msg"
|
||||
typeHandler="com.njcn.gather.tool.parsepqdif.typehandler.JsonNodeTypeHandler"/>
|
||||
<result column="createBy" property="createBy"/>
|
||||
<result column="createTime" property="createTime"/>
|
||||
<result column="updateBy" property="updateBy"/>
|
||||
<result column="updateTime" property="updateTime"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectPqdifPathList"
|
||||
resultMap="CsPqdifPathVOResultMap">
|
||||
SELECT
|
||||
ID AS id,
|
||||
Name AS name,
|
||||
Native_Version AS nativeVersion,
|
||||
Record_Count AS recordCount,
|
||||
Observation_Count AS observationCount,
|
||||
Sample_Value_Count AS sampleValueCount,
|
||||
State AS state,
|
||||
Result AS result,
|
||||
Msg AS msg,
|
||||
Create_By AS createBy,
|
||||
Create_Time AS createTime,
|
||||
Update_By AS updateBy,
|
||||
Update_Time AS updateTime
|
||||
FROM cs_pqdif_path
|
||||
WHERE State = 1
|
||||
<if test="keyword != null and keyword != ''">
|
||||
AND Name LIKE CONCAT('%', #{keyword}, '%')
|
||||
</if>
|
||||
<if test="result != null">
|
||||
AND Result = #{result}
|
||||
</if>
|
||||
ORDER BY Update_Time DESC, Create_Time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectPqdifParseMsgById"
|
||||
resultMap="CsPqdifPathVOResultMap">
|
||||
SELECT Msg AS msg
|
||||
FROM cs_pqdif_path
|
||||
WHERE ID = #{id}
|
||||
AND State = 1
|
||||
</select>
|
||||
|
||||
<select id="selectPqdifPathDetailById"
|
||||
resultType="com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathDetailVO">
|
||||
SELECT
|
||||
ID AS id,
|
||||
Name AS name,
|
||||
Json_Str AS jsonStr,
|
||||
Pqdif AS pqdifContent
|
||||
FROM cs_pqdif_path
|
||||
WHERE ID = #{id}
|
||||
AND State = 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1,12 +1,17 @@
|
||||
package com.njcn.gather.tool.parsepqdif.nativebridge;
|
||||
|
||||
import com.sun.jna.NativeLibrary;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Locale;
|
||||
|
||||
@Slf4j
|
||||
public final class PqdifNativeLibraryLoader {
|
||||
|
||||
private static final String RESOURCE_DLL = "/pqdif-native/win-x64/pqdifbasic.dll";
|
||||
@@ -41,8 +46,8 @@ public final class PqdifNativeLibraryLoader {
|
||||
NativeLibrary.addSearchPath("pqdifbasic", nativeDir.toAbsolutePath().toString());
|
||||
NativeLibrary.addSearchPath("pqdifbasic.dll", nativeDir.toAbsolutePath().toString());
|
||||
|
||||
System.out.println("PQDIF native dir = " + nativeDir.toAbsolutePath());
|
||||
System.out.println("PQDIF native dll = " + dllPath.toAbsolutePath());
|
||||
log.info("PQDIF native dir = {}", nativeDir.toAbsolutePath());
|
||||
log.info("PQDIF native dll = {}", dllPath.toAbsolutePath());
|
||||
|
||||
preparedNativeDir = nativeDir;
|
||||
prepared = true;
|
||||
@@ -81,4 +86,4 @@ public final class PqdifNativeLibraryLoader {
|
||||
System.setProperty(propertyName, nativePath + separator + oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.njcn.gather.tool.parsepqdif.pojo.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* PQDIF 存储记录保存参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("PQDIF存储记录保存参数")
|
||||
public class CsPqdifPathParam {
|
||||
|
||||
@ApiModelProperty("PQDIF名称")
|
||||
@NotBlank(message = "PQDIF名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("PQDIF文件二进制内容")
|
||||
private byte[] pqdifContent;
|
||||
|
||||
/**
|
||||
* PQDIF 存储记录编辑参数。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("PQDIF存储记录编辑参数")
|
||||
public static class UpdateParam extends CsPqdifPathParam {
|
||||
|
||||
@ApiModelProperty("PQDIF记录ID")
|
||||
@NotBlank(message = "PQDIF记录ID不能为空")
|
||||
private String id;
|
||||
}
|
||||
|
||||
/**
|
||||
* PQDIF 存储记录列表查询参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("PQDIF存储记录列表查询参数")
|
||||
public static class ListParam {
|
||||
|
||||
@ApiModelProperty("关键字,匹配PQDIF名称")
|
||||
private String keyword;
|
||||
|
||||
@ApiModelProperty("解析结果:1-成功,0-失败")
|
||||
private Integer result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.njcn.gather.tool.parsepqdif.pojo.param;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* PQDIF 解析结果保存参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("PQDIF解析结果保存参数")
|
||||
public class PqdifParseResultSaveParam {
|
||||
|
||||
@ApiModelProperty("native解析库版本")
|
||||
private String nativeVersion;
|
||||
|
||||
@ApiModelProperty("Record总数")
|
||||
private Long recordCount;
|
||||
|
||||
@ApiModelProperty("Observation Record总数")
|
||||
private Long observationCount;
|
||||
|
||||
@ApiModelProperty("每个Series返回的样例采样值数量")
|
||||
private Integer sampleValueCount;
|
||||
|
||||
@ApiModelProperty("解析结果:1-成功,0-失败")
|
||||
private Integer result;
|
||||
|
||||
@ApiModelProperty("解析提示、失败原因或解析结论JSON")
|
||||
private JsonNode msg;
|
||||
|
||||
@ApiModelProperty("完整PQDIF解析结果JSON")
|
||||
private String jsonStr;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.njcn.gather.tool.parsepqdif.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.njcn.gather.tool.parsepqdif.typehandler.JsonNodeTypeHandler;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* PQDIF 文件存储和解析结果记录。
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "cs_pqdif_path", autoResultMap = true)
|
||||
public class CsPqdifPathPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("ID")
|
||||
private String id;
|
||||
|
||||
@TableField("Name")
|
||||
private String name;
|
||||
|
||||
@TableField("Pqdif")
|
||||
private byte[] pqdifContent;
|
||||
|
||||
@TableField("Native_Version")
|
||||
private String nativeVersion;
|
||||
|
||||
@TableField("Record_Count")
|
||||
private Long recordCount;
|
||||
|
||||
@TableField("Observation_Count")
|
||||
private Long observationCount;
|
||||
|
||||
@TableField("Sample_Value_Count")
|
||||
private Integer sampleValueCount;
|
||||
|
||||
@TableField("Result")
|
||||
private Integer result;
|
||||
|
||||
@TableField(value = "Msg", typeHandler = JsonNodeTypeHandler.class)
|
||||
private JsonNode msg;
|
||||
|
||||
@TableField("Json_Str")
|
||||
private String jsonStr;
|
||||
|
||||
@TableField("State")
|
||||
private Integer state;
|
||||
|
||||
@TableField("Create_By")
|
||||
private String createBy;
|
||||
|
||||
@TableField("Create_Time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField("Update_By")
|
||||
private String updateBy;
|
||||
|
||||
@TableField("Update_Time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.gather.tool.parsepqdif.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* PQDIF 文件和解析结果详情。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("PQDIF文件和解析结果详情")
|
||||
public class CsPqdifPathDetailVO {
|
||||
|
||||
@ApiModelProperty("PQDIF记录ID")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("PQDIF名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("完整PQDIF解析结果JSON")
|
||||
private String jsonStr;
|
||||
|
||||
@JsonIgnore
|
||||
private byte[] pqdifContent;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.njcn.gather.tool.parsepqdif.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* PQDIF 存储记录列表项。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("PQDIF存储记录列表项")
|
||||
public class CsPqdifPathVO {
|
||||
|
||||
@ApiModelProperty("PQDIF记录ID")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("PQDIF名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("native解析库版本")
|
||||
private String nativeVersion;
|
||||
|
||||
@ApiModelProperty("Record总数")
|
||||
private Long recordCount;
|
||||
|
||||
@ApiModelProperty("Observation Record总数")
|
||||
private Long observationCount;
|
||||
|
||||
@ApiModelProperty("每个Series返回的样例采样值数量")
|
||||
private Integer sampleValueCount;
|
||||
|
||||
@ApiModelProperty("状态,1-正常,0-删除")
|
||||
private Integer state;
|
||||
|
||||
@ApiModelProperty("解析结果:1-成功,0-失败")
|
||||
private Integer result;
|
||||
|
||||
@ApiModelProperty("解析提示、失败原因或解析结论JSON")
|
||||
private JsonNode msg;
|
||||
|
||||
@ApiModelProperty("创建人")
|
||||
private String createBy;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新人")
|
||||
private String updateBy;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -4,15 +4,20 @@ import com.njcn.gather.tool.parsepqdif.nativebridge.PqdifNativeLibraryLoader;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.PqdifParseResponse;
|
||||
import com.njcn.pqdif.nativebridge.PqdifBasicNative;
|
||||
import com.njcn.pqdif.nativebridge.PqdifNativeSession;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Component
|
||||
public class PqdifNativeReader {
|
||||
|
||||
private static final String STATUS_SUCCESS = "SUCCESS";
|
||||
private static final String DATA_SUCCESS = "DATA_SUCCESS";
|
||||
private static final String DATA_FAILED = "DATA_FAILED";
|
||||
private static final int DEFAULT_SAMPLE_VALUE_COUNT = 5;
|
||||
|
||||
public PqdifParseResponse read(Path pqdifPath, String fileName) {
|
||||
@@ -40,10 +45,11 @@ public class PqdifNativeReader {
|
||||
recordVO.setRecordIndex(recordIndex);
|
||||
recordVO.setTypeGuid(recordInfo.typeGuid);
|
||||
recordVO.setTypeName(recordInfo.typeName);
|
||||
recordVO.setObservation(isObservation(recordInfo));
|
||||
boolean observationRecord = isObservation(recordInfo);
|
||||
recordVO.setObservation(observationRecord);
|
||||
response.getRecords().add(recordVO);
|
||||
|
||||
if (!isObservation(recordInfo)) {
|
||||
if (!observationRecord) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -120,7 +126,7 @@ public class PqdifNativeReader {
|
||||
vo.setScale(seriesInfo.scale);
|
||||
vo.setOffset(seriesInfo.offset);
|
||||
} catch (Throwable e) {
|
||||
vo.setDataStatus("DATA_FAILED");
|
||||
vo.setDataStatus(DATA_FAILED);
|
||||
vo.setDataMessage("getSeriesInfo failed, channel=" + channelIndex
|
||||
+ ", series=" + seriesIndex
|
||||
+ ", error=" + e.getMessage());
|
||||
@@ -132,12 +138,12 @@ public class PqdifNativeReader {
|
||||
try {
|
||||
double[] values = observation.getSeriesData(channelIndex, seriesIndex);
|
||||
|
||||
vo.setDataStatus("DATA_SUCCESS");
|
||||
vo.setDataStatus(DATA_SUCCESS);
|
||||
vo.setDataMessage(null);
|
||||
vo.setValueCount(values == null ? 0 : values.length);
|
||||
vo.setFirstValues(firstValues(values, DEFAULT_SAMPLE_VALUE_COUNT));
|
||||
} catch (Throwable e) {
|
||||
vo.setDataStatus("DATA_FAILED");
|
||||
vo.setDataStatus(DATA_FAILED);
|
||||
vo.setDataMessage("getSeriesData failed, channel=" + channelIndex
|
||||
+ ", series=" + seriesIndex
|
||||
+ ", seriesBaseType=" + vo.getSeriesBaseType()
|
||||
@@ -183,4 +189,4 @@ public class PqdifNativeReader {
|
||||
|
||||
return dateTime.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.njcn.gather.tool.parsepqdif.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.param.CsPqdifPathParam;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.param.PqdifParseResultSaveParam;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathDetailVO;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PQDIF 存储记录服务。
|
||||
*/
|
||||
public interface CsPqdifPathService {
|
||||
|
||||
List<CsPqdifPathVO> listPqdifPaths(CsPqdifPathParam.ListParam param);
|
||||
|
||||
JsonNode getPqdifParseMsg(String pqdifId);
|
||||
|
||||
CsPqdifPathDetailVO getPqdifParseDetail(String pqdifId);
|
||||
|
||||
boolean addPqdifPath(CsPqdifPathParam param);
|
||||
|
||||
boolean updatePqdifPath(CsPqdifPathParam.UpdateParam param);
|
||||
|
||||
boolean deletePqdifPath(List<String> ids);
|
||||
|
||||
boolean savePqdifParseResult(String pqdifId, PqdifParseResultSaveParam param);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package com.njcn.gather.tool.parsepqdif.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.njcn.gather.tool.parsepqdif.mapper.CsPqdifPathMapper;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.param.CsPqdifPathParam;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.param.PqdifParseResultSaveParam;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.po.CsPqdifPathPO;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathDetailVO;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.CsPqdifPathVO;
|
||||
import com.njcn.gather.tool.parsepqdif.service.CsPqdifPathService;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* PQDIF 存储记录服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CsPqdifPathServiceImpl implements CsPqdifPathService {
|
||||
|
||||
private static final int STATE_NORMAL = 1;
|
||||
|
||||
private static final int STATE_DELETED = 0;
|
||||
|
||||
private final CsPqdifPathMapper csPqdifPathMapper;
|
||||
|
||||
@Override
|
||||
public List<CsPqdifPathVO> listPqdifPaths(CsPqdifPathParam.ListParam param) {
|
||||
CsPqdifPathParam.ListParam checkedParam = param == null ? new CsPqdifPathParam.ListParam() : param;
|
||||
return csPqdifPathMapper.selectPqdifPathList(
|
||||
trimToNull(checkedParam.getKeyword()),
|
||||
checkedParam.getResult());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode getPqdifParseMsg(String pqdifId) {
|
||||
String id = requireText(pqdifId, "PQDIF记录ID不能为空");
|
||||
CsPqdifPathVO pqdifPath = csPqdifPathMapper.selectPqdifParseMsgById(id);
|
||||
return pqdifPath == null ? null : pqdifPath.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CsPqdifPathDetailVO getPqdifParseDetail(String pqdifId) {
|
||||
String id = requireText(pqdifId, "PQDIF记录ID不能为空");
|
||||
return csPqdifPathMapper.selectPqdifPathDetailById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean addPqdifPath(CsPqdifPathParam param) {
|
||||
CsPqdifPathParam checkedParam = requireParam(param);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
CsPqdifPathPO pqdifPath = buildPqdifPath(checkedParam);
|
||||
pqdifPath.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
pqdifPath.setState(STATE_NORMAL);
|
||||
pqdifPath.setCreateBy(currentUserId());
|
||||
pqdifPath.setCreateTime(now);
|
||||
pqdifPath.setUpdateBy(currentUserId());
|
||||
pqdifPath.setUpdateTime(now);
|
||||
return csPqdifPathMapper.insert(pqdifPath) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean updatePqdifPath(CsPqdifPathParam.UpdateParam param) {
|
||||
CsPqdifPathParam.UpdateParam checkedParam = requireUpdateParam(param);
|
||||
requirePqdifPath(checkedParam.getId());
|
||||
CsPqdifPathPO pqdifPath = buildPqdifPath(checkedParam);
|
||||
pqdifPath.setId(checkedParam.getId());
|
||||
pqdifPath.setUpdateBy(currentUserId());
|
||||
pqdifPath.setUpdateTime(LocalDateTime.now());
|
||||
return csPqdifPathMapper.updateById(pqdifPath) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean deletePqdifPath(List<String> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
throw new IllegalArgumentException("PQDIF记录ID不能为空");
|
||||
}
|
||||
CsPqdifPathPO pqdifPath = new CsPqdifPathPO();
|
||||
pqdifPath.setState(STATE_DELETED);
|
||||
pqdifPath.setUpdateBy(currentUserId());
|
||||
pqdifPath.setUpdateTime(LocalDateTime.now());
|
||||
return csPqdifPathMapper.update(pqdifPath, new LambdaUpdateWrapper<CsPqdifPathPO>()
|
||||
.in(CsPqdifPathPO::getId, ids)
|
||||
.eq(CsPqdifPathPO::getState, STATE_NORMAL)) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean savePqdifParseResult(String pqdifId, PqdifParseResultSaveParam param) {
|
||||
if (param == null) {
|
||||
throw new IllegalArgumentException("PQDIF解析结果不能为空");
|
||||
}
|
||||
CsPqdifPathPO pqdifPath = requirePqdifPath(pqdifId);
|
||||
pqdifPath.setNativeVersion(trimToNull(param.getNativeVersion()));
|
||||
pqdifPath.setRecordCount(param.getRecordCount());
|
||||
pqdifPath.setObservationCount(param.getObservationCount());
|
||||
pqdifPath.setSampleValueCount(param.getSampleValueCount());
|
||||
pqdifPath.setResult(normalizeResult(param.getResult()));
|
||||
pqdifPath.setMsg(param.getMsg());
|
||||
pqdifPath.setJsonStr(trimToNull(param.getJsonStr()));
|
||||
pqdifPath.setUpdateBy(currentUserId());
|
||||
pqdifPath.setUpdateTime(LocalDateTime.now());
|
||||
return csPqdifPathMapper.updateById(pqdifPath) > 0;
|
||||
}
|
||||
|
||||
private CsPqdifPathPO buildPqdifPath(CsPqdifPathParam param) {
|
||||
CsPqdifPathPO pqdifPath = new CsPqdifPathPO();
|
||||
pqdifPath.setName(requireText(param.getName(), "PQDIF名称不能为空"));
|
||||
pqdifPath.setPqdifContent(param.getPqdifContent());
|
||||
return pqdifPath;
|
||||
}
|
||||
|
||||
private CsPqdifPathParam requireParam(CsPqdifPathParam param) {
|
||||
if (param == null) {
|
||||
throw new IllegalArgumentException("PQDIF记录参数不能为空");
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
private CsPqdifPathParam.UpdateParam requireUpdateParam(CsPqdifPathParam.UpdateParam param) {
|
||||
if (param == null) {
|
||||
throw new IllegalArgumentException("PQDIF记录参数不能为空");
|
||||
}
|
||||
requireText(param.getId(), "PQDIF记录ID不能为空");
|
||||
return param;
|
||||
}
|
||||
|
||||
private CsPqdifPathPO requirePqdifPath(String pqdifId) {
|
||||
String id = requireText(pqdifId, "PQDIF记录ID不能为空");
|
||||
CsPqdifPathPO pqdifPath = csPqdifPathMapper.selectById(id);
|
||||
if (pqdifPath == null || !Integer.valueOf(STATE_NORMAL).equals(pqdifPath.getState())) {
|
||||
throw new IllegalArgumentException("PQDIF记录不存在或已删除");
|
||||
}
|
||||
return pqdifPath;
|
||||
}
|
||||
|
||||
private Integer normalizeResult(Integer result) {
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("解析结果不能为空");
|
||||
}
|
||||
if (result != 0 && result != 1) {
|
||||
throw new IllegalArgumentException("解析结果只能是0或1");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String requireText(String value, String message) {
|
||||
String text = trimToNull(value);
|
||||
if (text == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String text = value.trim();
|
||||
return text.isEmpty() ? null : text;
|
||||
}
|
||||
|
||||
private boolean isBlank(String value) {
|
||||
return trimToNull(value) == null;
|
||||
}
|
||||
|
||||
private String currentUserId() {
|
||||
try {
|
||||
String userId = RequestUtil.getUserId();
|
||||
return isBlank(userId) ? "未知用户" : userId;
|
||||
} catch (Exception ex) {
|
||||
return "未知用户";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,87 +3,115 @@ package com.njcn.gather.tool.parsepqdif.service.impl;
|
||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.PqdifParseResponse;
|
||||
import com.njcn.gather.tool.parsepqdif.reader.PqdifNativeReader;
|
||||
import com.njcn.gather.tool.parsepqdif.service.ParsePqdifService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ParsePqdifServiceImpl implements ParsePqdifService {
|
||||
|
||||
private static final String STATUS_FAILED = "FAILED";
|
||||
private static final String DEFAULT_SUFFIX = ".pqd";
|
||||
private static final String PQDIF_SUFFIX = ".pqdif";
|
||||
private static final String TEMP_DIR_NAME = "cn-tool-pqdif-upload";
|
||||
private static final String EMPTY_FILE_MESSAGE = "PQDIF文件不能为空";
|
||||
private static final String UNSUPPORTED_FILE_MESSAGE = "仅支持 .pqd 或 .pqdif 格式文件";
|
||||
private static final String DEFAULT_FAILED_MESSAGE = "PQDIF解析失败";
|
||||
private static final String UNKNOWN_FAILED_REASON = "请检查文件内容或原生解析库状态";
|
||||
|
||||
private final PqdifNativeReader pqdifNativeReader = new PqdifNativeReader();
|
||||
private final PqdifNativeReader pqdifNativeReader;
|
||||
|
||||
@Override
|
||||
public PqdifParseResponse parse(MultipartFile pqdifFile) {
|
||||
if (pqdifFile == null || pqdifFile.isEmpty()) {
|
||||
return failed(null, "PQDIF文件不能为空");
|
||||
return failed(null, EMPTY_FILE_MESSAGE);
|
||||
}
|
||||
|
||||
String originalFilename = pqdifFile.getOriginalFilename();
|
||||
String suffix = getSupportedSuffix(originalFilename);
|
||||
if (suffix == null) {
|
||||
return failed(originalFilename, UNSUPPORTED_FILE_MESSAGE);
|
||||
}
|
||||
|
||||
Path tempFile = null;
|
||||
|
||||
try {
|
||||
tempFile = createTempPqdifFile(pqdifFile);
|
||||
return pqdifNativeReader.read(tempFile, pqdifFile.getOriginalFilename());
|
||||
tempFile = createTempPqdifFile(pqdifFile, suffix);
|
||||
return pqdifNativeReader.read(tempFile, originalFilename);
|
||||
} catch (Exception e) {
|
||||
log.error("PQDIF解析失败,fileName={}", pqdifFile.getOriginalFilename(), e);
|
||||
return failed(pqdifFile.getOriginalFilename(), e.getMessage());
|
||||
log.error("PQDIF解析失败,fileName={}", originalFilename, e);
|
||||
return failed(originalFilename, buildFailedMessage(e));
|
||||
} finally {
|
||||
if (tempFile != null) {
|
||||
try {
|
||||
Files.deleteIfExists(tempFile);
|
||||
} catch (Exception e) {
|
||||
log.warn("删除PQDIF临时文件失败,path={}", tempFile, e);
|
||||
}
|
||||
}
|
||||
deleteTempFile(tempFile);
|
||||
}
|
||||
}
|
||||
|
||||
private Path createTempPqdifFile(MultipartFile pqdifFile) throws Exception {
|
||||
String originalFilename = pqdifFile.getOriginalFilename();
|
||||
String suffix = getSuffix(originalFilename);
|
||||
|
||||
Path uploadDir = Paths.get("D:", "CN_Tool_Runtime", "pqdif-upload");
|
||||
private Path createTempPqdifFile(MultipartFile pqdifFile, String suffix) throws Exception {
|
||||
// 原生解析库只接收文件路径,因此上传内容需先落到系统临时目录。
|
||||
Path uploadDir = Paths.get(System.getProperty("java.io.tmpdir"), TEMP_DIR_NAME);
|
||||
Files.createDirectories(uploadDir);
|
||||
|
||||
String safeFileName = "parse-pqdif-" + System.currentTimeMillis() + "-" +
|
||||
java.util.UUID.randomUUID().toString().replace("-", "") + suffix;
|
||||
|
||||
Path tempFile = uploadDir.resolve(safeFileName);
|
||||
|
||||
Path tempFile = Files.createTempFile(uploadDir, "parse-pqdif-", suffix);
|
||||
try (InputStream inputStream = pqdifFile.getInputStream()) {
|
||||
Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
private String getSuffix(String originalFilename) {
|
||||
if (originalFilename == null) {
|
||||
return ".pqd";
|
||||
private void deleteTempFile(Path tempFile) {
|
||||
if (tempFile == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Files.deleteIfExists(tempFile);
|
||||
} catch (Exception e) {
|
||||
log.warn("删除PQDIF临时文件失败,path={}", tempFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getSupportedSuffix(String originalFilename) {
|
||||
if (originalFilename == null || originalFilename.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = originalFilename.lastIndexOf('.');
|
||||
if (index < 0 || index == originalFilename.length() - 1) {
|
||||
return ".pqd";
|
||||
return null;
|
||||
}
|
||||
|
||||
return originalFilename.substring(index);
|
||||
String suffix = originalFilename.substring(index).toLowerCase(Locale.ROOT);
|
||||
if (DEFAULT_SUFFIX.equals(suffix) || PQDIF_SUFFIX.equals(suffix)) {
|
||||
return suffix;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resolveErrorMessage(Exception e) {
|
||||
String message = e.getMessage();
|
||||
if (message == null || message.trim().isEmpty()) {
|
||||
return UNKNOWN_FAILED_REASON;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private String buildFailedMessage(Exception e) {
|
||||
return DEFAULT_FAILED_MESSAGE + ":" + resolveErrorMessage(e);
|
||||
}
|
||||
|
||||
private PqdifParseResponse failed(String fileName, String message) {
|
||||
PqdifParseResponse response = new PqdifParseResponse();
|
||||
response.setStatus(STATUS_FAILED);
|
||||
response.setMessage(message == null ? "PQDIF解析失败" : message);
|
||||
response.setMessage(message == null ? DEFAULT_FAILED_MESSAGE : message);
|
||||
response.setFileName(fileName);
|
||||
response.setRecordCount(0L);
|
||||
response.setObservationCount(0L);
|
||||
@@ -92,4 +120,4 @@ public class ParsePqdifServiceImpl implements ParsePqdifService {
|
||||
response.setObservations(new ArrayList<PqdifParseResponse.ObservationVO>());
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.gather.tool.parsepqdif.typehandler;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* 将数据库 JSON 文本映射为 Jackson JsonNode,便于接口直接返回结构化解析结果。
|
||||
*/
|
||||
public class JsonNodeTypeHandler extends BaseTypeHandler<JsonNode> {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, JsonNode parameter, JdbcType jdbcType)
|
||||
throws SQLException {
|
||||
ps.setString(i, parameter.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
return parse(rs.getString(columnName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
return parse(rs.getString(columnIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
return parse(cs.getString(columnIndex));
|
||||
}
|
||||
|
||||
private JsonNode parse(String value) throws SQLException {
|
||||
if (value == null || value.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readTree(value);
|
||||
} catch (Exception ex) {
|
||||
throw new SQLException("解析JSON字段失败", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user