优化代码提交

This commit is contained in:
lilin 2025-06-19 11:25:40 +08:00
parent f7a3023629
commit e2ea3338f1
38 changed files with 3538 additions and 2246 deletions

View File

@ -2,10 +2,16 @@ package com.yfd.platform.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.yfd.platform.utils.TableNameContextHolder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/******************************
* 用途说明:
* 作者姓名: pcj
@ -16,11 +22,36 @@ public class MybitsPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 创建动态表名拦截器
DynamicTableNameInnerInterceptor dynamicInterceptor = new DynamicTableNameInnerInterceptor();
// 创建表名处理器映射
Map<String, TableNameHandler> handlerMap = new HashMap<>();
// ts_files 表添加处理器
handlerMap.put("ts_files", new TableNameHandler() {
@Override
public String dynamicTableName(String sql, String tableName) {
String taskCode = TableNameContextHolder.getTaskCode();
if (taskCode == null || taskCode.isEmpty()) {
throw new IllegalArgumentException("任务编码不能为空");
}
return "ts_files_" + taskCode;
}
});
// 设置处理器映射
dynamicInterceptor.setTableNameHandlerMap(handlerMap);
// 添加动态表名拦截器
interceptor.addInnerInterceptor(dynamicInterceptor);
// 添加分页拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

View File

@ -167,12 +167,12 @@ public class TsFilesController {
@PostMapping("/deleteTsFilesById")
@ApiOperation("根据ID删除试验数据管理文档内容")
@PreAuthorize("@el.check('del:tsFiles')")
public ResponseResult deleteTsFilesById(@RequestParam String id, @RequestParam String type) {
if (StrUtil.isBlank(id)) {
public ResponseResult deleteTsFilesById(@RequestParam String id, @RequestParam String type,@RequestParam String taskId) {
if (StrUtil.isBlank(id) || StrUtil.isBlank(taskId)) {
return ResponseResult.error("参数为空");
}
List<String> dataset = Arrays.asList(id);
return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type));
return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type,taskId));
}
/**********************************
@ -185,14 +185,14 @@ public class TsFilesController {
@PostMapping("/deleteTsFilesByIds")
@ApiOperation("批量删除试验数据管理文档内容")
@PreAuthorize("@el.check('del:tsFiles')")
public ResponseResult deleteTsFilesByIds(@RequestParam String ids, @RequestParam String type) {
if (StrUtil.isBlank(ids)) {
public ResponseResult deleteTsFilesByIds(@RequestParam String ids, @RequestParam String type,@RequestParam String taskId) {
if (StrUtil.isBlank(ids) || StrUtil.isBlank(taskId)) {
return ResponseResult.error("参数为空");
}
String[] splitIds = ids.split(",");
// 数组转集合
List<String> dataset = Arrays.asList(splitIds);
return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type));
return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type,taskId));
}
/**************************压缩 解压缩********************************/
@ -211,13 +211,13 @@ public class TsFilesController {
@Log(module = "实验数据管理", value = "压缩文件夹接口!")
@PostMapping("/compress")
@ApiOperation("压缩文件夹接口")
public ResponseResult compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId, String path) {
public ResponseResult compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId, String path,String taskId) {
try {
if (StrUtil.isBlank(ids) && StrUtil.isBlank(compressedFormat) && StrUtil.isBlank(compressedName) && StrUtil.isBlank(compressedPath) && StrUtil.isBlank(path)) {
if (StrUtil.isBlank(ids) && StrUtil.isBlank(compressedFormat) && StrUtil.isBlank(compressedName) && StrUtil.isBlank(compressedPath) && StrUtil.isBlank(path) && StrUtil.isBlank(taskId)) {
return ResponseResult.error("参数为空");
}
return ResponseResult.success(tsFilesService.compressFolder(ids, compressedFormat, compressedName, compressedPath, covered, parentId, path));
return ResponseResult.success(tsFilesService.compressFolder(ids, compressedFormat, compressedName, compressedPath, covered, parentId, path,taskId));
} catch (Exception e) {
System.out.print("压缩异常原因" + e);
return ResponseResult.error("压缩失败");
@ -235,12 +235,12 @@ public class TsFilesController {
@Log(module = "实验数据管理", value = "解压缩接口!")
@PostMapping("/decompression")
@ApiOperation("解压缩接口")
public ResponseResult decompressionFolder(String id, String decompressionPath, String parentId, String path) {
public ResponseResult decompressionFolder(String id, String decompressionPath, String parentId, String path,String taskId) {
try {
if (StrUtil.isBlank(id)) {
if (StrUtil.isBlank(id)|| StrUtil.isBlank(taskId)) {
return ResponseResult.error("参数为空");
}
return ResponseResult.success(tsFilesService.decompressionFolder(id, decompressionPath, parentId, path));
return ResponseResult.success(tsFilesService.decompressionFolder(id, decompressionPath, parentId, path,taskId));
} catch (Exception e) {
System.out.print("解压缩异常原因" + e);
return ResponseResult.error("解压缩失败");
@ -654,12 +654,12 @@ public class TsFilesController {
@Log(module = "实验数据管理", value = "实时获取轨迹数据!")
@PostMapping("/startSimpleNavi")
@ApiOperation("实时获取轨迹数据")
public ResponseResult startSimpleNavi(String id, int samTimes, String token) {
public ResponseResult startSimpleNavi(String id, int samTimes, String token,String taskId) {
try {
// 使用线程池异步执行任务
CompletableFuture.runAsync(() -> {
try {
tsFilesService.batchSendNaviOutDataJob(id, samTimes, token);
tsFilesService.batchSendNaviOutDataJob(id, samTimes, token,taskId);
} catch (Exception e) {
e.printStackTrace();
}
@ -694,12 +694,12 @@ public class TsFilesController {
@Log(module = "实验数据管理", value = "查询文件内容!")
@GetMapping("/api/files/content")
@ApiOperation("查询文件内容")
public ResponseResult getFileContent(@RequestParam String id) {
public ResponseResult getFileContent(@RequestParam String id,String taskId) {
try {
if (StrUtil.isBlank(id)) {
if (StrUtil.isBlank(id) && StrUtil.isBlank(taskId)) {
return ResponseResult.error("参数为空");
}
String content = tsFilesService.readFileContent(id);
String content = tsFilesService.readFileContent(id, taskId);
return ResponseResult.successData(content);
} catch (SecurityException | IOException e) {
return ResponseResult.error("非法操作: " + e.getMessage());
@ -715,12 +715,12 @@ public class TsFilesController {
@Log(module = "实验数据管理", value = "保存文件内容!")
@PostMapping("/save/files/content")
@ApiOperation("保存文件内容")
public ResponseResult saveFileContent(String id, String content) {
public ResponseResult saveFileContent(String id, String content,String taskId) {
try {
if (StrUtil.isBlank(id) && StrUtil.isBlank(content)) {
if (StrUtil.isBlank(id) && StrUtil.isBlank(content) && StrUtil.isBlank(taskId)) {
return ResponseResult.error("参数为空");
}
tsFilesService.saveFileContent(id, content);
tsFilesService.saveFileContent(id, content, taskId);
return ResponseResult.success("文件保存成功");
} catch (SecurityException | IOException e) {
return ResponseResult.error("非法操作: " + e.getMessage());
@ -737,7 +737,7 @@ public class TsFilesController {
@PostMapping("/batchModify")
@ApiOperation("批量修改文件中多行多列的内容")
public ResponseResult batchModifyFile(@RequestBody BatchModifyRequest request) throws IOException {
tsFilesService.batchUpdateFile(request.getId(), request.getModifications());
tsFilesService.batchUpdateFile(request.getId(), request.getModifications(),request.getTaskId());
return ResponseResult.success("文件保存成功");
}
@ -749,12 +749,12 @@ public class TsFilesController {
@Log(module = "实验数据管理", value = "获取文件url")
@PostMapping("/obtainUrl")
@ApiOperation("获取文件url")
public ResponseResult obtainUrl(String id, String type) {
if (StrUtil.isBlank(id) && StrUtil.isBlank(type)) {
public ResponseResult obtainUrl(String id, String type,String taskId) {
if (StrUtil.isBlank(id) && StrUtil.isBlank(type) && StrUtil.isBlank(type)) {
return ResponseResult.error("参数为空");
}
//查询本地树和minio树
FileItemResult fileItemResult = tsFilesService.obtainUrl(id, type);
FileItemResult fileItemResult = tsFilesService.obtainUrl(id, type,taskId);
return ResponseResult.successData(fileItemResult);
}
}

View File

@ -184,9 +184,7 @@ public class TsTaskController {
@ResponseBody
//@PreAuthorize("@el.check('select:devicesignal')")
public ResponseResult listTsTask() {
LambdaQueryWrapper<TsTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(TsTask::getTaskStartdate);
List<TsTask> tsTasks = tsTaskService.list(queryWrapper);
List<TsTask> tsTasks = tsTaskService.listTsTask();
return ResponseResult.successData(tsTasks);
}
}

View File

@ -13,6 +13,9 @@ public class BatchModifyRequest {
@NotBlank
private String id; // 文件ID
@NotBlank
private String taskId; // 任务ID
@NotEmpty
private List<ModifyCommand> modifications;
}

View File

@ -12,5 +12,6 @@ public class MoveCopyFileFolderRequest {
private String newFileName;
private String rename;
private String type;
private String taskId;
}

View File

@ -7,5 +7,6 @@ import java.util.List;
@Data
public class Parameter {
public List<ParameterList> parameterLists;
public String taskId;
// public String parameterLists;
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.modules.experimentalData.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -138,7 +139,21 @@ public class TsTask implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDate taskEnddate;
/**
* 本地存储空间id
*/
private Integer localStorageId;
/**
* 备份存储空间id
*/
private Integer backupStorageId;
/**
* 上传用到KEYTODO 增加用于前端展示
*/
@TableField(exist = false)
private String key;
}

View File

@ -21,4 +21,7 @@ public interface TsFilesMapper extends BaseMapper<TsFiles> {
int updateParentIdByPathHierarchy(@Param("taskId") String taskId, @Param("nodeId") String nodeId);
int countFiles(@Param("id") String id);
void updateTsFileByPath(@Param("taskId") String taskId,@Param("oldBasePath") String oldBasePath,@Param("newBasePath") String newBasePath);
}

View File

@ -60,7 +60,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* 参数说明 type local还是minio
* 返回值说明: com.yfd.platform.config.ResponseResult 返回批量删除成功或失败
***********************************/
String deleteTsFilesByIds(List<String> dataset, String type);
String deleteTsFilesByIds(List<String> dataset, String type, String taskId);
/**********************************
* 用途说明: 压缩文件夹接口
@ -73,7 +73,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* 参数说明 path 根目录 /项目名/节点名称/
* 返回值说明: com.yfd.platform.config.ResponseResult
***********************************/
String compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId,String path) throws FileNotFoundException;
String compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId,String path,String taskId) throws FileNotFoundException;
/**********************************
* 用途说明: 解压缩接口
@ -83,7 +83,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* 参数说明 path 根目录 /项目名/节点名称/
* 返回值说明: com.yfd.platform.config.ResponseResult
***********************************/
String decompressionFolder(String id, String decompressionPath, String parentId, String path);
String decompressionFolder(String id, String decompressionPath, String parentId, String path,String taskId);
/**********************************
* 用途说明: 将文件上传到备份空间
@ -144,7 +144,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* 参数说明 token SSE连接的token
* 返回值说明: com.yfd.platform.config.ResponseResult
***********************************/
void batchSendNaviOutDataJob(String id, int samTimes, String token);
void batchSendNaviOutDataJob(String id, int samTimes, String token,String taskId);
/**
* 查询文件内容接口
@ -152,7 +152,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* @param id 文件的id
* @return 文件内容的纯文本UTF-8 编码
*/
String readFileContent(String id) throws IOException;
String readFileContent(String id,String taskId) throws IOException;
/**********************************
* 用途说明: 保存文件内容接口
@ -160,14 +160,14 @@ public interface ITsFilesService extends IService<TsFiles> {
* 参数说明 content 新的文件内容HTML/文本
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
***********************************/
void saveFileContent(String id, String content) throws IOException;
void saveFileContent(String id, String content,String taskId) throws IOException;
/**********************************
* 用途说明: 批量修改文件中多行多列的内容
* 参数说明 request 要修改的文件信息
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
***********************************/
void batchUpdateFile(String id, List<ModifyCommand> modifications) throws IOException;
void batchUpdateFile(String id, List<ModifyCommand> modifications,String taskId) throws IOException;
/**********************************
* 用途说明: 文件自动备份
@ -198,7 +198,7 @@ public interface ITsFilesService extends IService<TsFiles> {
* 参数说明 id 文件夹ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回文件信息
***********************************/
FileItemResult obtainUrl(String id, String type);
FileItemResult obtainUrl(String id, String type,String taskId);
/**********************************
* 用途说明: 对比本地有minio没有的文件差异

View File

@ -64,4 +64,6 @@ public interface ITsTaskService extends IService<TsTask> {
* 返回值说明: com.yfd.platform.config.ResponseResult 返回删除成功或者失败
***********************************/
Object confirmDeleteTask(List<String> dataset);
List<TsTask> listTsTask();
}

View File

@ -22,21 +22,27 @@ import com.yfd.platform.modules.experimentalData.mapper.TsTaskMapper;
import com.yfd.platform.modules.experimentalData.service.ITsFilesService;
import com.yfd.platform.modules.experimentalData.service.ITsNodesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.specialDocument.domain.Nodes;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper;
import com.yfd.platform.modules.storage.mapper.StorageSourceMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.BatchDeleteRequest;
import com.yfd.platform.modules.storage.model.request.NewFolderRequest;
import com.yfd.platform.modules.storage.model.request.RenameFolderRequest;
import com.yfd.platform.modules.storage.model.result.FileItemResult;
import com.yfd.platform.modules.storage.service.StorageSourceService;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.utils.StringUtils;
import com.yfd.platform.utils.TableNameContextHolder;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
@ -93,6 +99,11 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
@Resource
private StorageSourceConfigMapper storageSourceConfigMapper;
@Resource
private StorageSourceMapper storageSourceMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
//顶级父节点 Top level parent node
public static final String TOP_LEVEL_PARENT_NODE = "00";
@ -289,76 +300,93 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
@Override
@Transactional(rollbackFor = Exception.class) // 添加事务注解遇到异常时回滚
public ResponseResult addTsNodes(TsNodes tsnodes) {
//查询文件表 如果有一样的名称不能新增
List<TsFiles> tsFiles = tsFilesMapper.selectList(new QueryWrapper<TsFiles>()
.eq("task_id", tsnodes.getTaskId())
.eq("parent_id", "00")
.eq("file_name", tsnodes.getNodeName())
.eq("is_file", "FOLDER"));
if (tsFiles.size() > 0) {
return ResponseResult.error("数据管理中存在该文件夹!");
}
// 校验文件名是否包含非法字符
String nodeName = tsnodes.getNodeName();
if (containsInvalidCharacters(nodeName)) {
return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*");
}
// 差不多的流程 就是提出来 然后判断 如果两个 中有一个是true
//获取当前登录用户
UsernamePasswordAuthenticationToken authentication =
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
LoginUser loginuser = (LoginUser) authentication.getPrincipal();
//创建人是当前登录人
tsnodes.setCreator(loginuser.getUsername());
//当前操作时间
LocalDateTime now = LocalDateTime.now();
// 转换为 Timestamp
Timestamp currentTime = Timestamp.valueOf(now);
tsnodes.setCreateTime(currentTime);
//通过获取上级节点的条数 设置节点顺序
QueryWrapper<TsNodes> queryWrapperNodeOrder = new QueryWrapper<>();
int orderno = this.count(queryWrapperNodeOrder.eq("parent_id", tsnodes.getParentId())) + 1;
//判断节点名称是否存在
QueryWrapper<TsNodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("node_name", tsnodes.getNodeName());//名称
queryWrapper.eq("task_id", tsnodes.getTaskId());//所属任务ID
queryWrapper.eq("parent_id", tsnodes.getParentId());//所属任务ID
int count = tsNodesMapper.selectCount(queryWrapper);
// 大于0说明 区域名称重复
if (count > 0) {
return ResponseResult.error("节点名称已存在!");
}
//序号
tsnodes.setNodeOrder(orderno);
// 初始化变量
ResponseResult result = ResponseResult.error();
int valueAdded = tsNodesMapper.insert(tsnodes);
if (valueAdded == 1) {
LOGGER.info("tsnodes表结构增加成功");
try {
TsTask tsTask = tsTaskMapper.selectById(tsnodes.getTaskId());
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
//查询文件表 如果有一样的名称不能新增
List<TsFiles> tsFiles = tsFilesMapper.selectList(new QueryWrapper<TsFiles>()
.eq("task_id", tsnodes.getTaskId())
.eq("parent_id", "00")
.eq("file_name", tsnodes.getNodeName())
.eq("is_file", "FOLDER"));
if (tsFiles.size() > 0) {
return ResponseResult.error("数据管理中存在该文件夹!");
}
// 校验文件名是否包含非法字符
String nodeName = tsnodes.getNodeName();
if (containsInvalidCharacters(nodeName)) {
return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*");
}
// 差不多的流程 就是提出来 然后判断 如果两个 中有一个是true
//获取当前登录用户
UsernamePasswordAuthenticationToken authentication =
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
LoginUser loginuser = (LoginUser) authentication.getPrincipal();
//创建人是当前登录人
tsnodes.setCreator(loginuser.getUsername());
//当前操作时间
LocalDateTime now = LocalDateTime.now();
// 转换为 Timestamp
Timestamp currentTime = Timestamp.valueOf(now);
tsnodes.setCreateTime(currentTime);
//通过获取上级节点的条数 设置节点顺序
QueryWrapper<TsNodes> queryWrapperNodeOrder = new QueryWrapper<>();
int orderno = this.count(queryWrapperNodeOrder.eq("parent_id", tsnodes.getParentId())) + 1;
//判断节点名称是否存在
QueryWrapper<TsNodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("node_name", tsnodes.getNodeName());//名称
queryWrapper.eq("task_id", tsnodes.getTaskId());//所属任务ID
queryWrapper.eq("parent_id", tsnodes.getParentId());//所属任务ID
int count = tsNodesMapper.selectCount(queryWrapper);
// 大于0说明 区域名称重复
if (count > 0) {
return ResponseResult.error("节点名称已存在!");
}
//序号
tsnodes.setNodeOrder(orderno);
//新增节点的时候 创建文件夹
NewFolderRequest newFolderRequest = new NewFolderRequest();
newFolderRequest.setName(tsnodes.getNodeName());//新建的文件夹名称,示例值(/a/b/c)
newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
newFolderRequest.setPath(tsnodes.getPath());//请求路径,示例值(/)
newFolderRequest.setStorageKey("local");//存储源 key,示例值(local minio sdlocal)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
if (flag) {
return ResponseResult.success();
int valueAdded = tsNodesMapper.insert(tsnodes);
if (valueAdded == 1) {
LOGGER.info("tsnodes表结构增加成功");
//新增节点的时候 创建文件夹
NewFolderRequest newFolderRequest = new NewFolderRequest();
newFolderRequest.setName(tsnodes.getNodeName());//新建的文件夹名称,示例值(/a/b/c)
newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
newFolderRequest.setPath(tsnodes.getPath());//请求路径,示例值(/)
newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
if (flag) {
result = ResponseResult.success();
} else {
LOGGER.error("节点新增成功但是local创建文件失败");
result = ResponseResult.error("物理文件夹创建失败");
}
return result;
} else {
LOGGER.error("节点新增成功但是local创建文件失败");
LOGGER.error("tsnodes表结构增加失败");
return ResponseResult.error();
}
} else {
LOGGER.error("tsnodes表结构增加失败");
return ResponseResult.error();
} catch (Exception e) {
// 异常处理
LOGGER.error("添加节点时发生异常: {}", e.getMessage(), e);
return ResponseResult.error("系统错误: " + e.getMessage());
} finally {
TableNameContextHolder.clear();
return result;
}
}
@ -380,45 +408,99 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
@Override
public ResponseResult updateTsNodes(TsNodes tsnodes) {
// 校验文件名是否包含非法字符
String nodeName = tsnodes.getNodeName();
if (containsInvalidCharacters(nodeName)) {
return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*");
}
//查询没改之前的节点名称
TsNodes nodesold = tsNodesMapper.selectById(tsnodes.getNodeId());
try {
TsTask tsTask = tsTaskMapper.selectById(tsnodes.getTaskId());
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
//老的节点名称
String nodeNameOld = null;
if (ObjUtil.isNotEmpty(nodesold)) {
nodeNameOld = nodesold.getNodeName();
}
// 校验文件名是否包含非法字符
String nodeName = tsnodes.getNodeName();
if (containsInvalidCharacters(nodeName)) {
return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*");
}
//获取当前登录用户
UsernamePasswordAuthenticationToken authentication =
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
LoginUser loginuser = (LoginUser) authentication.getPrincipal();
//创建人是当前登录人
tsnodes.setCreator(loginuser.getUsername());
// 查询旧节点名称
TsNodes nodesold = tsNodesMapper.selectById(tsnodes.getNodeId());
String nodeNameOld = ObjUtil.isNotEmpty(nodesold) ? nodesold.getNodeName() : null;
//判断节点名称是否存在
QueryWrapper<TsNodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("node_name", tsnodes.getNodeName());//名称
queryWrapper.eq("task_id", tsnodes.getTaskId());//所属任务ID
queryWrapper.eq("parent_id", tsnodes.getParentId());//所属任务ID
int count = tsNodesMapper.selectCount(queryWrapper);
// 大于0说明 区域名称重复
if (count > 0) {
return ResponseResult.error("节点名称已存在!");
}
int valueAdded = tsNodesMapper.updateById(tsnodes);
if (valueAdded == 1) {
LOGGER.info("tsnodes表结构修改成功");
return ResponseResult.success();
} else {
LOGGER.error("tsnodes表结构修改失败");
return ResponseResult.error();
// 获取当前登录用户
UsernamePasswordAuthenticationToken authentication =
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
LoginUser loginuser = (LoginUser) authentication.getPrincipal();
// 设置创建人
tsnodes.setCreator(loginuser.getUsername());
// 判断节点名称是否存在
QueryWrapper<TsNodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("node_name", tsnodes.getNodeName())
.eq("task_id", tsnodes.getTaskId())
.eq("parent_id", tsnodes.getParentId());
int count = tsNodesMapper.selectCount(queryWrapper);
if (count > 0) {
return ResponseResult.error("节点名称已存在!");
}
// 更新节点信息
int valueAdded = tsNodesMapper.updateById(tsnodes);
// 2. 构建新旧路径
String oldBasePath = tsnodes.getPath() + nodeNameOld + "/";
String newBasePath = tsnodes.getPath() + nodeName + "/";
//4.更新文件表ts_files表 根据所属项目ID 老路径 和新路径
tsFilesMapper.updateTsFileByPath(tsnodes.getTaskId(), oldBasePath, newBasePath);
//获取项目下面的所有子节点 都清除缓存
List<TsNodes> nodesList = tsNodesMapper.selectList(new QueryWrapper<TsNodes>().eq("task_id", tsnodes.getTaskId()));
if ((nodesList != null) && (nodesList.size() > 0)) {
for (TsNodes node : nodesList) {
//todo 修改节点成功以后 删除redis
for (int page = 1; page <= 5; page++) {
String redisKey = "tsfiles_" + node.getTaskId() + "_" + node.getNodeId() + "_parentId" + node.getParentId() + "_page_" + page;
redisTemplate.delete(redisKey);
}
}
}
//判断如果更新了节点名称
if (!nodeName.equals(nodeNameOld)) {
if (valueAdded == 1) {
//修改文件名称
RenameFolderRequest renameFolderRequest = new RenameFolderRequest();
renameFolderRequest.setName(nodeNameOld);//重命名的原文件夹名称,示例值(movie)
renameFolderRequest.setNewName(nodeName);// 重命名后的文件名称,示例值(music)
renameFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
renameFolderRequest.setPath(tsnodes.getPath());//请求路径,示例值(/)
renameFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey());
boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName());
if (flag) {
return ResponseResult.success("重命名成功");
} else {
LOGGER.error("节点修改成功,但是本地修改文件名失败");
return ResponseResult.error("重命名失败");
}
} else {
LOGGER.error("节点修改失败");
return ResponseResult.error();
}
} else {
if (valueAdded == 1) {
return ResponseResult.success("重命名成功");
} else {
return ResponseResult.error("重命名失败");
}
}
} catch (Exception e) {
LOGGER.error("更新试验任务节点时发生异常: {}", e.getMessage(), e);
return ResponseResult.error("系统错误,请稍后重试");
} finally {
TableNameContextHolder.clear();
}
}
@ -430,80 +512,92 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
***********************************/
@Override
public boolean deleteTsNodesById(String id, String path) {
//根据ID 查询当前数据
TsNodes tsNodes = tsNodesMapper.selectById(id);
//删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构
//查询所有的子节点
List<TsNodes> tsNodesList = selectChildrentsNodes(tsNodes.getNodeId(), tsNodes.getTaskId());
// 提取所有节点的 ID
List<String> nodeIds = tsNodesList.stream()
.map(TsNodes::getNodeId) // 获取每个节点的 ID
.collect(Collectors.toList());
//修改项目ID 和所有节点id的workPath字段为空
if (CollectionUtils.isNotEmpty(nodeIds)) {
// 4. 批量更新将这些节点的文件工作路径置空
LambdaUpdateWrapper<TsFiles> updateWrapper1 = new LambdaUpdateWrapper<>();
updateWrapper1.in(TsFiles::getNodeId, nodeIds).eq(TsFiles::getTaskId, tsNodes.getTaskId()).set(TsFiles::getWorkPath, "");
tsFilesMapper.update(null, updateWrapper1);
try {
//根据ID 查询当前数据
TsNodes tsNodes = tsNodesMapper.selectById(id);
TsTask tsTask = tsTaskMapper.selectById(tsNodes.getTaskId());
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
//删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构
//查询所有的子节点
List<TsNodes> tsNodesList = selectChildrentsNodes(tsNodes.getNodeId(), tsNodes.getTaskId());
// 提取所有节点的 ID
List<String> nodeIds = tsNodesList.stream()
.map(TsNodes::getNodeId) // 获取每个节点的 ID
.collect(Collectors.toList());
//修改项目ID 和所有节点id的workPath字段为空
if (CollectionUtils.isNotEmpty(nodeIds)) {
// 4. 批量更新将这些节点的文件工作路径置空
LambdaUpdateWrapper<TsFiles> updateWrapper1 = new LambdaUpdateWrapper<>();
updateWrapper1.in(TsFiles::getNodeId, nodeIds).eq(TsFiles::getTaskId, tsNodes.getTaskId()).set(TsFiles::getWorkPath, "");
tsFilesMapper.update(null, updateWrapper1);
// 5. 删除符合条件的文件记录
LambdaQueryWrapper<TsFiles> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.in(TsFiles::getNodeId, nodeIds)
.eq(TsFiles::getTaskId, tsNodes.getTaskId())
.and(wrapper -> wrapper.isNull(TsFiles::getBackupPath).or().eq(TsFiles::getBackupPath, ""))
.and(wrapper -> wrapper.isNull(TsFiles::getWorkPath).or().eq(TsFiles::getWorkPath, ""));
tsFilesMapper.delete(deleteWrapper);
}
// 5. 删除符合条件的文件记录
LambdaQueryWrapper<TsFiles> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.in(TsFiles::getNodeId, nodeIds)
.eq(TsFiles::getTaskId, tsNodes.getTaskId())
.and(wrapper -> wrapper.isNull(TsFiles::getBackupPath).or().eq(TsFiles::getBackupPath, ""))
.and(wrapper -> wrapper.isNull(TsFiles::getWorkPath).or().eq(TsFiles::getWorkPath, ""));
tsFilesMapper.delete(deleteWrapper);
}
//删除当前节点的文件夹 todo 这个地方改动
// 删除 sdlocal 中的文件夹
List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem();
deleteItemData.setName(tsNodes.getNodeName());
deleteItemData.setPassword("");
deleteItemData.setPath(path);
deleteItemData.setType(FileTypeEnum.FOLDER);
deleteItemList.add(deleteItemData);
//删除当前节点的文件夹 todo 这个地方改动
// 删除 sdlocal 中的文件夹
List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem();
deleteItemData.setName(tsNodes.getNodeName());
deleteItemData.setPassword("");
deleteItemData.setPath(path);
deleteItemData.setType(FileTypeEnum.FOLDER);
deleteItemList.add(deleteItemData);
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey("local");
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);
for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) {
boolean flag = false;
try {
if (deleteItem.getType() == FileTypeEnum.FILE) {
flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName());
} else if (deleteItem.getType() == FileTypeEnum.FOLDER) {
flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName());
}
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);
for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) {
boolean flag = false;
try {
if (deleteItem.getType() == FileTypeEnum.FILE) {
flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName());
} else if (deleteItem.getType() == FileTypeEnum.FOLDER) {
flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName());
}
if (flag) {
deleteSuccessCount++;
} else {
if (flag) {
deleteSuccessCount++;
} else {
deleteFailCount++;
}
} catch (Exception e) {
LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e);
deleteFailCount++;
}
} catch (Exception e) {
LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e);
deleteFailCount++;
}
}
if (deleteSuccessCount >= 1) {
// 删除当前节点
int deleteCount = tsNodesMapper.deleteBatchIds(nodeIds);
if (deleteCount >= 1) {
LOGGER.info("tsnodes表结删除改成功");
return true;
if (deleteSuccessCount >= 1) {
// 删除当前节点
int deleteCount = tsNodesMapper.deleteBatchIds(nodeIds);
if (deleteCount >= 1) {
LOGGER.info("tsnodes表结删除改成功");
return true;
} else {
LOGGER.error("tsnodes表结构删除失败");
return false;
}
} else {
LOGGER.error("tsnodes表结构删除失败");
return false;
}
} else {
} catch (Exception e) {
LOGGER.error("删除试验任务节点时发生异常: {}", e.getMessage(), e);
return false;
} finally {
TableNameContextHolder.clear();
}
}
private List<TsNodes> selectChildrentsNodes(String parentId, String taskId) {
@ -559,7 +653,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
}
//批量删除TsFiles表数据
if (dataset.size() > 0) {
tsFilesService.deleteTsFilesByIds(dataset, "local");
tsFilesService.deleteTsFilesByIds(dataset, "local", taskId);
}
}
}
@ -580,6 +674,9 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
if (tsNodesList.size() == 0) {
return true;
}
TsTask tsTask = tsTaskMapper.selectById(taskId);
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
for (TsNodes tsNodes : tsNodesList) {
//删除文件表
@ -595,7 +692,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey("local");
batchDeleteRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);
@ -643,10 +740,10 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
***********************************/
@Override
@Async("asyncExecutor")
public void testDataScanByIdAsync(String id,LoginUser loginuser) throws Exception {
public void testDataScanByIdAsync(String id, LoginUser loginuser) throws Exception {
try {
// 执行扫描并且插入数据库
this.testDataScanById(id,loginuser);
this.testDataScanById(id, loginuser);
} finally {
// 生成唯一Key
String asyncKey = taskStatusHolder.testDatascanKey(id);
@ -663,48 +760,64 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
***********************************/
@Override
public Object confirmDeleteNodes(String id) {
JSONObject jsonObject = new JSONObject();
TsNodes tsNodes = tsNodesMapper.selectById(id);
if (tsNodes == null) {
jsonObject.putOpt("status", "1");
try {
JSONObject jsonObject = new JSONObject();
TsNodes tsNodes = tsNodesMapper.selectById(id);
TsTask tsTask = tsTaskMapper.selectById(tsNodes.getTaskId());
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
if (tsNodes == null) {
jsonObject.putOpt("status", "1");
return ResponseResult.successData(jsonObject);
}
//SQL通过节点ID 递归查询节点下面的所有子节点 以及files表中 backup_path IS NOT NULL
int count = tsFilesService.countFiles(id);
//如果大于0不让删
if (count > 0) {
jsonObject.putOpt("status", "0");
} else {
jsonObject.putOpt("status", "1");
}
return ResponseResult.successData(jsonObject);
} catch (Exception e) {
LOGGER.error("检查节点是否允许删除时发生异常: {}", e.getMessage(), e);
return ResponseResult.error("系统错误,请稍后重试");
} finally {
TableNameContextHolder.clear();
}
//SQL通过节点ID 递归查询节点下面的所有子节点 以及files表中 backup_path IS NOT NULL
int count = tsFilesService.countFiles(id);
//如果大于0不让删
if (count > 0) {
jsonObject.putOpt("status", "0");
} else {
jsonObject.putOpt("status", "1");
}
return ResponseResult.successData(jsonObject);
}
private String testDataScanById(String id,LoginUser loginuser) throws Exception {
private String testDataScanById(String id, LoginUser loginuser) throws Exception {
try {
//查询试验任务信息
TsTask tsTask = tsTaskMapper.selectById(id);
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
//文件的第一层是节点 下面的层级是文件夹
//获取文件列表
String absolutePath = "/" + tsTask.getTaskName() + "/";
FileListRequest fileListRequest = buildFileRequest(absolutePath, tsTask);
String storageKey = fileListRequest.getStorageKey();
Integer storageId = storageSourceService.findIdByKey(storageKey);
if (storageId == null) {
throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey);
}
// 处理请求参数默认值
fileListRequest.handleDefaultValue();
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId);
//todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件递归增加
List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath());
//查询试验任务信息
TsTask tsTask = tsTaskMapper.selectById(id);
//文件的第一层是节点 下面的层级是文件夹
//获取文件列表
String absolutePath = "/" + tsTask.getTaskName() + "/";
FileListRequest fileListRequest = buildFileRequest(absolutePath);
String storageKey = fileListRequest.getStorageKey();
Integer storageId = storageSourceService.findIdByKey(storageKey);
if (storageId == null) {
throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey);
if (fileItemList.size() == 0) {
throw new Exception("该试验任务管理项目目录不存在或没有项目文档,请先建立项目目录和文档。");
}
firstLayerData(fileItemList, id, loginuser);
return "扫描完成";
} catch (Exception e) {
LOGGER.error("执行试验数据扫描时发生未知异常: {}", e.getMessage(), e);
return "扫描失败:" + e.getMessage();
} finally {
TableNameContextHolder.clear();
}
// 处理请求参数默认值
fileListRequest.handleDefaultValue();
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId);
//todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件递归增加
List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath());
if (fileItemList.size() == 0) {
throw new Exception("该试验任务管理项目目录不存在或没有项目文档,请先建立项目目录和文档。");
}
firstLayerData(fileItemList, id, loginuser);
return "扫描完成";
}
/**
@ -714,8 +827,11 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
* @param taskId 所属任务ID
* @throws Exception
*/
public void firstLayerData(List<FileItemResult> fileItemList, String taskId,LoginUser loginuser) throws Exception {
public void firstLayerData(List<FileItemResult> fileItemList, String taskId, LoginUser loginuser) throws Exception {
// 设置当前时间
LocalDateTime now = LocalDateTime.now();
// 转换为 Timestamp
Timestamp currentTime = Timestamp.valueOf(now);
for (FileItemResult item : fileItemList) {
//思路就是 如果是文件夹 就查询一下 没有就新增 新的的时候递归往下走
if (item.getType() == FileTypeEnum.FOLDER) {
@ -730,9 +846,83 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
TsNodes node = savetsNodes(taskId, TOP_LEVEL_PARENT_NODE, item.getName());
otherLevelsData(taskId, node.getNodeId(), item.getName(), item.getPath(), TOP_LEVEL_PARENT_NODE, loginuser);
} else {
otherLevelsData(taskId, nodeData.getNodeId(), item.getName(), item.getPath(), TOP_LEVEL_PARENT_NODE, loginuser);
//otherLevelsData(taskId, nodeData.getNodeId(), item.getName(), item.getPath(), TOP_LEVEL_PARENT_NODE, loginuser);
continue;
}
} else {
//todo 如果是文件 首先判断表中有没有 如果没有 就新增 到节点名称为根节点的 节点下面
//查询节点表中 有没有根节点的节点 如果有就直接使用 如果没有就新增
LambdaQueryWrapper<TsNodes> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TsNodes::getTaskId, taskId);
queryWrapper.eq(TsNodes::getParentId, TOP_LEVEL_PARENT_NODE);
queryWrapper.eq(TsNodes::getNodeName, "根节点");
TsNodes nodeData = tsNodesMapper.selectOne(queryWrapper);
if (nodeData == null) {
//新增一个根节点
TsNodes node = savetsNodes(taskId, TOP_LEVEL_PARENT_NODE, "根节点");
String finalPath = item.getPath().replace(item.getName(), "");
//保存文件信息
TsFiles tsFiles1 = new TsFiles();
//任务
tsFiles1.setTaskId(taskId);
//节点
tsFiles1.setNodeId(node.getNodeId());
//文件 文件夹 区分
tsFiles1.setIsFile("FILE");
//上级ID
tsFiles1.setParentId("00");
//文件名称
tsFiles1.setFileName(item.getName());
//工作空间路径
tsFiles1.setWorkPath(ensurePathFormat(finalPath));
tsFiles1.setUploadTime(currentTime);
tsFiles1.setUploader(loginuser.getUsername());
long bytes = item.getSize();
// 转换为 KB 并保留两位小数
double fileSizeInKB = bytes / (1024.0);
String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数
tsFiles1.setFileSize(fileSizeFormatted);
tsFilesMapper.insert(tsFiles1);
} else {
//先通过名称 + 节点 + 任务 + 路径 查询 如果有就跳过 没有就继续新增
LambdaQueryWrapper<TsFiles> queryWrapperFiles = new LambdaQueryWrapper<>();
queryWrapperFiles.eq(TsFiles::getNodeId, nodeData.getNodeId());
queryWrapperFiles.eq(TsFiles::getTaskId, taskId);
queryWrapperFiles.eq(TsFiles::getWorkPath, item.getPath());
queryWrapperFiles.eq(TsFiles::getFileName, item.getName());
TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFiles);
if (tsFiles == null) {
String finalPath = item.getPath().replace(item.getName(), "");
//保存文件信息
TsFiles tsFiles1 = new TsFiles();
//任务
tsFiles1.setTaskId(taskId);
//节点
tsFiles1.setNodeId(nodeData.getNodeId());
//文件 文件夹 区分
tsFiles1.setIsFile("FILE");
//上级ID
tsFiles1.setParentId("00");
//文件名称
tsFiles1.setFileName(item.getName());
//工作空间路径
tsFiles1.setWorkPath(ensurePathFormat(finalPath));
tsFiles1.setUploadTime(currentTime);
tsFiles1.setUploader(loginuser.getUsername());
long bytes = item.getSize();
// 转换为 KB 并保留两位小数
double fileSizeInKB = bytes / (1024.0);
String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数
tsFiles1.setFileSize(fileSizeFormatted);
tsFilesMapper.insert(tsFiles1);
} else {
continue;
}
}
}
}
}
@ -745,7 +935,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
* @param parentId 父级ID
* @return
*/
private void otherLevelsData(String taskId, String nodeId, String nodeName, String path, String parentId,LoginUser loginuser) throws Exception {
private void otherLevelsData(String taskId, String nodeId, String nodeName, String path, String parentId, LoginUser loginuser) throws Exception {
// 存储所有目录和文件的列表
List<TsFiles> tsFilesToCreate = new ArrayList<>();
@ -757,6 +947,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
// 查询本地文件路径根目录 E:\yun
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "filePath");
queryWrapper.eq("storage_id", "1");
queryWrapper.eq("type", "local");
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
//获取文件列表 这个地方path+name
@ -984,15 +1175,21 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
return node;
}
private FileListRequest buildFileRequest(String path) {
private FileListRequest buildFileRequest(String path, TsTask tsTask) {
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
FileListRequest fileListRequest = new FileListRequest();
fileListRequest.setOrderBy("time");
fileListRequest.setOrderDirection("desc");
fileListRequest.setPassword("");
fileListRequest.setPath(path);
fileListRequest.setStorageKey("local");
fileListRequest.setStorageKey(storageSource.getKey());
return fileListRequest;
}
// 辅助方法获取存储配置
private StorageSource getStorageConfig(Integer id) {
return storageSourceMapper.selectOne(new LambdaQueryWrapper<StorageSource>().eq(StorageSource::getId, id)
);
}
}

View File

@ -18,13 +18,16 @@ import com.yfd.platform.modules.experimentalData.service.ITsFilesService;
import com.yfd.platform.modules.experimentalData.service.ITsNodesService;
import com.yfd.platform.modules.experimentalData.service.ITsTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.specialDocument.domain.Project;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.mapper.StorageSourceMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.BatchDeleteRequest;
import com.yfd.platform.modules.storage.model.request.NewFolderRequest;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.utils.StringUtils;
import com.yfd.platform.utils.TableNameContextHolder;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -32,12 +35,17 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.sql.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.time.LocalDateTime;
/**
* <p>
* 试验任务表 服务实现类
@ -72,6 +80,11 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
@Resource
private StorageSourceContext storageSourceContext;
@Resource
private StorageSourceMapper storageSourceMapper;
@Autowired
private DataSource dataSource;
private static final String INITIAL_CODE = "00001";
private static final int MAX_CODE_VALUE = 99999;
@ -169,15 +182,15 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
//生成任务名称 任务开始时间_结束时间_地点_载机名称_设备代号_编号
String taskName = buildTaskName(tsTask);
tsTask.setTaskName(taskName);
LambdaQueryWrapper<TsTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TsTask::getTaskName,tsTask.getTaskName());
queryWrapper.eq(TsTask::getTaskName, tsTask.getTaskName());
TsTask tsTask1 = tsTaskMapper.selectOne(queryWrapper);
if (tsTask1 != null){
if (tsTask1 != null) {
throw new RuntimeException("试验任务管理项目已存在!");
}
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
// 设置当前时间
LocalDateTime now = LocalDateTime.now();
// 转换为 Timestamp
@ -193,10 +206,12 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
newFolderRequest.setName(tsTask.getTaskName());//新建的文件夹名称,示例值(/a/b/c)
newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
newFolderRequest.setPath(path);//请求路径,示例值(/)
newFolderRequest.setStorageKey("local");//存储源 key,示例值(local minio)
newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
if (flag) {
// 动态创建数据表
createTaskFileTable(taskCode);
return true;
} else {
LOGGER.error("试验任务增加成功,但是本地试验任务文件夹创建失败");
@ -208,12 +223,74 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
}
// 动态创建任务文件表
private void createTaskFileTable(String taskCode) {
// 添加表名校验重要防止SQL注入
if (!taskCode.matches("^\\d{5}$")) { // 假设任务编号是5位数字
throw new IllegalArgumentException("非法任务编号格式: " + taskCode);
}
String tableName = "ts_files_" + taskCode;
String sql = String.format(
"CREATE TABLE IF NOT EXISTS `%s` LIKE `ts_files`",
tableName
);
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
// 1. 记录要执行的SQL
LOGGER.info("执行DDL: {}", sql);
// 2. 执行SQL
boolean result = stmt.execute(sql);
// 3. 验证结果
LOGGER.debug("执行结果: {}", result);
// 4. 二次验证
if (!tableExists(tableName)) {
throw new RuntimeException("表创建后验证失败: " + tableName);
}
} catch (SQLException e) {
// 提取MySQL错误信息
String errorMsg = extractMysqlError(e);
LOGGER.error("创建表失败: {} - {}", tableName, errorMsg);
throw new RuntimeException("创建表失败: " + errorMsg, e);
}
}
private boolean tableExists(String tableName) {
try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData meta = conn.getMetaData();
// 获取当前数据库信息
String catalog = conn.getCatalog();
String schema = conn.getSchema();
// 查询表是否存在
try (ResultSet rs = meta.getTables(catalog, schema, tableName, new String[]{"TABLE"})) {
return rs.next();
}
} catch (SQLException e) {
LOGGER.error("检查表存在失败: {}", tableName, e);
return false;
}
}
private String extractMysqlError(SQLException e) {
// 提取MySQL特有的错误信息
while (e != null) {
if (e.getMessage().contains("MySQL")) {
return String.format("MySQL 错误 [%d]: %s", e.getErrorCode(), e.getMessage());
}
e = e.getNextException();
}
return "未知数据库错误";
}
public static String buildTaskName(TsTask tsTask) {
List<String> parts = new ArrayList<>();
// 定义日期格式化模板
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
// 按顺序添加非空字段
addIfNotEmpty(parts, String.valueOf(tsTask.getTaskStartdate()));
addIfNotEmpty(parts, String.valueOf(tsTask.getTaskEnddate()));
addIfNotEmpty(parts, formatDate(tsTask.getTaskStartdate(), formatter));
addIfNotEmpty(parts, formatDate(tsTask.getTaskEnddate(), formatter));
addIfNotEmpty(parts, tsTask.getTaskPlace());
addIfNotEmpty(parts, tsTask.getCarrierName());
addIfNotEmpty(parts, tsTask.getDeviceCode());
@ -222,6 +299,15 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
return String.join("_", parts);
}
// 格式化日期的方法
private static String formatDate(Object date, DateTimeFormatter formatter) {
if (date != null) {
return ((java.time.LocalDate) date).format(formatter);
}
return null;
}
private static void addIfNotEmpty(List<String> list, String value) {
if (StringUtils.isNotBlank(value)) { // 使用Apache Commons Lang的空判断
list.add(value.trim()); // 去除首尾空格
@ -262,21 +348,27 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
public boolean deleteTstaskByIds(List<String> dataset) {
Boolean value = false;
//循环所有的ID
for (String taskId : dataset) {
//删除项目
try {
// 删除节点表
LambdaQueryWrapper<TsNodes> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.eq(TsNodes::getTaskId, taskId);
tsNodesMapper.delete(deleteWrapper);
// 删除文件表
LambdaQueryWrapper<TsFiles> deleteWrapperFiles = new LambdaQueryWrapper<>();
deleteWrapperFiles.eq(TsFiles::getTaskId, taskId);
tsFilesMapper.delete(deleteWrapperFiles);
//循环所有的ID
for (String taskId : dataset) {
//删除项目
TsTask tsTask = tsTaskMapper.selectById(taskId);
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
// 删除节点表
LambdaQueryWrapper<TsNodes> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.eq(TsNodes::getTaskId, taskId);
tsNodesMapper.delete(deleteWrapper);
// 删除文件表
LambdaQueryWrapper<TsFiles> deleteWrapperFiles = new LambdaQueryWrapper<>();
deleteWrapperFiles.eq(TsFiles::getTaskId, taskId);
tsFilesMapper.delete(deleteWrapperFiles);
//todo 删除文件表数据
// tsFilesMapper.deleteSdFilesBytaskId(taskId);
TsTask tsTask = tsTaskMapper.selectById(taskId);
// String path = "/" + tsTask.getTaskName() + "/";
// //调用删除节点 根据任务ID
// Boolean deleteTsnodes = tsNodesService.deleteTsNodesByTaskId(taskId, path);
@ -289,59 +381,65 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
// value = false;
// }
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
// 删除 local 中的文件夹 项目文件夹
List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem();
deleteItemData.setName(tsTask.getTaskName());
deleteItemData.setPassword("");
deleteItemData.setPath("/");
deleteItemData.setType(FileTypeEnum.FOLDER);
deleteItemList.add(deleteItemData);
// 删除 local 中的文件夹 项目文件夹
List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem();
deleteItemData.setName(tsTask.getTaskName());
deleteItemData.setPassword("");
deleteItemData.setPath("/");
deleteItemData.setType(FileTypeEnum.FOLDER);
deleteItemList.add(deleteItemData);
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey("local");
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);
for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) {
boolean flag = false;
try {
if (deleteItem.getType() == FileTypeEnum.FILE) {
flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName());
} else if (deleteItem.getType() == FileTypeEnum.FOLDER) {
flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName());
}
for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) {
boolean flag = false;
try {
if (deleteItem.getType() == FileTypeEnum.FILE) {
flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName());
} else if (deleteItem.getType() == FileTypeEnum.FOLDER) {
flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName());
}
if (flag) {
deleteSuccessCount++;
} else {
if (flag) {
deleteSuccessCount++;
} else {
deleteFailCount++;
}
} catch (Exception e) {
LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e);
deleteFailCount++;
}
} catch (Exception e) {
LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e);
deleteFailCount++;
}
}
if (deleteSuccessCount >= 1) {
// 删除当前项目
int deleteCount = tsTaskMapper.deleteById(taskId);
if (deleteCount == 1) {
LOGGER.info("tstask表结删除改成功");
value = true;
if (deleteSuccessCount >= 1) {
// 删除当前项目
int deleteCount = tsTaskMapper.deleteById(taskId);
if (deleteCount == 1) {
LOGGER.info("tstask表结删除改成功");
value = true;
} else {
LOGGER.error("tstask表结构删除失败");
value = false;
}
} else {
LOGGER.error("tstask表结构删除失败");
value = false;
}
} else {
value = false;
}
return value;
} catch (Exception e) {
} finally {
TableNameContextHolder.clear();
}
return value;
}
@ -352,20 +450,53 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
***********************************/
@Override
public Object confirmDeleteTask(List<String> dataset) {
JSONObject jsonObject = new JSONObject();
// 删除 getBackupPath getWorkPath 都为空的记录
LambdaQueryWrapper<TsFiles> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(TsFiles::getTaskId, dataset)
.and(wrapper -> wrapper.isNotNull(TsFiles::getBackupPath)
.or().ne(TsFiles::getBackupPath, ""));
int count = tsFilesService.count(queryWrapper);
//如果大于0不让删
if (count > 0) {
jsonObject.putOpt("status", "0");
} else {
jsonObject.putOpt("status", "1");
try {
LambdaQueryWrapper<TsTask> queryWrapperTsk = new LambdaQueryWrapper<>();
queryWrapperTsk.in(TsTask::getId, dataset);
List<TsTask> tsTasks = tsTaskMapper.selectList(queryWrapperTsk);
JSONObject result = new JSONObject();
boolean allDeletable = true;
for (TsTask tsTask : tsTasks) {
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
// 查询是否有备份路径或非空路径的文件
LambdaQueryWrapper<TsFiles> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TsFiles::getTaskId, tsTask.getId())
.and(wrapper -> wrapper.isNotNull(TsFiles::getBackupPath)
.or().ne(TsFiles::getBackupPath, ""));
int count = tsFilesService.count(queryWrapper);
if (count > 0) {
allDeletable = false;
break; // 一旦发现不可删除项提前终止循环
}
}
result.putOpt("status", allDeletable ? "1" : "0");
return ResponseResult.successData(result);
} catch (Exception e) {
// 使用日志框架代替 printStackTrace
LOGGER.error("确认删除实验任务时发生异常", e);
return ResponseResult.error("查询失败");
} finally {
TableNameContextHolder.clear();
}
return ResponseResult.successData(jsonObject);
}
@Override
public List<TsTask> listTsTask() {
LambdaQueryWrapper<TsTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(TsTask::getTaskStartdate);
List<TsTask> tsTasks = tsTaskMapper.selectList(queryWrapper);
for (TsTask tsTask : tsTasks){
StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId());
tsTask.setKey(storageSource.getKey());
}
return tsTasks;
}
@Transactional(rollbackFor = Exception.class)
@ -398,4 +529,10 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
}
}
// 辅助方法获取存储配置
private StorageSource getStorageConfig( Integer id) {
return storageSourceMapper.selectOne(new LambdaQueryWrapper<StorageSource>().eq(StorageSource::getId, id)
);
}
}

View File

@ -161,9 +161,7 @@ public class ProjectController {
@ResponseBody
//@PreAuthorize("@el.check('select:devicesignal')")
public ResponseResult listSdproject() {
LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Project::getProjectTime);
List<Project> projects = projectService.list(queryWrapper);
List<Project> projects = projectService.listProject();
return ResponseResult.successData(projects);
}

View File

@ -6,6 +6,7 @@ import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@ -91,4 +92,22 @@ public class Project implements Serializable {
private String custom3;
/**
* 本地存储空间id
*/
private Integer localStorageId;
/**
* 上传用到KEYTODO 增加用于前端展示
*/
@TableField(exist = false)
private String key;
/**
* 上传用到typeTODO 增加用于前端展示
*/
@TableField(exist = false)
private String type;
}

View File

@ -1,9 +1,11 @@
package com.yfd.platform.modules.specialDocument.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.modules.specialDocument.domain.Files;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
@ -22,4 +24,33 @@ public interface FilesMapper extends BaseMapper<Files> {
//根据节点删除文件递归子节点文件
int deleteByNodeId(@Param("nodeId")String nodeId);
void updateFileByPath(@Param("projectId") String projectId,@Param("oldBasePath") String oldBasePath,@Param("newBasePath") String newBasePath);
//分页查询文件表
Page<Files> selectFilesPage(@Param("page") Page<Files> page,
@Param("fileName") String fileName,
@Param("keywords") String keywords,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate,
@Param("projectId") String projectId,
@Param("nodeId") String nodeId,
@Param("fileName1") String fileName1,
@Param("tableName") String tableName
);
//插入文件表
int insertSdFilesTable(@Param("tableName") String tableName, @Param("files") Files filess);
//更新文件表
int updateSdFiles(@Param("tableName") String tableName, @Param("files") Files files);
//批量查询文件表
List<Files> selectSdFilesBatchIds(@Param("dataset") List<String> dataset,@Param("tableName") String tableName);
//删除文件表
int deleteSdFiles(@Param("tableName") String tableName, @Param("files") Files files);
//查询文件表根据ID
Files selectSdFilesById(@Param("tableName") String tableName, @Param("id") String id);
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.modules.specialDocument.mapper;
import com.yfd.platform.modules.specialDocument.domain.Nodes;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -20,4 +21,6 @@ public interface NodesMapper extends BaseMapper<Nodes> {
int updateParentIdByPathHierarchy();
int deleteNodesRecursively(String nodeId);
void updateNodesByPath(@Param("projectId") String projectId,@Param("oldBasePath") String oldBasePath,@Param("newBasePath") String newBasePath);
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.modules.specialDocument.mapper;
import com.yfd.platform.modules.specialDocument.domain.Project;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
@ -13,4 +14,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface ProjectMapper extends BaseMapper<Project> {
// 新增动态建表方法
static int createFileTable(@Param("tableName") String tableName) {
return 0;
}
}

View File

@ -46,4 +46,6 @@ public interface IProjectService extends IService<Project> {
boolean deleteProjectByIds(List<String> dataset);
String generateNextProjectCode();
List<Project> listProject();
}

View File

@ -11,16 +11,18 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.exception.file.InvalidStorageSourceException;
import com.yfd.platform.modules.config.model.request.FileListRequest;
import com.yfd.platform.modules.experimentalData.domain.TsFiles;
import com.yfd.platform.modules.specialDocument.domain.Files;
import com.yfd.platform.modules.specialDocument.domain.Project;
import com.yfd.platform.modules.specialDocument.mapper.FilesMapper;
import com.yfd.platform.modules.specialDocument.mapper.ProjectMapper;
import com.yfd.platform.modules.specialDocument.service.IFilesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.storage.chain.FileChain;
import com.yfd.platform.modules.storage.chain.FileContext;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.controller.file.FileController;
import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper;
import com.yfd.platform.modules.storage.mapper.StorageSourceMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.BatchDeleteRequest;
@ -81,7 +83,9 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
private FilesMapper filesMapper;
@Autowired
private FileController fileController;
private ProjectMapper projectMapper;
@Resource
private StorageSourceMapper storageSourceMapper;
@Resource
private StorageSourceContext storageSourceContext;
@ -223,9 +227,11 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
public FileItemResult sdLocalUrl(String id) {
FileItemResult fileItemResult = new FileItemResult();
Files files = filesMapper.selectById(id);
Project project = projectMapper.selectById(files.getProjectId());
StorageSource storageSource = storageSourceMapper.selectById(project.getLocalStorageId());
String pathAndName = files.getFilePath() + files.getFileName();
//准备获取文件的信息
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey("sdlocal");
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(storageSource.getKey());
fileItemResult = fileService.getFileItem(pathAndName);
return fileItemResult;
}
@ -299,13 +305,13 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
if (authentication != null) {
loginuser = (LoginUser) authentication.getPrincipal();
}
Project project = projectMapper.selectById(files.getProjectId());
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
//新增之前从处理一下源路径的数据 ,String sourcePath,String targetPath
// 查询本地文件路径根目录 E:\yun
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "filePath");
queryWrapper.eq("type", "sdlocal");
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath","local",project.getLocalStorageId());
//源路径 临时路径
String sourceFilePath = files.getSourcePath();
//目标路径
@ -322,7 +328,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
//校验是否真正上传
String pathAndName = filess.getFilePath() + filess.getFileName();
//准备获取文件的信息
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey("sdlocal");
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(storageSource.getKey());
FileItemResult fileItemResult = fileService.getFileItem(pathAndName);
if (fileItemResult == null || fileItemResult.getName() == null) {
return ResponseResult.error(filess.getFileName() + "文件没有上传到空间,请重新选择上传!");
@ -380,8 +386,8 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
LocalDateTime now = LocalDateTime.now();
// 转换为 Timestamp
Timestamp currentTime = Timestamp.valueOf(now);
FileListRequest sourcefileListRequest = buildFileRequest(sourceFilePath);
FileListRequest targetfileListRequest = buildFileRequest(targetFilePath);
FileListRequest sourcefileListRequest = buildFileRequest(sourceFilePath,files.getProjectId());
FileListRequest targetfileListRequest = buildFileRequest(targetFilePath,files.getProjectId());
//获取源文件列表 包含文件和文件夹
List<FileItemResult> sourceFileItemList = obtainFileItemResultData(sourcefileListRequest);
@ -583,13 +589,16 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
return fileItemList;
}
private FileListRequest buildFileRequest(String path) {
private FileListRequest buildFileRequest(String path,String projectId) {
Project project = projectMapper.selectById(projectId);
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
FileListRequest fileListRequest = new FileListRequest();
fileListRequest.setOrderBy("time");
fileListRequest.setOrderDirection("desc");
fileListRequest.setPassword("");
fileListRequest.setPath(path);
fileListRequest.setStorageKey("sdlocal");
fileListRequest.setStorageKey(storageSource.getKey());
return fileListRequest;
}
@ -673,6 +682,8 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
redisTemplate.delete(redisKey);
}
int SuccessCount = 0, FailCount = 0, total = CollUtil.size(dataset);
Project project = projectMapper.selectById(filesList.get(0).getProjectId());
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
//Todo 最直接的办法 循环出来 一条一条删除
for (Files files : filesList) {
@ -689,7 +700,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey("sdlocal");
batchDeleteRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
List<BatchDeleteRequest.DeleteItem> deleteItems = batchDeleteRequest.getDeleteItems();
@ -745,12 +756,15 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
// 修改 sdlocal 文件名的方法
private boolean updateMinioFileName(Files filesData, Files files) {
try {
Project project = projectMapper.selectById(files.getProjectId());
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
RenameFileRequest renameFileRequest = new RenameFileRequest();
renameFileRequest.setName(filesData.getFileName());
renameFileRequest.setNewName(files.getFileName());
renameFileRequest.setPassword("");
renameFileRequest.setPath(filesData.getFilePath());
renameFileRequest.setStorageKey("sdlocal");
renameFileRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey());
return fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName());
@ -759,4 +773,17 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
return false;
}
}
// 辅助方法获取存储配置
private StorageSource getStorageConfig(Integer id) {
return storageSourceMapper.selectOne(new LambdaQueryWrapper<StorageSource>().eq(StorageSource::getId, id)
);
}
// 辅助方法获取存储配置
private StorageSourceConfig getStorageSourceConfig(String name, String type,Integer id) {
return storageSourceConfigMapper.selectOne(
new LambdaQueryWrapper<StorageSourceConfig>().eq(StorageSourceConfig::getName, name).eq(StorageSourceConfig::getType, type).eq(StorageSourceConfig::getStorageId,id)
);
}
}

View File

@ -3,8 +3,6 @@ package com.yfd.platform.modules.specialDocument.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.io.FileUtil;
import com.amazonaws.util.IOUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yfd.platform.component.TaskStatusHolder;
@ -23,6 +21,8 @@ import com.yfd.platform.modules.specialDocument.service.INodesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper;
import com.yfd.platform.modules.storage.mapper.StorageSourceMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.BatchDeleteRequest;
@ -41,6 +41,7 @@ import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
@ -100,10 +101,17 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
@Autowired
private TaskStatusHolder taskStatusHolder;
@Resource
private StorageSourceMapper storageSourceMapper;
//专项项目表Mapper
@Resource
private ProjectMapper projectMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
//顶级父节点 Top level parent node
public static final String TOP_LEVEL_PARENT_NODE = "00";
@ -301,6 +309,9 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
@Transactional(rollbackFor = Exception.class) // 添加事务注解遇到异常时回滚
public ResponseResult addNodes(Nodes nodes) {
Project project = projectMapper.selectById(nodes.getProjectId());
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
// 校验文件名是否包含非法字符
String nodeName = nodes.getNodeName();
if (containsInvalidCharacters(nodeName)) {
@ -362,7 +373,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
newFolderRequest.setName(nodes.getNodeName());//新建的文件夹名称,示例值(/a/b/c)
newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
newFolderRequest.setPath(nodes.getPath());//请求路径,示例值(/)
newFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio sdlocal)
newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
if (flag) {
@ -392,6 +403,9 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
if (containsInvalidCharacters(nodeName)) {
return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*");
}
Project project = projectMapper.selectById(nodes.getProjectId());
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
//查询没改之前的节点名称
Nodes nodesold = nodesMapper.selectById(nodes.getId());
@ -401,9 +415,6 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
nodeNameOld = nodesold.getNodeName();
}
//获取专项文档项目
Project project = projectMapper.selectById(nodes.getProjectId());
//获取当前登录用户
UsernamePasswordAuthenticationToken authentication =
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
@ -424,49 +435,84 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
if (count > 0) {
return ResponseResult.error("节点名称已存在!");
}
//更新当前数据
int valueUpdate = nodesMapper.updateById(nodes);
// 4. 递归获取所有子节点ID包含当前节点
List<String> affectedNodeIds = getAllChildNodeIds(nodes.getId());
// 2. 构建新旧路径
String oldBasePath = nodes.getPath() + nodeNameOld + "/";
String newBasePath = nodes.getPath() + nodeName + "/";
// 5. 更新相关文件路径
updateFilePaths(affectedNodeIds, nodes.getProjectId(), nodeNameOld, nodeName);
//3.跟新节点表sd_nodes表 根据所属项目ID 老路径 和新路径
nodesMapper.updateNodesByPath(nodes.getProjectId(), oldBasePath, newBasePath);
if (valueUpdate == 1) {
List<String> pathNodes = new ArrayList<>();
Nodes nodesData = nodesMapper.selectById(nodes.getParentId());
// 从当前节点向上遍历直到根节点
while (nodesData != null) {
pathNodes.add(nodesData.getNodeName());
// 如果父节点是 "00"说明已经到了根节点停止遍历
if ("00".equals(nodesData.getParentId())) {
break;
//4.更新文件表sd_files表 根据所属项目ID 老路径 和新路径
filesMapper.updateFileByPath(nodes.getProjectId(), oldBasePath, newBasePath);
//获取项目下面的所有子节点 都清除缓存
List<Nodes> nodesList = nodesMapper.selectList(new QueryWrapper<Nodes>().eq("project_id", nodes.getProjectId()));
if ((nodesList != null) && (nodesList.size() > 0)) {
for (Nodes node : nodesList) {
//todo 修改节点成功以后 删除redis
for (int page = 1; page <= 5; page++) {
String redisKey = "sdfiles_" + node.getProjectId() + "_" + node.getId() + "_page_" + page;
redisTemplate.delete(redisKey);
}
// 获取父节点
nodesData = nodesMapper.selectById(nodesData.getParentId()); // 修正 nodesData 中获取 parentId
LOGGER.info("已清理缓存project={}, node={}, pages=1-5", nodes.getProjectId(), nodes.getId());
}
// 反转路径使其从根节点到当前节点
Collections.reverse(pathNodes);
String path = String.join("/", pathNodes);
}
//修改文件名称
RenameFolderRequest renameFolderRequest = new RenameFolderRequest();
renameFolderRequest.setName(nodeNameOld);//重命名的原文件夹名称,示例值(movie)
renameFolderRequest.setNewName(nodeName);// 重命名后的文件名称,示例值(music)
renameFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
renameFolderRequest.setPath(nodes.getPath());//请求路径,示例值(/)
renameFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio sdlocal)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey());
boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName());
if (flag) {
//判断如果更新了节点名称
if (!nodeName.equals(nodeNameOld)) {
// // 4. 递归获取所有子节点ID包含当前节点
// List<String> affectedNodeIds = getAllChildNodeIds(nodes.getId());
//
// // 5. 更新相关文件路径
// updateFilePaths(affectedNodeIds, nodes.getProjectId(), nodeNameOld, nodeName);
if (valueUpdate == 1) {
// List<String> pathNodes = new ArrayList<>();
// Nodes nodesData = nodesMapper.selectById(nodes.getParentId());
// // 从当前节点向上遍历直到根节点
// while (nodesData != null) {
// pathNodes.add(nodesData.getNodeName());
// // 如果父节点是 "00"说明已经到了根节点停止遍历
// if ("00".equals(nodesData.getParentId())) {
// break;
// }
// // 获取父节点
// nodesData = nodesMapper.selectById(nodesData.getParentId()); // 修正 nodesData 中获取 parentId
// }
// // 反转路径使其从根节点到当前节点
// Collections.reverse(pathNodes);
// String path = String.join("/", pathNodes);
//修改文件名称
RenameFolderRequest renameFolderRequest = new RenameFolderRequest();
renameFolderRequest.setName(nodeNameOld);//重命名的原文件夹名称,示例值(movie)
renameFolderRequest.setNewName(nodeName);// 重命名后的文件名称,示例值(music)
renameFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
renameFolderRequest.setPath(nodes.getPath());//请求路径,示例值(/)
renameFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey());
boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName());
if (flag) {
return ResponseResult.success("重命名成功");
} else {
LOGGER.error("节点修改成功但是sdlocal修改文件名失败");
return ResponseResult.error("重命名失败");
}
} else {
LOGGER.error("节点修改失败");
return ResponseResult.error();
}
} else {
if (valueUpdate == 1) {
return ResponseResult.success("重命名成功");
} else {
LOGGER.error("节点修改成功但是sdlocal修改文件名失败");
return ResponseResult.error("重命名失败");
}
} else {
LOGGER.error("节点修改失败");
return ResponseResult.error();
}
}
@ -545,6 +591,8 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
if (nodes == null) {
return false; // 节点不存在
}
Project project = projectMapper.selectById(nodes.getProjectId());
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
// //递归获取当前节点和它下面的所有节点
// List<Nodes> nodesList = selectChildrenNodes(id, nodes.getProjectId());
// // 提取所有节点的 ID
@ -581,7 +629,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey("sdlocal");
batchDeleteRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);
@ -699,12 +747,13 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
//查询项目信息
Project project = projectMapper.selectById(id);
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
// 查询本地文件路径根目录 E:\yun
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "filePath");
queryWrapper.eq("type", "sdlocal");
queryWrapper.eq("storage_id", project.getLocalStorageId());
queryWrapper.eq("type", storageSource.getType());
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
//获取文件列表
@ -944,7 +993,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
String absolutePath = path + nodeName + "/";
//获取文件列表
FileListRequest fileListRequest = buildFileRequest(absolutePath);
FileListRequest fileListRequest = buildFileRequest(absolutePath,projectId);
String storageKey = fileListRequest.getStorageKey();
Integer storageId = storageSourceService.findIdByKey(storageKey);
if (storageId == null) {
@ -1012,13 +1061,15 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
return map.get(adjustedIndex);
}
private FileListRequest buildFileRequest(String path) {
private FileListRequest buildFileRequest(String path,String projectId) {
Project project = projectMapper.selectById(projectId);
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
FileListRequest fileListRequest = new FileListRequest();
fileListRequest.setOrderBy("time");
fileListRequest.setOrderDirection("desc");
fileListRequest.setPassword("");
fileListRequest.setPath(path);
fileListRequest.setStorageKey("sdlocal");
fileListRequest.setStorageKey(storageSource.getKey());
return fileListRequest;
}
@ -1123,14 +1174,14 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
try {
// 1. 优化合并重复的异常捕获
//------------------------------------------
// 查询存储配置
StorageSourceConfig config = getStorageConfig();
if (config == null) throw new RuntimeException("未找到本地存储路径配置");
// 优化提前验证项目存在性避免后续无效操作
Project project = projectMapper.selectById(id);
if (project == null) throw new RuntimeException("项目不存在: " + id);
// 查询存储配置 wrapper.eq("name", "filePath").eq("type", "sdlocal");
StorageSourceConfig config = getStorageSourceConfig("filePath", "local", project.getLocalStorageId());
if (config == null) throw new RuntimeException("未找到本地存储路径配置");
// 优化解压路径统一构建逻辑
final String tempDir = "temporary";
final String zipName = getFileNameWithoutExtension(fileName);
@ -1172,12 +1223,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
}
}
// 新增辅助方法解耦核心逻辑 --------------------------------------------------
private StorageSourceConfig getStorageConfig() {
QueryWrapper<StorageSourceConfig> wrapper = new QueryWrapper<>();
wrapper.eq("name", "filePath").eq("type", "sdlocal");
return storageSourceConfigMapper.selectOne(wrapper);
}
private void transferProjectFiles(String projectId, String basePath, String sourceDir, String targetDir) throws Exception {
String sourcePath = "/temporary/" + sourceDir + "/";
@ -1201,78 +1247,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
}
}
// public void documentUploadByIdAsync(String id, String fileName, LoginUser loginuser) throws IOException {
// try {
//
// // 查询本地文件路径根目录 E:\yun
// QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("name", "filePath");
// queryWrapper.eq("type", "sdlocal");
// StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
//
// if (storageSourceConfig == null) {
// throw new RuntimeException("未找到本地存储路径配置");
// }
//
// //解压以后的文件夹名称
// String zipName = getFileNameWithoutExtension(fileName); // 示例222
//
// //查询项目信息
// Project project = projectMapper.selectById(id);
// if (project == null) {
// throw new RuntimeException("项目不存在");
// }
//
// if (!project.getProjectName().equals(zipName)) {
// throw new RuntimeException("压缩包名称需要和项目名称保持一致");
// }
//
// String decompressionPath = "/" + "temporary";
// //构建要解压的zip文件路径 例如 D:\yun\temporary\111.zip
// Path zipFilePath = Paths.get(storageSourceConfig.getValue(), decompressionPath, fileName);
// // 4. 构建解压目标路径 例如 D:\yun\temporary\111
// Path destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath);
//
// LOGGER.info("要解压文件路径:{}", zipFilePath);
// LOGGER.info("解压以后文件路径:{}", destRoot);
//
//
// //todo 如果项目不存在 直接拷贝到目标路径下 拷贝完成以后 然后新增一个项目结构 然后走一遍扫描
//
// //源文件夹路径
// String sourceFolderPath = "/" + "temporary" + "/" + zipName + "/";
// //目标文件夹路径
// String targetFolderPath = "/" + project.getProjectName() + "/";
//
// //首先执行解压缩
// unzipToTemp(zipFilePath, String.valueOf(destRoot));
// // 执行上传并且插入数据库
// this.documentUploadById(id, sourceFolderPath, targetFolderPath, storageSourceConfig.getValue());
// //开始执行更新表数据 名称是去掉后缀以后的
// uploadProject(zipName, loginuser);
// LOGGER.info("开始更新表数据:{}", zipName);
//
// //获取文件路径
// Path destRootPath = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName);
// File targetZip = new File(String.valueOf(zipFilePath));
// File target = new File(String.valueOf(destRootPath));
// //删除临时文件ZIP
// deleteDirectory(targetZip);
// //删除临时文件
// deleteDirectory(target);
// } catch (IOException e) {
// throw new RuntimeException(e);
// } catch (Exception e) {
// throw new RuntimeException(e);
// } finally {
// // 生成唯一Key
// String asyncKey = taskStatusHolder.documentUploadKey(id);
// // 无论成功失败都标记完成
// taskStatusHolder.finishTask(asyncKey);
// WebSocketServer.sendMessageTo("专项文档上传任务处理完成!", "projectId_" + id);
//
// }
// }
public static void deleteDirectory(File directory) throws Exception {
if (!directory.exists()) {
@ -1317,8 +1292,8 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
return null;
}
FileListRequest sourcefileListRequest = buildFileRequest(sourceFolderPath);
FileListRequest targetfileListRequest = buildFileRequest(targetFolderPath);
FileListRequest sourcefileListRequest = buildFileRequest(sourceFolderPath, id);
FileListRequest targetfileListRequest = buildFileRequest(targetFolderPath, id);
//获取源文件列表 包含文件和文件夹
List<FileItemResult> sourceFileItemList = obtainFileItemResultData(sourcefileListRequest);
@ -1415,8 +1390,10 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
LambdaQueryWrapper<Project> projectLambdaQueryWrapper = new LambdaQueryWrapper<>();
projectLambdaQueryWrapper.eq(Project::getProjectName, projectName);
Project project = projectMapper.selectOne(projectLambdaQueryWrapper);
//如果项目不存在
if (project == null) {
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
String projectCode = this.generateNextProjectCode();
project.setProjectCode("1");
@ -1435,7 +1412,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
newFolderRequest.setName(project.getProjectName());//新建的文件夹名称,示例值(/a/b/c)
newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
newFolderRequest.setPath(path);//请求路径,示例值(/)
newFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio)
newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
}
@ -1748,5 +1725,21 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
}
}
// 辅助方法获取存储配置
private StorageSource getStorageConfig( Integer id) {
return storageSourceMapper.selectOne(new LambdaQueryWrapper<StorageSource>().eq(StorageSource::getId, id)
);
}
// 辅助方法获取存储配置
private StorageSourceConfig getStorageSourceConfig(String name, String type,Integer id) {
return storageSourceConfigMapper.selectOne(
new LambdaQueryWrapper<StorageSourceConfig>().eq(StorageSourceConfig::getName, name).eq(StorageSourceConfig::getType, type).eq(StorageSourceConfig::getStorageId,id)
);
}
}

View File

@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.modules.specialDocument.domain.Files;
import com.yfd.platform.modules.specialDocument.domain.Nodes;
import com.yfd.platform.modules.specialDocument.domain.Project;
import com.yfd.platform.modules.specialDocument.mapper.ProjectMapper;
@ -12,23 +11,26 @@ import com.yfd.platform.modules.specialDocument.service.INodesService;
import com.yfd.platform.modules.specialDocument.service.IProjectService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.mapper.StorageSourceMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.BatchDeleteRequest;
import com.yfd.platform.modules.storage.model.request.NewFolderRequest;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.system.mapper.SysDictionaryItemsMapper;
import com.yfd.platform.utils.StringUtils;
import io.netty.channel.ChannelInboundHandlerAdapter;
import net.bytebuddy.implementation.bytecode.Throw;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.sql.Timestamp;
import javax.sql.DataSource;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -57,13 +59,16 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
@Resource
private INodesService nodesService;
//字典表Mapper
@Resource
private SysDictionaryItemsMapper sysDictionaryItemsMapper;
@Resource
private StorageSourceContext storageSourceContext;
@Resource
private StorageSourceMapper storageSourceMapper;
@Autowired
private DataSource dataSource;
/**********************************
* 用途说明: 分页查询专项文档管理-项目管理
* 参数说明
@ -125,6 +130,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
// 转换为 Timestamp
Timestamp currentTime = Timestamp.valueOf(now);
project.setCreateTime(currentTime);
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Project::getProjectName,project.getProjectName());
@ -144,10 +150,13 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
newFolderRequest.setName(project.getProjectName());//新建的文件夹名称,示例值(/a/b/c)
newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问则支持请求密码,示例值(123456)
newFolderRequest.setPath(path);//请求路径,示例值(/)
newFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio)
newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio)
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
if (flag) {
// 动态创建数据表
//createTaskFileTable(projectCode);
return true;
} else {
LOGGER.error("节点新增成功,但是本地专项文件夹创建失败");
@ -158,31 +167,67 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
return false;
}
}
// //查询字典表获取项目类型对应数据字典
// QueryWrapper<SysDictionaryItems> queryWrapperSysDictionary = new QueryWrapper<>();
// queryWrapperSysDictionary.eq("parentcode", "compressType");
// queryWrapperSysDictionary.orderByAsc("orderno");
// SysDictionaryItems sysDictionaryItems = sysDictionaryItemsMapper.selectOne(queryWrapperSysDictionary);
// if(sysDictionaryItems != null){
// project.setProjectType(sysDictionaryItems.getDictName());
// }
// 动态创建任务文件表
private void createTaskFileTable(String taskCode) {
// 添加表名校验重要防止SQL注入
if (!taskCode.matches("^\\d{5}$")) { // 假设任务编号是5位数字
throw new IllegalArgumentException("非法任务编号格式: " + taskCode);
}
//TODO 01.21沟通以后说是先不用管重复校验问题
// //通过项目名称 项目编号查询 查看是否存在
// QueryWrapper<Project> queryWrapper = new QueryWrapper<>();
// if(project.getProjectCode() != null){
// queryWrapper.eq("project_code",project.getProjectCode());
// }
// if(project.getProjectName() != null){
// queryWrapper.eq("project_name",project.getProjectName());
// }
// List<Project> projects = projectMapper.selectList(queryWrapper);
// if(){
//
// }
String tableName = "sd_files_" + taskCode;
String sql = String.format(
"CREATE TABLE IF NOT EXISTS `%s` LIKE `sd_files`",
tableName
);
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
// 1. 记录要执行的SQL
LOGGER.info("执行DDL: {}", sql);
// 2. 执行SQL
boolean result = stmt.execute(sql);
// 3. 验证结果
LOGGER.debug("执行结果: {}", result);
// 4. 二次验证
if (!tableExists(tableName)) {
throw new RuntimeException("表创建后验证失败: " + tableName);
}
} catch (SQLException e) {
// 提取MySQL错误信息
String errorMsg = extractMysqlError(e);
LOGGER.error("创建表失败: {} - {}", tableName, errorMsg);
throw new RuntimeException("创建表失败: " + errorMsg, e);
}
}
private boolean tableExists(String tableName) {
try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData meta = conn.getMetaData();
// 获取当前数据库信息
String catalog = conn.getCatalog();
String schema = conn.getSchema();
// 查询表是否存在
try (ResultSet rs = meta.getTables(catalog, schema, tableName, new String[]{"TABLE"})) {
return rs.next();
}
} catch (SQLException e) {
LOGGER.error("检查表存在失败: {}", tableName, e);
return false;
}
}
private String extractMysqlError(SQLException e) {
// 提取MySQL特有的错误信息
while (e != null) {
if (e.getMessage().contains("MySQL")) {
return String.format("MySQL 错误 [%d]: %s", e.getErrorCode(), e.getMessage());
}
e = e.getNextException();
}
return "未知数据库错误";
}
// 编号生成工具方法
@ -216,6 +261,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
}
/**********************************
* 用途说明: 修改专项文档管理-项目管理
* 参数说明
@ -256,6 +303,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
//循环所有的ID
for (String id : dataset) {
Project project = projectMapper.selectById(id);
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
String path = "/" + project.getProjectName() + "/";
QueryWrapper<Nodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("project_id", id);
@ -288,7 +337,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
batchDeleteRequest.setDeleteItems(deleteItemList);
batchDeleteRequest.setStorageKey("sdlocal");
batchDeleteRequest.setStorageKey(storageSource.getKey());
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);
@ -330,4 +379,23 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
}
return value;
}
@Override
public List<Project> listProject() {
LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Project::getProjectTime);
List<Project> projects = projectMapper.selectList(queryWrapper);
for (Project project : projects){
StorageSource storageSource = getStorageConfig(project.getLocalStorageId());
project.setKey(storageSource.getKey());
project.setType(String.valueOf(storageSource.getType()));
}
return projects;
}
// 辅助方法获取存储配置
private StorageSource getStorageConfig(Integer id) {
return storageSourceMapper.selectOne(new LambdaQueryWrapper<StorageSource>().eq(StorageSource::getId, id)
);
}
}

View File

@ -13,6 +13,8 @@ import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import com.yfd.platform.modules.storage.model.param.IStorageParam;
import com.yfd.platform.modules.storage.service.StorageSourceConfigService;
import com.yfd.platform.modules.storage.service.StorageSourceService;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.modules.storage.support.StorageSourceSupport;
import com.yfd.platform.utils.ClassUtils;
@ -176,12 +178,23 @@ public class StorageSourceContext {
*
* @return 存储源对应未初始化的 Service
*/
private AbstractBaseFileService<IStorageParam> getInitStorageBeanByStorageId(Integer storageId) {
String keyById = storageSourceMapper.findKeyById(storageId);
StorageSource storageSource = storageSourceMapper.findByStorageKey(keyById);
String type = String.valueOf(storageSource.getType());
// private AbstractBaseFileService<IStorageParam> getInitStorageBeanByStorageId(Integer storageId) {
// String keyById = storageSourceMapper.findKeyById(storageId);
//// StorageSource storageSource = storageSourceMapper.findByStorageKey(keyById);
// storageSourceMapper
//// String type = String.valueOf(storageSource.getType());
//
// StorageTypeEnum storageTypeEnum = Optional.ofNullable(storageSourceMapper.findByStorageKey(keyById)).map(StorageSource::getType).orElse(null);
// for (AbstractBaseFileService<?> value : storageTypeEnumFileServiceMap.values()) {
// if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) {
// return SpringUtil.getBean(value.getClass());
// }
// }
// return null;
// }
StorageTypeEnum storageTypeEnum = Optional.ofNullable(storageSourceMapper.findByStorageKey(keyById)).map(StorageSource::getType).orElse(null);
private AbstractBaseFileService<IStorageParam> getInitStorageBeanByStorageId(Integer storageId) {
StorageTypeEnum storageTypeEnum = Optional.ofNullable(this.findById(storageId)).map(StorageSource::getType).orElse(null);;
for (AbstractBaseFileService<?> value : storageTypeEnumFileServiceMap.values()) {
if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) {
return SpringUtil.getBean(value.getClass());
@ -190,6 +203,9 @@ public class StorageSourceContext {
return null;
}
public StorageSource findById(Integer id) {
return storageSourceMapper.selectById(id);
}
/**
* 获取指定存储源的初始化参数.

View File

@ -1,14 +1,17 @@
package com.yfd.platform.modules.storage.controller.base;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest;
import com.yfd.platform.modules.config.model.request.UpdateStorageSortRequest;
import com.yfd.platform.modules.experimentalData.domain.TsFiles;
import com.yfd.platform.modules.storage.convert.StorageSourceConvert;
import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.enums.SearchModeEnum;
import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult;
import com.yfd.platform.modules.storage.service.StorageSourceService;
import io.swagger.annotations.Api;
@ -48,6 +51,33 @@ public class StorageSourceController {
return ResponseResult.successData(storageSourceAdminResults);
}
@ApiOperationSupport(order = 11)
@ApiOperation(value = "根据类型获取所有存储源列表", notes = "根据类型获取所有添加的存储源列表,按照排序值由小到大排序")
@GetMapping("/storagesBytype")
public ResponseResult storageListBytype(String type) {
List<StorageSource> list = storageSourceService.findAllOrderByOrderNumByType(type);
List<StorageSourceAdminResult> storageSourceAdminResults = storageSourceConvert.entityToAdminResultList(list);
return ResponseResult.successData(storageSourceAdminResults);
}
@ApiOperationSupport(order = 10)
@ApiOperation(value = "分页获取所有存储源列表", notes = "分页获取所有添加的存储源列表,按照排序值由小到大排序")
@GetMapping("/storagesPage")
public ResponseResult storagePage(Page<StorageSource> page,String type,String name) {
Page<StorageSource> pageResult = storageSourceService.findAllOrderByOrderNumPage(page, type,name);
Page<StorageSourceAdminResult> storageSourceAdminResults = storageSourceConvert.entityToAdminResultPage(pageResult);
return ResponseResult.successData(storageSourceAdminResults);
}
@ApiOperationSupport(order = 12)
@ApiOperation(value = "通过key查询type", notes = "通过key查询type")
@GetMapping("/storagesType")
public ResponseResult storagesType(String key) {
StorageSource storageSource = storageSourceService.findAllOrderBystoragesType(key);
return ResponseResult.successData(storageSource);
}
@ApiOperationSupport(order = 2)
@ApiOperation(value = "获取指定存储源参数", notes = "获取指定存储源基本信息及其参数")
@ -63,6 +93,10 @@ public class StorageSourceController {
@ApiOperation(value = "保存存储源参数", notes = "保存存储源的所有参数")
@PostMapping("/storage")
public ResponseResult saveStorageItem(@RequestBody SaveStorageSourceRequest saveStorageSourceRequest) {
saveStorageSourceRequest.setEnable( true);
saveStorageSourceRequest.setEnableFileOperator( true);
saveStorageSourceRequest.setSearchMode(SearchModeEnum.SEARCH_CACHE_MODE);
saveStorageSourceRequest.setEnableFileAnnoOperator(false);
Integer id = storageSourceService.saveStorageSource(saveStorageSourceRequest);
return ResponseResult.successData(id);
}
@ -78,6 +112,7 @@ public class StorageSourceController {
}
@ApiOperationSupport(order = 5)
@ApiOperation(value = "启用存储源", notes = "开启存储源后可在前台显示")
@ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class)

View File

@ -1,5 +1,6 @@
package com.yfd.platform.modules.storage.convert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest;
import com.yfd.platform.modules.readme.model.entity.ReadmeConfig;
import com.yfd.platform.modules.storage.model.dto.StorageSourceAllParamDTO;
@ -53,6 +54,7 @@ public interface StorageSourceConvert {
*/
List<StorageSourceAdminResult> entityToAdminResultList(List<StorageSource> list);
Page<StorageSourceAdminResult> entityToAdminResultPage(Page<StorageSource> pageResult);
StorageSourceDTO entityToDTO(StorageSource storageSource, StorageSourceAllParamDTO storageSourceAllParam);
@ -68,4 +70,5 @@ public interface StorageSourceConvert {
StorageSource saveRequestToEntity(SaveStorageSourceRequest saveStorageSourceRequest);
}

View File

@ -1,18 +1,31 @@
package com.yfd.platform.modules.storage.convert.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest;
import com.yfd.platform.modules.experimentalData.domain.TsTask;
import com.yfd.platform.modules.experimentalData.mapper.TsTaskMapper;
import com.yfd.platform.modules.readme.model.entity.ReadmeConfig;
import com.yfd.platform.modules.specialDocument.domain.Project;
import com.yfd.platform.modules.specialDocument.mapper.ProjectMapper;
import com.yfd.platform.modules.storage.convert.StorageSourceConvert;
import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper;
import com.yfd.platform.modules.storage.model.dto.StorageSourceAllParamDTO;
import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult;
import com.yfd.platform.modules.storage.model.result.StorageSourceConfigResult;
import com.yfd.platform.modules.storage.model.result.StorageSourceResult;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Date: 2025/1/10 12:44
@ -21,6 +34,18 @@ import java.util.List;
@Service
public class StorageSourceConvertImpl implements StorageSourceConvert {
@Resource
private StorageSourceConfigMapper storageSourceConfigMapper;
//专项项目表Mapper
@Resource
private ProjectMapper projectMapper;
//试验任务Mapper
@Resource
private TsTaskMapper tsTaskMapper;
@Override
public List<StorageSourceResult> entityToResultList(List<StorageSource> list) {
if ( list == null ) {
@ -57,18 +82,127 @@ public class StorageSourceConvertImpl implements StorageSourceConvert {
@Override
public List<StorageSourceAdminResult> entityToAdminResultList(List<StorageSource> list) {
if ( list == null ) {
return null;
if (list == null) {
return Collections.emptyList();
}
List<StorageSourceAdminResult> list1 = new ArrayList<StorageSourceAdminResult>( list.size() );
for ( StorageSource storageSource : list ) {
list1.add( storageSourceToStorageSourceAdminResult( storageSource ) );
}
return list1;
return list.stream()
.map(this::storageSourceToStorageSourceAdminResult)
.collect(Collectors.toList());
}
@Override
public Page<StorageSourceAdminResult> entityToAdminResultPage(Page<StorageSource> sourcePage) {
if (sourcePage == null) {
return new Page<>();
}
List<StorageSource> recordData = sourcePage.getRecords();
for (StorageSource storageSource : recordData) {
StringBuilder result = new StringBuilder(); // 用于拼接结果
String type = storageSource.getType().getKey();
if ("local".equals(type)) {
//获取关联的存储内容 先获取专项文档
LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Project::getLocalStorageId, storageSource.getId());
List<Project> projects = projectMapper.selectList(queryWrapper);
if (projects.size()>0){
for (Project project : projects) {
if (result.length() > 0) {
result.append(", "); // 如果结果不为空加上逗号分隔
}
result.append(project.getProjectName()); // 添加项目名称
}
}
LambdaQueryWrapper<TsTask> queryWrapper1 = new LambdaQueryWrapper<>();
queryWrapper1.eq(TsTask::getLocalStorageId, storageSource.getId());
List<TsTask> tsTasks = tsTaskMapper.selectList(queryWrapper1);
if (tsTasks.size()>0){
for (TsTask task : tsTasks) {
if (result.length() > 0) {
result.append(", "); // 如果结果不为空加上逗号分隔
}
result.append(task.getTaskName()); // 添加任务名称
}
}
storageSource.setStoreContent(String.valueOf(result));
//存储路径
LambdaQueryWrapper<StorageSourceConfig> queryWrapperData = new LambdaQueryWrapper<>();
queryWrapperData.eq(StorageSourceConfig::getStorageId, storageSource.getId());
queryWrapperData.eq(StorageSourceConfig::getName, "filePath");
String value = storageSourceConfigMapper.selectOne(queryWrapperData).getValue();
storageSource.setValueData(value);
//空间使用率
storageSource.setSpaceOccupancyRatio(calculateLocalStorageUsage(value));
}else {
LambdaQueryWrapper<TsTask> queryWrapper1 = new LambdaQueryWrapper<>();
queryWrapper1.eq(TsTask::getBackupStorageId, storageSource.getId());
List<TsTask> tsTasks = tsTaskMapper.selectList(queryWrapper1);
if (tsTasks.size()>0){
for (TsTask task : tsTasks) {
if (result.length() > 0) {
result.append(", "); // 如果结果不为空加上逗号分隔
}
result.append(task.getTaskName()); // 添加任务名称
}
}
storageSource.setStoreContent(String.valueOf(result));
storageSource.setValueData(null);
}
}
// 转换记录列表
List<StorageSourceAdminResult> records = entityToAdminResultList(sourcePage.getRecords());
// 创建目标分页对象并复制所有分页属性
Page<StorageSourceAdminResult> resultPage = new Page<>();
// 复制分页属性
resultPage.setRecords(records);
resultPage.setTotal(sourcePage.getTotal());
resultPage.setSize(sourcePage.getSize());
resultPage.setCurrent(sourcePage.getCurrent());
resultPage.setOrders(sourcePage.getOrders());
resultPage.setOptimizeCountSql(sourcePage.optimizeCountSql());
resultPage.setSearchCount(sourcePage.isSearchCount());
resultPage.setCountId(sourcePage.getCountId());
resultPage.setMaxLimit(sourcePage.getMaxLimit());
return resultPage;
}
// 计算本地路径的空间使用率
public static String calculateLocalStorageUsage(String path) {
File file = new File(path);
if (!file.exists()) {
throw new IllegalArgumentException("路径不存在: " + path);
}
// 获取磁盘空间信息
long totalSpace = file.getTotalSpace();
long freeSpace = file.getFreeSpace();
// 计算使用率
long usedSpace = totalSpace - freeSpace;
double usagePercentage = (double) usedSpace / totalSpace * 100;
// 格式化输出
DecimalFormat df = new DecimalFormat("#.##");
return df.format(usagePercentage) + "%";
}
@Override
public StorageSourceDTO entityToDTO(StorageSource storageSource, StorageSourceAllParamDTO storageSourceAllParam) {
if ( storageSource == null && storageSourceAllParam == null ) {
@ -178,7 +312,9 @@ public class StorageSourceConvertImpl implements StorageSourceConvert {
storageSourceAdminResult.setOrderNum( storageSource.getOrderNum() );
storageSourceAdminResult.setDefaultSwitchToImgMode( storageSource.getDefaultSwitchToImgMode() );
storageSourceAdminResult.setCompatibilityReadme( storageSource.getCompatibilityReadme() );
storageSourceAdminResult.setStoreContent( storageSource.getStoreContent());
storageSourceAdminResult.setSpaceOccupancyRatio( storageSource.getSpaceOccupancyRatio());
storageSourceAdminResult.setValueData( storageSource.getValueData());
return storageSourceAdminResult;
}
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.modules.storage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import org.apache.ibatis.annotations.Mapper;
@ -96,4 +97,7 @@ public interface StorageSourceMapper extends BaseMapper<StorageSource> {
*/
String findKeyById(@Param("id") Integer id);
Page<StorageSource> findAllOrderByOrderNumPage(@Param("page") Page<StorageSource> page,@Param("type") String type,@Param("name") String name);
List<StorageSource> findAllOrderByOrderNumByType(@Param("type") String type);
}

View File

@ -102,5 +102,13 @@ public class StorageSource implements Serializable {
@ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件")
private Boolean compatibilityReadme;
//存储内容
@TableField(exist = false)
private String storeContent;
//存储空间使用率
@TableField(exist = false)
private String spaceOccupancyRatio;
//存储路径
@TableField(exist = false)
private String valueData;
}

View File

@ -2,8 +2,10 @@ package com.yfd.platform.modules.storage.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonValue;
import io.swagger.annotations.ApiModelProperty;
import java.util.HashMap;
@ -59,6 +61,12 @@ public enum StorageTypeEnum implements IEnum {
this.description = description;
}
// 添加反序列化方法
@JsonCreator // 告诉Jackson用此方法反序列化
public static StorageTypeEnum fromKey(String key) {
return ENUM_MAP.get(key);
}
@JsonValue // 告诉Jackson序列化时使用此字段
public String getKey() {
return key;
}

View File

@ -1,5 +1,6 @@
package com.yfd.platform.modules.storage.model.result;
import com.baomidou.mybatisplus.annotation.TableField;
import com.yfd.platform.modules.storage.model.enums.SearchModeEnum;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import io.swagger.annotations.ApiModel;
@ -81,4 +82,14 @@ public class StorageSourceAdminResult {
@ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件")
private Boolean compatibilityReadme;
//存储内容
@TableField(exist = false)
private String storeContent;
//存储空间使用率
@TableField(exist = false)
private String spaceOccupancyRatio;
//存储路径
@TableField(exist = false)
private String valueData;
}

View File

@ -3,6 +3,9 @@ package com.yfd.platform.modules.storage.service;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.exception.BadRequestException;
import com.yfd.platform.exception.StorageSourceException;
import com.yfd.platform.exception.file.InvalidStorageSourceException;
import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest;
@ -15,6 +18,7 @@ import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import com.yfd.platform.modules.storage.model.param.QiniuParam;
import com.yfd.platform.utils.CodeMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
@ -61,6 +65,14 @@ public class StorageSourceService {
return storageSourceMapper.findAllOrderByOrderNum();
}
public List<StorageSource> findAllOrderByOrderNumByType(String type) {
return storageSourceMapper.findAllOrderByOrderNumByType(type);
}
public Page<StorageSource> findAllOrderByOrderNumPage(Page<StorageSource> page,String type,String name) {
return storageSourceMapper.findAllOrderByOrderNumPage(page,type,name);
}
/**
* 获取所有已启用的存储源列表按照存储源的排序号排序
@ -132,7 +144,21 @@ public class StorageSourceService {
*
* @return 存储源 DTO
*/
@Cacheable(key = "'dto-' + #id", unless = "#result == null")
// @Cacheable(key = "'dto-' + #id", unless = "#result == null")
// public StorageSourceDTO findDTOById(Integer id) {
// // 将参数列表通过反射写入到 StorageSourceAllParam .
// StorageSourceAllParamDTO storageSourceAllParam = new StorageSourceAllParamDTO();
// storageSourceConfigService.selectStorageConfigByStorageId(id)
// .forEach(storageSourceConfig ->
// ReflectUtil.setFieldValue(storageSourceAllParam, storageSourceConfig.getName(), storageSourceConfig.getValue())
// );
//
// // 获取数据库对象转为 dto 对象返回
// StorageSource storageSource = findById(id);
// return storageSourceConvert.entityToDTO(storageSource, storageSourceAllParam);
// }
//从表中直接获取 不从缓存
public StorageSourceDTO findDTOById(Integer id) {
// 将参数列表通过反射写入到 StorageSourceAllParam .
StorageSourceAllParamDTO storageSourceAllParam = new StorageSourceAllParamDTO();
@ -289,6 +315,11 @@ public class StorageSourceService {
saveStorageSourceRequest.getId(), saveStorageSourceRequest.getName(),
saveStorageSourceRequest.getKey(), saveStorageSourceRequest.getType().getDescription());
StorageSource storageSourceData = storageSourceMapper.findByStorageKey(saveStorageSourceRequest.getKey());
if (storageSourceData != null ){
throw new BadRequestException("填充存储源别名已存在");
}
// 转换为存储源 entity 对象
StorageSource storageSource = storageSourceConvert.saveRequestToEntity(saveStorageSourceRequest);
@ -319,4 +350,8 @@ public class StorageSourceService {
return storageId;
}
public StorageSource findAllOrderBystoragesType(String storageKey) {
return storageSourceMapper.findByStorageKey(storageKey);
}
}

View File

@ -57,6 +57,7 @@ public class CodeMsg {
public static CodeMsg STORAGE_SOURCE_INIT_FAIL = new CodeMsg("50100", "初始化存储源失败");
public static CodeMsg STORAGE_SOURCE_INIT_STORAGE_CONFIG_FAIL = new CodeMsg("50101", "初始化存储源参数失败");
public static CodeMsg STORAGE_SOURCE_INIT_STORAGE_PARAM_FIELD_FAIL = new CodeMsg("50102", "填充存储源字段失败");
public static CodeMsg STORAGE_SOURCE_INIT_REPEAT = new CodeMsg("50103", "填充存储源别名重复");
// 文件操作相关错误

View File

@ -0,0 +1,18 @@
package com.yfd.platform.utils;
public class TableNameContextHolder {
private static final ThreadLocal<String> TASK_CODE = new ThreadLocal<>();
public static void setTaskCode(String taskCode) {
TASK_CODE.set(taskCode);
}
public static String getTaskCode() {
return TASK_CODE.get();
}
public static void clear() {
TASK_CODE.remove();
}
}

View File

@ -38,7 +38,16 @@
SELECT count(*)
FROM ts_files
WHERE node_id IN (SELECT node_id FROM node_tree)
AND backup_path IS NOT NULL
AND (backup_path IS NOT NULL AND backup_path != '')
</select>
<update id="updateTsFileByPath">
UPDATE ts_files
SET work_path = REPLACE (
work_path,#{oldBasePath}, #{newBasePath})
WHERE
task_id = #{taskId}
AND work_path LIKE CONCAT(#{oldBasePath}, '%')
</update>
</mapper>

View File

@ -37,4 +37,120 @@
DELETE FROM sd_files WHERE node_id IN (SELECT id FROM node_tree)
</delete>
<update id="updateFileByPath">
UPDATE sd_files
SET file_path = REPLACE (
file_path,#{oldBasePath}, #{newBasePath})
WHERE
project_id = #{projectId}
AND file_path LIKE CONCAT(#{oldBasePath}, '%')
</update>
<select id="selectFilesPage" resultType="com.yfd.platform.modules.specialDocument.domain.Files">
<!-- 使用反引号包裹动态表名 -->
SELECT * FROM `${tableName}`
<where>
<!-- 文件名称不为空 -->
<if test="fileName != null and fileName != ''">
AND file_name LIKE CONCAT('%', #{fileName}, '%')
</if>
<!-- 关键字不为空 -->
<if test="keywords != null and keywords != ''">
AND keywords LIKE CONCAT('%', #{keywords}, '%')
</if>
<!-- 开始时间和结束时间 -->
<if test="startDate != null">
AND upload_time &gt;= #{startDate}
</if>
<if test="endDate != null">
AND upload_time &lt; #{endDate}
</if>
<!-- 项目ID和节点ID -->
<if test="projectId != null">
AND project_id = #{projectId}
</if>
<if test="nodeId != null">
AND node_id = #{nodeId}
</if>
</where>
ORDER BY upload_time DESC
</select>
<insert id="insertSdFilesTable">
INSERT INTO `${tableName}` (
id,
project_id,
node_id,
file_name,
file_path,
keywords,
file_size,
upload_time,
uploader
<!-- 其他字段 -->
) VALUES (
#{files.id},
#{files.projectId},
#{files.nodeId},
#{files.fileName},
#{files.filePath},
#{files.keywords},
#{files.fileSize},
#{files.uploadTime},
#{files.uploader}
<!-- 其他值 -->
)
</insert>
<update id="updateSdFiles">
UPDATE `${tableName}`
SET
file_name = #{files.fileName},
file_path = #{files.filePath},
keywords = #{files.keywords},
file_size = #{files.fileSize},
upload_time = #{files.uploadTime},
uploader = #{files.uploader}
<!-- 其他字段 -->
WHERE id = #{files.id}
</update>
<select id="selectSdFilesBatchIds" resultType="com.yfd.platform.modules.specialDocument.domain.Files">
<!-- 动态表名 -->
SELECT *
FROM `${tableName}`
<where>
<!-- 动态条件ID 集合 -->
<if test="dataset != null and dataset.size() > 0">
AND id IN
<foreach item="id" collection="dataset" open="(" close=")" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
<select id="selectSdFilesById" resultType="com.yfd.platform.modules.specialDocument.domain.Files">
SELECT *
FROM `${tableName}`
WHERE id = #{id}
</select>
<delete id="deleteSdFiles">
<!-- 删除动态表 -->
DELETE FROM `${tableName}`
<where>
<!-- 删除条件 -->
<if test="files.id != null">
AND id = #{files.id}
</if>
</where>
</delete>
</mapper>

View File

@ -37,4 +37,16 @@
DELETE FROM sd_nodes WHERE id IN (SELECT id FROM node_tree)
</delete>
<update id="updateNodesByPath">
UPDATE sd_nodes
SET custom3 = REPLACE (
custom3,#{oldBasePath}, #{newBasePath})
WHERE
project_id = #{projectId}
AND custom3 LIKE CONCAT(#{oldBasePath}, '%')
</update>
</mapper>

View File

@ -2,4 +2,8 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yfd.platform.modules.specialDocument.mapper.ProjectMapper">
<update id="createFileTable">
CREATE TABLE IF NOT EXISTS `${tableName}` LIKE `sd_files`
</update>
</mapper>

View File

@ -74,4 +74,37 @@
from fi_storage_source
where `id`=#{id,jdbcType=INTEGER}
</select>
<!--auto generated by MybatisCodeHelper on 2021-07-15-->
<select id="findAllOrderByOrderNumPage" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from fi_storage_source
<where>
<!-- 存储空间名称不为空 -->
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<!-- 存储策略不为空 -->
<if test="type != null and type != ''">
AND type =#{type}
</if>
</where>
order by ifnull(order_num, -1), id desc
</select>
<select id="findAllOrderByOrderNumByType" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from fi_storage_source
<where>
<!-- 存储策略不为空 -->
<if test="type != null and type != ''">
AND type =#{type}
</if>
</where>
order by ifnull(order_num, -1), id desc
</select>
</mapper>