添加了pqdif解析的基础功能,开放了一个基础解析接口。
This commit is contained in:
@@ -35,10 +35,41 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.njcn</groupId>
|
||||||
|
<artifactId>pqdif-native-basic-bridge</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<scope>system</scope>
|
||||||
|
<systemPath>${project.basedir}/lib/pqdif-native-basic-bridge-1.0.0-jar-with-dependencies.jar</systemPath>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>parse-pqdif</finalName>
|
<finalName>parse-pqdif</finalName>
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<!-- PQDIF native DLL 和示例文件必须原样复制,不能 filtering -->
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>false</filtering>
|
||||||
|
<includes>
|
||||||
|
<include>pqdif-native/**</include>
|
||||||
|
<include>pqdif-samples/**</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
|
||||||
|
<!-- 其他资源按普通方式复制 -->
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>false</filtering>
|
||||||
|
<excludes>
|
||||||
|
<exclude>pqdif-native/**</exclude>
|
||||||
|
<exclude>pqdif-samples/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/parse-pqdif")
|
@RequestMapping("/api/parse-pqdif")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ParsePqdifController extends BaseController {
|
public class ParsePqdifController extends BaseController {
|
||||||
|
|
||||||
private final ParsePqdifService parsePqdifService;
|
private final ParsePqdifService parsePqdifService;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.njcn.gather.tool.parsepqdif.nativebridge;
|
||||||
|
|
||||||
|
import com.sun.jna.NativeLibrary;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public final class PqdifNativeLibraryLoader {
|
||||||
|
|
||||||
|
private static final String RESOURCE_DLL = "/pqdif-native/win-x64/pqdifbasic.dll";
|
||||||
|
private static final String DLL_NAME = "pqdifbasic.dll";
|
||||||
|
private static final String TEMP_DIR_NAME = "cn-tool-pqdif-native";
|
||||||
|
|
||||||
|
private static volatile boolean prepared;
|
||||||
|
private static Path preparedNativeDir;
|
||||||
|
|
||||||
|
private PqdifNativeLibraryLoader() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized Path ensurePrepared() {
|
||||||
|
if (prepared) {
|
||||||
|
return preparedNativeDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isWindows()) {
|
||||||
|
throw new IllegalStateException("当前接入的是 Windows x64 版 pqdifbasic.dll,非 Windows 环境无法加载");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Path nativeDir = Paths.get(System.getProperty("java.io.tmpdir"), TEMP_DIR_NAME, "win-x64");
|
||||||
|
Files.createDirectories(nativeDir);
|
||||||
|
|
||||||
|
Path dllPath = nativeDir.resolve(DLL_NAME);
|
||||||
|
copyResourceDll(dllPath);
|
||||||
|
|
||||||
|
appendLibraryPath("jna.library.path", nativeDir);
|
||||||
|
appendLibraryPath("java.library.path", nativeDir);
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
preparedNativeDir = nativeDir;
|
||||||
|
prepared = true;
|
||||||
|
return nativeDir;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("准备 pqdifbasic.dll 失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isWindows() {
|
||||||
|
String osName = System.getProperty("os.name", "").toLowerCase(Locale.ROOT);
|
||||||
|
return osName.contains("win");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copyResourceDll(Path dllPath) throws IOException {
|
||||||
|
try (InputStream inputStream = PqdifNativeLibraryLoader.class.getResourceAsStream(RESOURCE_DLL)) {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IOException("classpath 中找不到 " + RESOURCE_DLL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Files.copy(inputStream, dllPath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendLibraryPath(String propertyName, Path nativeDir) {
|
||||||
|
String nativePath = nativeDir.toAbsolutePath().toString();
|
||||||
|
String oldValue = System.getProperty(propertyName);
|
||||||
|
String separator = System.getProperty("path.separator");
|
||||||
|
|
||||||
|
if (oldValue == null || oldValue.trim().isEmpty()) {
|
||||||
|
System.setProperty(propertyName, nativePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!oldValue.toLowerCase(Locale.ROOT).contains(nativePath.toLowerCase(Locale.ROOT))) {
|
||||||
|
System.setProperty(propertyName, nativePath + separator + oldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,8 @@ import io.swagger.annotations.ApiModel;
|
|||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
import java.util.List;
|
||||||
* PQDIF 解析占位响应。
|
|
||||||
*/
|
|
||||||
@Data
|
@Data
|
||||||
@ApiModel("PQDIF解析响应")
|
@ApiModel("PQDIF解析响应")
|
||||||
public class PqdifParseResponse {
|
public class PqdifParseResponse {
|
||||||
@@ -19,4 +18,75 @@ public class PqdifParseResponse {
|
|||||||
|
|
||||||
@ApiModelProperty("文件名")
|
@ApiModelProperty("文件名")
|
||||||
private String fileName;
|
private String fileName;
|
||||||
}
|
|
||||||
|
@ApiModelProperty("native 解析库版本")
|
||||||
|
private String nativeVersion;
|
||||||
|
|
||||||
|
@ApiModelProperty("Record 总数")
|
||||||
|
private Long recordCount;
|
||||||
|
|
||||||
|
@ApiModelProperty("Observation Record 总数")
|
||||||
|
private Long observationCount;
|
||||||
|
|
||||||
|
@ApiModelProperty("每个 Series 返回的样例值数量")
|
||||||
|
private Integer sampleValueCount;
|
||||||
|
|
||||||
|
@ApiModelProperty("Record 列表")
|
||||||
|
private List<RecordInfoVO> records;
|
||||||
|
|
||||||
|
@ApiModelProperty("Observation 列表")
|
||||||
|
private List<ObservationVO> observations;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class RecordInfoVO {
|
||||||
|
private Long recordIndex;
|
||||||
|
private String typeGuid;
|
||||||
|
private String typeName;
|
||||||
|
private Boolean observation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ObservationVO {
|
||||||
|
private Long recordIndex;
|
||||||
|
private String name;
|
||||||
|
private Double timeStartExcelDays;
|
||||||
|
private String timeStartText;
|
||||||
|
private Long channelCount;
|
||||||
|
private List<ChannelInfoVO> channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ChannelInfoVO {
|
||||||
|
private Long channelIndex;
|
||||||
|
private String name;
|
||||||
|
private Long seriesCount;
|
||||||
|
private Long phaseId;
|
||||||
|
private String quantityTypeGuid;
|
||||||
|
private Long quantityMeasuredId;
|
||||||
|
private List<SeriesInfoVO> series;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class SeriesInfoVO {
|
||||||
|
private Long seriesIndex;
|
||||||
|
private Long quantityUnitsId;
|
||||||
|
private String quantityCharacteristicGuid;
|
||||||
|
private String valueTypeGuid;
|
||||||
|
private Long seriesBaseType;
|
||||||
|
private Double scale;
|
||||||
|
private Double offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DATA_SUCCESS / DATA_FAILED
|
||||||
|
*/
|
||||||
|
private String dataStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据读取失败原因
|
||||||
|
*/
|
||||||
|
private String dataMessage;
|
||||||
|
|
||||||
|
private Integer valueCount;
|
||||||
|
private List<Double> firstValues;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
package com.njcn.gather.tool.parsepqdif.reader;
|
||||||
|
|
||||||
|
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 java.nio.file.Path;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class PqdifNativeReader {
|
||||||
|
|
||||||
|
private static final String STATUS_SUCCESS = "SUCCESS";
|
||||||
|
private static final int DEFAULT_SAMPLE_VALUE_COUNT = 5;
|
||||||
|
|
||||||
|
public PqdifParseResponse read(Path pqdifPath, String fileName) {
|
||||||
|
PqdifNativeLibraryLoader.ensurePrepared();
|
||||||
|
|
||||||
|
PqdifParseResponse response = new PqdifParseResponse();
|
||||||
|
response.setStatus(STATUS_SUCCESS);
|
||||||
|
response.setMessage("PQDIF解析完成");
|
||||||
|
response.setFileName(fileName);
|
||||||
|
response.setNativeVersion(PqdifBasicNative.INSTANCE.pqdif_basic_version());
|
||||||
|
response.setSampleValueCount(DEFAULT_SAMPLE_VALUE_COUNT);
|
||||||
|
response.setRecords(new ArrayList<PqdifParseResponse.RecordInfoVO>());
|
||||||
|
response.setObservations(new ArrayList<PqdifParseResponse.ObservationVO>());
|
||||||
|
|
||||||
|
try (PqdifNativeSession session = new PqdifNativeSession()) {
|
||||||
|
session.open(pqdifPath.toAbsolutePath().toString());
|
||||||
|
|
||||||
|
long recordCount = session.getRecordCount();
|
||||||
|
response.setRecordCount(recordCount);
|
||||||
|
|
||||||
|
for (long recordIndex = 0; recordIndex < recordCount; recordIndex++) {
|
||||||
|
PqdifNativeSession.RecordInfo recordInfo = session.getRecordInfo(recordIndex);
|
||||||
|
|
||||||
|
PqdifParseResponse.RecordInfoVO recordVO = new PqdifParseResponse.RecordInfoVO();
|
||||||
|
recordVO.setRecordIndex(recordIndex);
|
||||||
|
recordVO.setTypeGuid(recordInfo.typeGuid);
|
||||||
|
recordVO.setTypeName(recordInfo.typeName);
|
||||||
|
recordVO.setObservation(isObservation(recordInfo));
|
||||||
|
response.getRecords().add(recordVO);
|
||||||
|
|
||||||
|
if (!isObservation(recordInfo)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (PqdifNativeSession.Observation observation = session.openObservation(recordIndex)) {
|
||||||
|
response.getObservations().add(readObservation(recordIndex, observation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.setObservationCount((long) response.getObservations().size());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PqdifParseResponse.ObservationVO readObservation(
|
||||||
|
long recordIndex,
|
||||||
|
PqdifNativeSession.Observation observation) {
|
||||||
|
|
||||||
|
PqdifNativeSession.ObservationInfo info = observation.getInfo();
|
||||||
|
|
||||||
|
PqdifParseResponse.ObservationVO vo = new PqdifParseResponse.ObservationVO();
|
||||||
|
vo.setRecordIndex(recordIndex);
|
||||||
|
vo.setName(info.name);
|
||||||
|
vo.setTimeStartExcelDays(info.timeStartExcelDays);
|
||||||
|
vo.setTimeStartText(toExcelDateTimeText(info.timeStartExcelDays));
|
||||||
|
vo.setChannelCount(info.channelCount);
|
||||||
|
vo.setChannels(new ArrayList<PqdifParseResponse.ChannelInfoVO>());
|
||||||
|
|
||||||
|
for (long channelIndex = 0; channelIndex < info.channelCount; channelIndex++) {
|
||||||
|
PqdifNativeSession.ChannelInfo channelInfo = observation.getChannelInfo(channelIndex);
|
||||||
|
vo.getChannels().add(readChannel(observation, channelIndex, channelInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PqdifParseResponse.ChannelInfoVO readChannel(
|
||||||
|
PqdifNativeSession.Observation observation,
|
||||||
|
long channelIndex,
|
||||||
|
PqdifNativeSession.ChannelInfo channelInfo) {
|
||||||
|
|
||||||
|
PqdifParseResponse.ChannelInfoVO vo = new PqdifParseResponse.ChannelInfoVO();
|
||||||
|
vo.setChannelIndex(channelIndex);
|
||||||
|
vo.setName(channelInfo.name);
|
||||||
|
vo.setSeriesCount(channelInfo.seriesCount);
|
||||||
|
vo.setPhaseId(channelInfo.phaseId);
|
||||||
|
vo.setQuantityTypeGuid(channelInfo.quantityTypeGuid);
|
||||||
|
vo.setQuantityMeasuredId(channelInfo.quantityMeasuredId);
|
||||||
|
vo.setSeries(new ArrayList<PqdifParseResponse.SeriesInfoVO>());
|
||||||
|
|
||||||
|
for (long seriesIndex = 0; seriesIndex < channelInfo.seriesCount; seriesIndex++) {
|
||||||
|
vo.getSeries().add(readSeries(observation, channelIndex, seriesIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PqdifParseResponse.SeriesInfoVO readSeries(
|
||||||
|
PqdifNativeSession.Observation observation,
|
||||||
|
long channelIndex,
|
||||||
|
long seriesIndex) {
|
||||||
|
|
||||||
|
PqdifParseResponse.SeriesInfoVO vo = new PqdifParseResponse.SeriesInfoVO();
|
||||||
|
vo.setSeriesIndex(seriesIndex);
|
||||||
|
|
||||||
|
PqdifNativeSession.SeriesInfo seriesInfo = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
seriesInfo = observation.getSeriesInfo(channelIndex, seriesIndex);
|
||||||
|
|
||||||
|
vo.setQuantityUnitsId(seriesInfo.quantityUnitsId);
|
||||||
|
vo.setQuantityCharacteristicGuid(seriesInfo.quantityCharacteristicGuid);
|
||||||
|
vo.setValueTypeGuid(seriesInfo.valueTypeGuid);
|
||||||
|
vo.setSeriesBaseType(seriesInfo.seriesBaseType);
|
||||||
|
vo.setScale(seriesInfo.scale);
|
||||||
|
vo.setOffset(seriesInfo.offset);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
vo.setDataStatus("DATA_FAILED");
|
||||||
|
vo.setDataMessage("getSeriesInfo failed, channel=" + channelIndex
|
||||||
|
+ ", series=" + seriesIndex
|
||||||
|
+ ", error=" + e.getMessage());
|
||||||
|
vo.setValueCount(0);
|
||||||
|
vo.setFirstValues(new ArrayList<Double>());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
double[] values = observation.getSeriesData(channelIndex, seriesIndex);
|
||||||
|
|
||||||
|
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.setDataMessage("getSeriesData failed, channel=" + channelIndex
|
||||||
|
+ ", series=" + seriesIndex
|
||||||
|
+ ", seriesBaseType=" + vo.getSeriesBaseType()
|
||||||
|
+ ", valueTypeGuid=" + vo.getValueTypeGuid()
|
||||||
|
+ ", characteristicGuid=" + vo.getQuantityCharacteristicGuid()
|
||||||
|
+ ", error=" + e.getMessage());
|
||||||
|
vo.setValueCount(0);
|
||||||
|
vo.setFirstValues(new ArrayList<Double>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isObservation(PqdifNativeSession.RecordInfo recordInfo) {
|
||||||
|
if (recordInfo == null || recordInfo.typeName == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String type = recordInfo.typeName.toLowerCase(Locale.ROOT);
|
||||||
|
return type.contains("observation") || type.contains("tagrecobservation");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Double> firstValues(double[] values, int maxCount) {
|
||||||
|
if (values == null || values.length == 0) {
|
||||||
|
return new ArrayList<Double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = Math.min(values.length, maxCount);
|
||||||
|
List<Double> result = new ArrayList<Double>();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
result.add(values[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toExcelDateTimeText(double excelDays) {
|
||||||
|
long days = (long) Math.floor(excelDays);
|
||||||
|
double dayFraction = excelDays - days;
|
||||||
|
long nanos = Math.round(dayFraction * 24D * 60D * 60D * 1_000_000_000D);
|
||||||
|
|
||||||
|
LocalDateTime dateTime = LocalDateTime.of(1899, 12, 30, 0, 0)
|
||||||
|
.plusDays(days)
|
||||||
|
.plusNanos(nanos);
|
||||||
|
|
||||||
|
return dateTime.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,95 @@
|
|||||||
package com.njcn.gather.tool.parsepqdif.service.impl;
|
package com.njcn.gather.tool.parsepqdif.service.impl;
|
||||||
|
|
||||||
import com.njcn.gather.tool.parsepqdif.pojo.vo.PqdifParseResponse;
|
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 com.njcn.gather.tool.parsepqdif.service.ParsePqdifService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
import java.io.InputStream;
|
||||||
* PQDIF 解析服务实现。
|
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;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class ParsePqdifServiceImpl implements ParsePqdifService {
|
public class ParsePqdifServiceImpl implements ParsePqdifService {
|
||||||
|
|
||||||
private static final String STATUS_NOT_SUPPORTED = "NOT_SUPPORTED";
|
private static final String STATUS_FAILED = "FAILED";
|
||||||
|
|
||||||
|
private final PqdifNativeReader pqdifNativeReader = new PqdifNativeReader();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PqdifParseResponse parse(MultipartFile pqdifFile) {
|
public PqdifParseResponse parse(MultipartFile pqdifFile) {
|
||||||
|
if (pqdifFile == null || pqdifFile.isEmpty()) {
|
||||||
|
return failed(null, "PQDIF文件不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
Path tempFile = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
tempFile = createTempPqdifFile(pqdifFile);
|
||||||
|
return pqdifNativeReader.read(tempFile, pqdifFile.getOriginalFilename());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("PQDIF解析失败,fileName={}", pqdifFile.getOriginalFilename(), e);
|
||||||
|
return failed(pqdifFile.getOriginalFilename(), e.getMessage());
|
||||||
|
} finally {
|
||||||
|
if (tempFile != null) {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(tempFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("删除PQDIF临时文件失败,path={}", tempFile, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
Files.createDirectories(uploadDir);
|
||||||
|
|
||||||
|
String safeFileName = "parse-pqdif-" + System.currentTimeMillis() + "-" +
|
||||||
|
java.util.UUID.randomUUID().toString().replace("-", "") + suffix;
|
||||||
|
|
||||||
|
Path tempFile = uploadDir.resolve(safeFileName);
|
||||||
|
|
||||||
|
try (InputStream inputStream = pqdifFile.getInputStream()) {
|
||||||
|
Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSuffix(String originalFilename) {
|
||||||
|
if (originalFilename == null) {
|
||||||
|
return ".pqd";
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = originalFilename.lastIndexOf('.');
|
||||||
|
if (index < 0 || index == originalFilename.length() - 1) {
|
||||||
|
return ".pqd";
|
||||||
|
}
|
||||||
|
|
||||||
|
return originalFilename.substring(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PqdifParseResponse failed(String fileName, String message) {
|
||||||
PqdifParseResponse response = new PqdifParseResponse();
|
PqdifParseResponse response = new PqdifParseResponse();
|
||||||
response.setStatus(STATUS_NOT_SUPPORTED);
|
response.setStatus(STATUS_FAILED);
|
||||||
response.setMessage("PQDIF解析功能待实现");
|
response.setMessage(message == null ? "PQDIF解析失败" : message);
|
||||||
response.setFileName(pqdifFile == null ? null : pqdifFile.getOriginalFilename());
|
response.setFileName(fileName);
|
||||||
|
response.setRecordCount(0L);
|
||||||
|
response.setObservationCount(0L);
|
||||||
|
response.setSampleValueCount(0);
|
||||||
|
response.setRecords(new ArrayList<PqdifParseResponse.RecordInfoVO>());
|
||||||
|
response.setObservations(new ArrayList<PqdifParseResponse.ObservationVO>());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user