提交代码0326
This commit is contained in:
parent
64a3231f01
commit
fc32e0fecd
@ -98,6 +98,12 @@
|
|||||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.opencsv</groupId>
|
||||||
|
<artifactId>opencsv</artifactId>
|
||||||
|
<version>5.7.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- spring-elasticsearch搜素-->
|
<!-- spring-elasticsearch搜素-->
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||||
|
@ -426,12 +426,12 @@ public class TsFilesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询文件内容接口
|
/**********************************
|
||||||
*
|
* 用途说明: 查询文件内容接口
|
||||||
* @param id 文件的id
|
* 参数说明 id 文件的ID
|
||||||
* @return 文件内容的纯文本(UTF-8 编码)
|
* 返回值说明: com.yfd.platform.config.ResponseResult文件内容的纯文本(UTF-8 编码)
|
||||||
*/
|
***********************************/
|
||||||
@Log(module = "实验数据管理", value = "查询文件内容!")
|
@Log(module = "实验数据管理", value = "查询文件内容!")
|
||||||
@GetMapping("/api/files/content")
|
@GetMapping("/api/files/content")
|
||||||
@ApiOperation("查询文件内容")
|
@ApiOperation("查询文件内容")
|
||||||
@ -447,13 +447,12 @@ public class TsFilesController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**********************************
|
||||||
* 保存文件内容接口
|
* 用途说明: 保存文件内容接口
|
||||||
*
|
* 参数说明 id 文件的ID
|
||||||
* @param id 文件的id
|
* 参数说明 content 新的文件内容(HTML/文本)
|
||||||
* @param content 新的文件内容(HTML/文本)
|
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
|
||||||
* @return 操作结果
|
***********************************/
|
||||||
*/
|
|
||||||
@Log(module = "实验数据管理", value = "保存文件内容!")
|
@Log(module = "实验数据管理", value = "保存文件内容!")
|
||||||
@PostMapping("/save/files/content")
|
@PostMapping("/save/files/content")
|
||||||
@ApiOperation("保存文件内容")
|
@ApiOperation("保存文件内容")
|
||||||
@ -470,5 +469,19 @@ public class TsFilesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* 用途说明: 批量修改文件中多行多列的内容
|
||||||
|
* 参数说明 request 要修改的文件信息
|
||||||
|
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
|
||||||
|
***********************************/
|
||||||
|
@Log(module = "实验数据管理", value = "批量修改文件中多行多列的内容!")
|
||||||
|
@PostMapping("/batchModify")
|
||||||
|
@ApiOperation("批量修改文件中多行多列的内容")
|
||||||
|
public ResponseResult batchModifyFile(@RequestBody BatchModifyRequest request) throws IOException {
|
||||||
|
tsFilesService.batchUpdateFile(request.getId(), request.getModifications());
|
||||||
|
return ResponseResult.success("文件保存成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.yfd.platform.modules.experimentalData.domain;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
// 批量修改请求对象
|
||||||
|
@Data
|
||||||
|
public class BatchModifyRequest {
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String id; // 文件ID
|
||||||
|
|
||||||
|
@NotEmpty
|
||||||
|
private List<ModifyCommand> modifications;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.yfd.platform.modules.experimentalData.domain;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
// 单条修改指令
|
||||||
|
@Data
|
||||||
|
public class ModifyCommand {
|
||||||
|
|
||||||
|
@Min(1)
|
||||||
|
private int lineNum; // 行号(从1开始)
|
||||||
|
|
||||||
|
@Min(1)
|
||||||
|
private int colNum; // 列号(从1开始)
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String newValue;
|
||||||
|
}
|
@ -2,10 +2,7 @@ package com.yfd.platform.modules.experimentalData.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.yfd.platform.config.ResponseResult;
|
import com.yfd.platform.config.ResponseResult;
|
||||||
import com.yfd.platform.modules.experimentalData.domain.DualTreeResponse;
|
import com.yfd.platform.modules.experimentalData.domain.*;
|
||||||
import com.yfd.platform.modules.experimentalData.domain.MoveCopyFileFolderRequest;
|
|
||||||
import com.yfd.platform.modules.experimentalData.domain.Parameter;
|
|
||||||
import com.yfd.platform.modules.experimentalData.domain.TsFiles;
|
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
@ -170,12 +167,18 @@ public interface ITsFilesService extends IService<TsFiles> {
|
|||||||
*/
|
*/
|
||||||
String readFileContent(String id) throws IOException;
|
String readFileContent(String id) throws IOException;
|
||||||
|
|
||||||
/**
|
/**********************************
|
||||||
* 保存文件内容接口
|
* 用途说明: 保存文件内容接口
|
||||||
*
|
* 参数说明 id 文件的ID
|
||||||
* @param id 文件的id
|
* 参数说明 content 新的文件内容(HTML/文本)
|
||||||
* @param content 新的文件内容(HTML/文本)
|
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
|
||||||
* @return 操作结果
|
***********************************/
|
||||||
*/
|
|
||||||
void saveFileContent(String id, String content) throws IOException;
|
void saveFileContent(String id, String content) throws IOException;
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* 用途说明: 批量修改文件中多行多列的内容
|
||||||
|
* 参数说明 request 要修改的文件信息
|
||||||
|
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
|
||||||
|
***********************************/
|
||||||
|
void batchUpdateFile(String id, List<ModifyCommand> modifications) throws IOException;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package com.yfd.platform.modules.experimentalData.service.impl;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
|
||||||
|
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
@ -24,6 +26,9 @@ import com.amazonaws.services.s3.model.S3ObjectInputStream;
|
|||||||
import com.amazonaws.util.IOUtils;
|
import com.amazonaws.util.IOUtils;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.opencsv.CSVReader;
|
||||||
|
import com.opencsv.CSVWriter;
|
||||||
|
import com.opencsv.exceptions.CsvValidationException;
|
||||||
import com.yfd.platform.component.ServerSendEventServer;
|
import com.yfd.platform.component.ServerSendEventServer;
|
||||||
import com.yfd.platform.config.ResponseResult;
|
import com.yfd.platform.config.ResponseResult;
|
||||||
import com.yfd.platform.modules.experimentalData.domain.*;
|
import com.yfd.platform.modules.experimentalData.domain.*;
|
||||||
@ -62,7 +67,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
|||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.beans.factory.annotation.Value; // 正确
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.xml.crypto.Data;
|
import javax.xml.crypto.Data;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -108,6 +113,8 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
private List<String> compressSuffixes;
|
private List<String> compressSuffixes;
|
||||||
private final Set<String> addedEntries = new HashSet<>();
|
private final Set<String> addedEntries = new HashSet<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************
|
/**********************************
|
||||||
* 用途说明: 分页查询试验数据管理-文档内容
|
* 用途说明: 分页查询试验数据管理-文档内容
|
||||||
* 参数说明
|
* 参数说明
|
||||||
@ -4263,6 +4270,144 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* 用途说明: 批量修改文件中多行多列的内容
|
||||||
|
* 参数说明 request 要修改的文件信息
|
||||||
|
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
|
||||||
|
***********************************/
|
||||||
|
@Override
|
||||||
|
public void batchUpdateFile(String id, List<ModifyCommand> modifications)throws IOException {
|
||||||
|
StorageSourceConfig config = storageSourceConfigMapper.selectOne(new QueryWrapper<StorageSourceConfig>().eq("name", "filePath"));
|
||||||
|
TsFiles tsFile = tsFilesMapper.selectById(id);
|
||||||
|
if (tsFile == null) {
|
||||||
|
throw new IllegalArgumentException("文件ID不存在: " + id);
|
||||||
|
}
|
||||||
|
Path filePath = Paths.get(config.getValue(), tsFile.getWorkPath(), tsFile.getFileName()).normalize();
|
||||||
|
// 安全校验
|
||||||
|
if (!filePath.startsWith(config.getValue())) {
|
||||||
|
throw new SecurityException("路径越界: " + filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.2 检查文件是否为文本类型
|
||||||
|
validateTextFile(filePath);
|
||||||
|
|
||||||
|
LOGGER.info("批量修改文件: {}, 修改指令数: {}", filePath, modifications.size());
|
||||||
|
|
||||||
|
|
||||||
|
// 3. 创建临时文件(在指定目录下)
|
||||||
|
Path tempDir = Paths.get(config.getValue(), tsFile.getWorkPath()).normalize();
|
||||||
|
if (!Files.exists(tempDir)) {
|
||||||
|
Files.createDirectories(tempDir); // 确保目录存在
|
||||||
|
}
|
||||||
|
|
||||||
|
// 临时文件名格式:原文件名_时间戳.tmp
|
||||||
|
String tempFileName = tsFile.getFileName() + "_" + System.currentTimeMillis() + ".tmp";
|
||||||
|
Path tempPath = tempDir.resolve(tempFileName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 读取文件内容(兼容Java 8)
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applyModifications(lines, modifications);
|
||||||
|
|
||||||
|
// 写入临时文件(兼容Java 8)
|
||||||
|
try (BufferedWriter writer = Files.newBufferedWriter(tempPath, StandardCharsets.UTF_8)) {
|
||||||
|
for (String line : lines) {
|
||||||
|
writer.write(line);
|
||||||
|
writer.newLine(); // 保留原换行符风格
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Files.move(tempPath, filePath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Files.deleteIfExists(tempPath);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用所有修改到文件内容
|
||||||
|
* @param lines 文件每一行的内容
|
||||||
|
* @param modifications 修改指令集合
|
||||||
|
*/
|
||||||
|
private void applyModifications(List<String> lines, List<ModifyCommand> modifications) {
|
||||||
|
modifications.forEach(cmd -> {
|
||||||
|
if (cmd.getLineNum() > lines.size()) {
|
||||||
|
throw new IllegalArgumentException("行号超出范围: " + cmd.getLineNum());
|
||||||
|
}
|
||||||
|
String originalLine = lines.get(cmd.getLineNum() - 1);
|
||||||
|
String modifiedLine = modifyLine(originalLine, cmd.getColNum(), cmd.getNewValue());
|
||||||
|
lines.set(cmd.getLineNum() - 1, modifiedLine);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void validateTextFile(Path filePath) throws IOException {
|
||||||
|
String mimeType = Files.probeContentType(filePath);
|
||||||
|
if (mimeType == null || !mimeType.startsWith("text/")) {
|
||||||
|
throw new IOException("只允许修改文本文件,检测到类型: " + mimeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String modifyTabDelimitedLine(String line, int colNum, String newValue) {
|
||||||
|
String[] columns = line.split("\t", -1); // -1保留空列
|
||||||
|
if (colNum < 1 || colNum > columns.length) {
|
||||||
|
throw new IllegalArgumentException("列号越界: " + colNum);
|
||||||
|
}
|
||||||
|
columns[colNum - 1] = newValue;
|
||||||
|
return String.join("\t", columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String modifyCsvLine(String line, int colNum, String newValue) {
|
||||||
|
try (CSVReader reader = new CSVReader(new StringReader(line))) {
|
||||||
|
String[] columns = reader.readNext();
|
||||||
|
if (colNum < 1 || colNum > columns.length) {
|
||||||
|
throw new IllegalArgumentException("列号越界: " + colNum);
|
||||||
|
}
|
||||||
|
columns[colNum - 1] = newValue;
|
||||||
|
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
try (CSVWriter writer = new CSVWriter(sw)) {
|
||||||
|
writer.writeNext(columns);
|
||||||
|
return sw.toString().trim(); // 去除末尾换行
|
||||||
|
}
|
||||||
|
} catch (IOException | CsvValidationException e) {
|
||||||
|
throw new UncheckedIOException("CSV解析失败", (IOException) e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String modifySpaceDelimitedLine(String line, int colNum, String newValue) {
|
||||||
|
// 处理连续多个空格(保留原始对齐)
|
||||||
|
String[] columns = line.split("\\s+", -1);
|
||||||
|
if (colNum < 1 || colNum > columns.length) {
|
||||||
|
throw new IllegalArgumentException("列号越界: " + colNum);
|
||||||
|
}
|
||||||
|
columns[colNum - 1] = newValue;
|
||||||
|
|
||||||
|
// 重建原始空格对齐(假设原文件用固定空格数分隔)
|
||||||
|
return String.join(" ", columns); // 用4个空格分隔
|
||||||
|
}
|
||||||
|
|
||||||
|
private String modifyLine(String line, int colNum, String newValue) {
|
||||||
|
// 自动检测分隔符类型
|
||||||
|
if (line.contains("\t")) {
|
||||||
|
return modifyTabDelimitedLine(line, colNum, newValue);
|
||||||
|
} else if (line.contains(",")) {
|
||||||
|
return modifyCsvLine(line, colNum, newValue);
|
||||||
|
} else {
|
||||||
|
return modifySpaceDelimitedLine(line, colNum, newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user