diff --git a/java/pom.xml b/java/pom.xml index aecd25c..0a61ecc 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -12,7 +12,7 @@ com.yfd filesmanagesystem 1.0 - jar + war filesmanagesystem 文件管理系统 @@ -26,6 +26,14 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java index 62321cc..c0733c7 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java @@ -11,11 +11,16 @@ import com.yfd.platform.config.ResponseResult; import com.yfd.platform.modules.experimentalData.domain.TsTask; import com.yfd.platform.modules.experimentalData.service.ITsTaskService; import com.yfd.platform.utils.StringUtils; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.swagger.annotations.ApiOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -37,6 +42,8 @@ import java.util.Map; @RequestMapping("/experimentalData/tstask") public class TsTaskController { + private static final Logger LOGGER = LoggerFactory.getLogger(ChannelInboundHandlerAdapter.class); + //试验任务服务类 @Resource private ITsTaskService tsTaskService; @@ -214,4 +221,125 @@ public class TsTaskController { List tsTasks = tsTaskService.listTsTask(); return ResponseResult.successData(tsTasks); } + + @Log(module = "试验数据管理", value = "导出试验任务SQL数据") + @PostMapping("/exportTaskSql") + @ApiOperation("导出试验任务SQL数据") + @PreAuthorize("@el.check('export:tsTask')") + public void exportTaskSql(@RequestParam String taskId, HttpServletResponse response) { + if (StrUtil.isBlank(taskId)) { + throw new RuntimeException("任务ID不能为空"); + } + + try { + // 调用服务层执行导出操作 + byte[] zipData = tsTaskService.exportTaskSqlAsZip(taskId); + + // 添加日志记录ZIP数据大小 + LOGGER.info("生成的ZIP文件大小: {} 字节", zipData.length); + + // 验证ZIP数据是否有效 + if (zipData.length == 0) { + throw new RuntimeException("生成的ZIP数据为空"); + } + + // 获取任务信息用于文件名 + TsTask task = tsTaskService.getById(taskId); + String taskCode = ""; + + // 确保taskCode有值且符合5位数字格式 + if (task != null && StrUtil.isNotBlank(task.getTaskCode())) { + taskCode = task.getTaskCode(); + // 验证taskCode格式是否正确(5位数字) + if (!taskCode.matches("^\\d{5}$")) { + // 如果不是5位数字格式,需要处理 + try { + int codeValue = Integer.parseInt(taskCode); + if (codeValue >= 1 && codeValue <= 99999) { + // 格式化为5位数字字符串 + taskCode = String.format("%05d", codeValue); + } else { + throw new IllegalArgumentException("该任务编号超出有效范围: " + taskCode); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException("无效的任务编号格式: " + taskCode); + } + } + } + + // 设置响应头信息 + String fileName = taskCode + "_exportdata.zip"; + response.setContentType("application/zip"); + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + response.setContentLength(zipData.length); + + // 写入响应流 + response.getOutputStream().write(zipData); + response.getOutputStream().flush(); + + LOGGER.info("ZIP文件导出成功,文件名: {}, 大小: {} 字节", fileName, zipData.length); + } catch (Exception e) { + LOGGER.error("导出试验任务SQL数据失败", e); + throw new RuntimeException("导出失败:" + e.getMessage()); + } + } + + + /********************************** + * 用途说明: 导入ZIP文件中的试验任务SQL数据 + * 参数说明: + * file ZIP文件 + * taskCode 任务编号 + * localStorageId 本地存储空间标识 + * backupStorageId 备份空间标识 + * 返回值说明: ResponseResult 返回导入结果 + ***********************************/ + @Log(module = "试验数据管理", value = "导入试验任务SQL数据") + @PostMapping("/importTaskSql") + @ApiOperation("导入试验任务SQL数据") + @PreAuthorize("@el.check('import:tsTask')") + public ResponseResult importTaskSql(@RequestParam("file") MultipartFile file, + @RequestParam("taskCode") String taskCode, + @RequestParam("localStorageId") int localStorageId, + @RequestParam("backupStorageId") int backupStorageId) { + if (file.isEmpty() || StrUtil.isBlank(taskCode)) { + return ResponseResult.error("文件或任务编号不能为空"); + } + + try { + // 调用服务层执行导入操作 + boolean result = tsTaskService.importTaskSqlFromZip(file, taskCode, localStorageId, backupStorageId); + + if (result) { + return ResponseResult.success("导入成功"); + } else { + return ResponseResult.error("导入失败"); + } + } catch (Exception e) { + //log.error("导入试验任务SQL数据失败", e); + return ResponseResult.error("导入失败:" + e.getMessage()); + } + } + + /********************************** + * 用途说明: 获取最大的任务编号+1 + * 参数说明: 无 + * 返回值说明: ResponseResult 返回最大任务编号+1 + ***********************************/ + @Log(module = "试验数据管理", value = "获取最大任务编号") + @GetMapping("/getMaxTaskCode") + @ApiOperation("获取最大任务编号") +// @PreAuthorize("@el.check('select:tsTask')") + public ResponseResult getMaxTaskCode() { + try { + String maxTaskCode = tsTaskService.getMaxTaskCode(); + return ResponseResult.successData(maxTaskCode); + } catch (Exception e) { + //log.error("获取最大任务编号失败", e); + return ResponseResult.error("获取最大任务编号失败:" + e.getMessage()); + } + } + + } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsTaskMapper.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsTaskMapper.java index 869cd3d..58e3718 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsTaskMapper.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsTaskMapper.java @@ -13,4 +13,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface TsTaskMapper extends BaseMapper { + /** + * 查询最大的任务编号 + * @return 最大任务编号 + */ + String selectMaxTaskCode(); + } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java index b797e8e..5751998 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java @@ -264,4 +264,12 @@ public interface ITsFilesService extends IService { * 返回值说明: com.yfd.platform.config.ResponseResult 返回文件集合列表 ***********************************/ Object listTsFilesById(String id, String taskId, String nodeId); + + /** + * 根据任务ID获取文件列表 + * @param taskId 任务ID + * @return 文件列表 + */ + List getByTaskId(String taskId); + } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsNodesService.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsNodesService.java index 1e864a9..a77363c 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsNodesService.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsNodesService.java @@ -65,4 +65,12 @@ public interface ITsNodesService extends IService { * 返回值说明: com.yfd.platform.config.ResponseResult 返回删除成功或者失败 ***********************************/ Object confirmDeleteNodes(String id); + + /** + * 根据任务ID获取节点列表 + * @param taskId 任务ID + * @return 节点列表 + */ + List getByTaskId(String taskId); + } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java index ed9a1ef..b3022dd 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java @@ -3,6 +3,7 @@ package com.yfd.platform.modules.experimentalData.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.experimentalData.domain.TsTask; import com.baomidou.mybatisplus.extension.service.IService; +import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.List; @@ -70,4 +71,27 @@ public interface ITsTaskService extends IService { List listTsTask(); + /** + * 导出试验任务相关SQL数据为ZIP文件 + * @param taskId 任务ID + * @return ZIP文件字节数组 + */ + byte[] exportTaskSqlAsZip(String taskId) throws IOException; + + /** + * 从ZIP文件导入试验任务SQL数据 + * @param file ZIP文件 + * @param taskCode 任务编号 + * @param localStorageId 本地存储空间标识 + * @param backupStorageId 备份空间标识 + * @return 是否导入成功 + */ + boolean importTaskSqlFromZip(MultipartFile file, String taskCode, int localStorageId, int backupStorageId) throws IOException; + + /** + * 获取最大任务编号+1 + * @return 最大任务编号+1 + */ + String getMaxTaskCode(); + } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java index 39c680e..01e7937 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java @@ -6275,6 +6275,12 @@ public class TsFilesServiceImpl extends ServiceImpl impl return String.format("%s,%s,%s,%s", parts[0], parts[1], parts[2], parts[3]); } + @Override + public List getByTaskId(String taskId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getTaskId, taskId); + return this.list(queryWrapper); + } } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java index 87a7fa4..126b4ce 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java @@ -682,7 +682,10 @@ public class TsNodesServiceImpl extends ServiceImpl impl } else { deleteFailCount++; } - } catch (Exception e) { + }catch (NullPointerException e) { + LOGGER.error("删除节点时发生空指针异常,文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); + deleteFailCount++; + }catch (Exception e) { LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); deleteFailCount++; } @@ -1132,4 +1135,12 @@ public class TsNodesServiceImpl extends ServiceImpl impl return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) ); } + + @Override + public List getByTaskId(String taskId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsNodes::getTaskId, taskId); + return this.list(queryWrapper); + } + } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java index 0b09e9f..a121dee 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONObject; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -36,11 +37,21 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; import java.sql.*; +import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter; import java.util.*; @@ -48,7 +59,13 @@ import java.util.*; import javax.annotation.Resource; import javax.sql.DataSource; import java.time.LocalDateTime; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; /** *

@@ -93,6 +110,9 @@ public class TsTaskServiceImpl extends ServiceImpl impleme private SysDictionaryItemsMapper sysDictionaryItemsMapper; @Autowired private DataSource dataSource; + @Autowired + private JdbcTemplate jdbcTemplate; + private static final String INITIAL_CODE = "00001"; private static final int MAX_CODE_VALUE = 99999; @@ -533,98 +553,97 @@ public class TsTaskServiceImpl extends ServiceImpl impleme Boolean value = false; try { - - //循环所有的ID for (String taskId : dataset) { - //删除项目 - TsTask tsTask = tsTaskMapper.selectById(taskId); - TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); - // 删除节点表 - LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); - deleteWrapper.eq(TsNodes::getTaskId, taskId); - tsNodesMapper.delete(deleteWrapper); + try { + //获取试验任务及任务编码 + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); - // 删除文件表 - LambdaQueryWrapper deleteWrapperFiles = new LambdaQueryWrapper<>(); - deleteWrapperFiles.eq(TsFiles::getTaskId, taskId); - tsFilesMapper.delete(deleteWrapperFiles); - //todo 删除文件表数据 -// tsFilesMapper.deleteSdFilesBytaskId(taskId); + // 删除节点表 + LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); + deleteWrapper.eq(TsNodes::getTaskId, taskId); + tsNodesMapper.delete(deleteWrapper); + // 删除文件表 + LambdaQueryWrapper deleteWrapperFiles = new LambdaQueryWrapper<>(); + deleteWrapperFiles.eq(TsFiles::getTaskId, taskId); + tsFilesMapper.delete(deleteWrapperFiles); -// String path = "/" + tsTask.getTaskName() + "/"; -// //调用删除节点 根据任务ID -// Boolean deleteTsnodes = tsNodesService.deleteTsNodesByTaskId(taskId, path); -// //如果删除成功 接着删除节点表数据 -// if (deleteTsnodes) { -// LOGGER.info("tsNodes表结删除改成功"); -// value = true; -// } else { -// LOGGER.error("tsNodes表结构删除失败"); -// value = false; -// } + // 删除本地存储空间中的文件夹 + StorageSource localStorageSource = getStorageConfig(tsTask.getLocalStorageId()); + deleteStorageFolder(localStorageSource, tsTask); - StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); - // 删除 local 中的文件夹 项目文件夹 - List 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); - - 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 { - deleteFailCount++; - } - } catch (Exception e) { - LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); - deleteFailCount++; + // 如果有备份存储空间,也删除备份存储空间中的文件夹 + if (tsTask.getBackupStorageId() != null && tsTask.getBackupStorageId() > 0) { + StorageSource backupStorageSource = getStorageConfig(tsTask.getBackupStorageId()); + deleteStorageFolder(backupStorageSource, tsTask); } - } - - if (deleteSuccessCount >= 1) { - // 删除当前项目 + // 删除当前试验任务 int deleteCount = tsTaskMapper.deleteById(taskId); if (deleteCount == 1) { - LOGGER.info("tstask表结删除改成功"); + LOGGER.info("tstask表结构删除成功"); value = true; } else { LOGGER.error("tstask表结构删除失败"); value = false; } - } else { - value = false; + } finally { + // 每次处理完一个任务后清理上下文 + TableNameContextHolder.clear(); } - - } - return value; } catch (Exception e) { - - } finally { - TableNameContextHolder.clear(); + LOGGER.error("删除试验任务时发生异常", e); + return false; + } + } + + + // 这个方法会递归删除试验任务文件夹及其下的所有子文件夹和文件。当调用 fileService.deleteFolder() 方法时,存储服务实现会自动处理递归删除逻辑,确保整个文件夹树都被清除。 + //这是文件存储系统的基本特性,不论是本地文件系统还是MinIO等云存储服务,在删除文件夹时都会删除其包含的所有内容。 + private void deleteStorageFolder(StorageSource storageSource, TsTask tsTask) { + try { + List 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; + 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++; + LOGGER.info("删除成功 - 存储类型: {}, 类型: {}, 路径: {}, 名称: {}", + storageSource.getKey(), deleteItem.getType(), deleteItem.getPath(), deleteItem.getName()); + } else { + LOGGER.warn("删除失败 - 存储类型: {}, 类型: {}, 路径: {}, 名称: {}", + storageSource.getKey(), deleteItem.getType(), deleteItem.getPath(), deleteItem.getName()); + } + } catch (Exception e) { + LOGGER.error("删除文件/文件夹失败, 存储类型: {}, 文件路径: {}, 文件名称: {}", + storageSource.getKey(), deleteItem.getPath(), deleteItem.getName(), e); + } + } + } catch (Exception e) { + LOGGER.error("删除存储空间文件夹时发生异常, 存储类型: {}", storageSource.getKey(), e); } - return value; } /********************************** @@ -645,11 +664,11 @@ public class TsTaskServiceImpl extends ServiceImpl impleme for (TsTask tsTask : tsTasks) { TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); - // 查询是否有备份路径或非空路径的文件 + // 查询 backup_path 既不为 null 也不为空字符串的记录 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(TsFiles::getTaskId, tsTask.getId()) - .and(wrapper -> wrapper.isNotNull(TsFiles::getBackupPath) - .or().ne(TsFiles::getBackupPath, "")); + .isNotNull(TsFiles::getBackupPath) + .ne(TsFiles::getBackupPath, ""); int count = tsFilesService.count(queryWrapper); @@ -719,4 +738,608 @@ public class TsTaskServiceImpl extends ServiceImpl impleme return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) ); } + + @Override + public byte[] exportTaskSqlAsZip(String taskId) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + try(ZipOutputStream zos = new ZipOutputStream(baos)) { + // 生成SQL内容 + StringBuilder sqlBuilder = new StringBuilder(); + + // 1. 添加ts_task表数据导出 + TsTask task = this.getById(taskId); + String taskCode = ""; + + // 确保taskCode有值且符合5位数字格式 + if (task != null && StrUtil.isNotBlank(task.getTaskCode())) { + taskCode = task.getTaskCode(); + // 验证taskCode格式是否正确(5位数字) + if (!taskCode.matches("^\\d{5}$")) { + // 如果不是5位数字格式,需要处理 + try { + int codeValue = Integer.parseInt(taskCode); + if (codeValue >= 1 && codeValue <= 99999) { + // 格式化为5位数字字符串 + taskCode = String.format("%05d", codeValue); + } else { + throw new IllegalArgumentException("该任务编号超出有效范围: " + taskCode); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException("无效的任务编号格式: " + taskCode); + } + } + } + if (task != null) { + sqlBuilder.append("-- 试验任务数据\n"); + sqlBuilder.append(generateInsertSql("ts_task", task)).append("\n\n"); + } + + //2. 添加ts_nodes表相关记录导出(需要注入相应的service) + List nodes = tsNodesService.getByTaskId(taskId); + if (nodes != null && !nodes.isEmpty()) { + sqlBuilder.append("-- 节点数据\n"); + for (TsNodes node : nodes) { + sqlBuilder.append(generateInsertSql("ts_nodes", node)).append("\n"); + } + sqlBuilder.append("\n"); + } + + // 3. 添加ts_files表结构和数据导出 + if (task != null) { + String dynamicTableName = "ts_files_" + task.getTaskCode(); + // 设置动态表名上下文 + TableNameContextHolder.setTaskCode(task.getTaskCode()); + + try { + // 查询该任务的所有文件数据 + List files = tsFilesService.getByTaskId(taskId); + if (files != null && !files.isEmpty()) { + sqlBuilder.append("-- 文件表结构\n"); + sqlBuilder.append(generateCreateTableSql(dynamicTableName)).append("\n\n"); + + sqlBuilder.append("-- 文件数据\n"); + for (TsFiles file : files) { + sqlBuilder.append(generateInsertSql(dynamicTableName, file)).append("\n"); + } + } + } finally { + // 清理表名上下文 + TableNameContextHolder.clear(); + } + } + + // 将SQL内容写入ZIP文件 + ZipEntry sqlEntry = new ZipEntry(taskCode+"_exportdata.sql"); + zos.putNextEntry(sqlEntry); + zos.write(sqlBuilder.toString().getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); + + zos.finish(); +// zos.flush(); + + byte[] result = baos.toByteArray(); + LOGGER.info("生成ZIP数据大小: {} 字节", result.length); + return result; + } finally { + //zos.close(); + baos.close(); + } +} + + // 生成INSERT SQL语句的方法 + private String generateInsertSql(String tableName, Object entity) { + if (entity == null) { + return ""; + } + + try { + Class clazz = entity.getClass(); + Field[] fields = clazz.getDeclaredFields(); + + StringBuilder columns = new StringBuilder(); + StringBuilder values = new StringBuilder(); + + for (Field field : fields) { + // 跳过序列化相关字段 + if (field.getName().equals("serialVersionUID")) { + continue; + } + // 跳过非数据库字段(可以根据实际需要调整条件) + if (field.getName().equals("key")) { + continue; + } + + // 跳过 ts_nodes 表中不存在的字段 + if ("ts_nodes".equals(tableName) && "path".equals(field.getName())) { + continue; + } + + // 跳过 ts_files 相关表中不存在的字段 + if (tableName.startsWith("ts_files_") && + ("url".equals(field.getName()) || + "type".equals(field.getName()) || + "localOnlyFiles".equals(field.getName()) || + "minioOnlyFiles".equals(field.getName()) || + "md5mismatchedFiles".equals(field.getName()) || + "locatMd5".equals(field.getName()) || + "minioMd5".equals(field.getName()) || + "fileContent".equals(field.getName()) || + "md5MismatchedFiles".equals(field.getName()))) { + continue; + } + + field.setAccessible(true); + String columnName = camelToUnderscore(field.getName()); + Object value = field.get(entity); + + columns.append(columnName).append(","); + values.append(formatValue(value)).append(","); + } + + // 移除末尾逗号 + if (columns.length() > 0) { + columns.deleteCharAt(columns.length() - 1); + values.deleteCharAt(values.length() - 1); + } + + return "INSERT INTO " + tableName + " (" + columns + ") VALUES (" + values + ");"; + } catch (Exception e) { + LOGGER.error("生成INSERT SQL语句失败", e); + return ""; + } + } + + // 驼峰命名转下划线 + private String camelToUnderscore(String camelCase) { + return camelCase.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase(); + } + + // 格式化值 + private String formatValue(Object value) { + if (value == null) { + return "NULL"; + } + if (value instanceof String) { + return "'" + value.toString().replace("'", "''") + "'"; + } + if (value instanceof Date) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return "'" + sdf.format(value) + "'"; + } + // 处理 java.time 类型 + if (value instanceof java.time.LocalDate) { + return "'" + value.toString() + "'"; + } + if (value instanceof java.time.LocalDateTime) { + return "'" + ((java.time.LocalDateTime) value).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "'"; + } + return value.toString(); + } + + + + + + // 生成CREATE TABLE SQL语句的方法 + private String generateCreateTableSql(String tableName) { + // 使用 LIKE 语句创建与 ts_files 结构相同的新表 + return "CREATE TABLE IF NOT EXISTS `" + tableName + "` LIKE `ts_files`;"; + } + + /** + * 从ZIP文件中导入任务SQL数据 + * + * @param file ZIP文件,包含SQL文件 + * @param taskCode 目标任务编号,用于替换SQL中的原始任务编号 + * @param localStorageId 本地存储ID + * @param backupStorageId 备份存储ID + * @return 导入成功返回true,失败返回false + * @throws IOException 文件读取或解压过程中发生IO异常 + */ + @Override + public boolean importTaskSqlFromZip(MultipartFile file, String taskCode, int localStorageId, int backupStorageId) throws IOException { + + // 1. 解压ZIP文件 + byte[] zipBytes = file.getBytes(); + //根据文件名称获取原始任务编号:00002_data.sql.zip + String originalFilename = file.getOriginalFilename(); + String originalTaskCode = extractTaskCodeFromFileName(originalFilename); + List sqlFiles = extractSqlFromZip(zipBytes); + + // 2. 替换 SQL 文件中的任务编号,存储空间编号。 + List allSqlStatements = new ArrayList<>(); + for (SqlFileContent sqlFile : sqlFiles) { + LOGGER.debug("原始SQL内容: {}", sqlFile.getContent().substring(0, Math.min(200, sqlFile.getContent().length()))); + String modifiedContent = replaceTaskCodeInSql(sqlFile.getContent(), originalTaskCode, taskCode, localStorageId, backupStorageId); + LOGGER.debug("替换后SQL内容: {}", modifiedContent.substring(0, Math.min(200, modifiedContent.length()))); + allSqlStatements.addAll(parseSqlStatements(modifiedContent)); + } + + // 3. 拆分 DDL 与 INSERT 语句,合并相同表的 INSERT,提高执行效率 + List ddlSqlList = new ArrayList<>(); + List dmlSqlList = new ArrayList<>(); + + for (String sql : allSqlStatements) { + String upper = sql.trim().toUpperCase(); + if (upper.startsWith("CREATE") || upper.startsWith("DROP") || upper.startsWith("ALTER") || upper.startsWith("SET")) { + ddlSqlList.add(sql); + } else if (upper.startsWith("INSERT")) { + dmlSqlList.add(sql); + } + } + + // 先执行 DDL + LOGGER.info("开始执行DDL语句,共 {} 条", ddlSqlList.size()); + executeSqlImport(ddlSqlList); + + // 再合并并执行 DML + List mergedSqlStatements = mergeInsertStatements(dmlSqlList); + LOGGER.info("开始导入数据,共 {} 条INSERT语句,合并后 {} 条", dmlSqlList.size(), mergedSqlStatements.size()); + long startTime = System.currentTimeMillis(); + + // 4. 执行 SQL 批量导入 + boolean result = executeSqlImport(mergedSqlStatements); + + long endTime = System.currentTimeMillis(); + LOGGER.info("SQL导入完成,耗时 {} ms", (endTime - startTime)); + return result; + } + + /** + * 从文件名中提取原始任务编号 + * @param fileName 文件名,如 "00002_data.sql.zip" + * @return 任务编号,如 "00002" + */ + private String extractTaskCodeFromFileName(String fileName) { + if (StrUtil.isBlank(fileName)) { + return null; + } + + // 使用正则表达式匹配5位数字开头的文件名 + Pattern pattern = Pattern.compile("^(\\d{5})_.*$"); + Matcher matcher = pattern.matcher(fileName); + + if (matcher.matches()) { + String taskCode = matcher.group(1); + // 验证任务编号范围是否在00001-99999之间 + try { + int codeValue = Integer.parseInt(taskCode); + if (codeValue >= 1 && codeValue <= 99999) { + return taskCode; + } + } catch (NumberFormatException e) { + // 解析失败,返回null + return null; + } + } + + return null; + } + + + // 解压ZIP文件并提取SQL内容 + private List extractSqlFromZip(byte[] zipBytes) throws IOException { + List sqlFiles = new ArrayList<>(); + try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes))) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + if (!entry.isDirectory() && entry.getName().endsWith(".sql")) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int len; + while ((len = zis.read(buffer)) > 0) { + baos.write(buffer, 0, len); + } + // 修改这一行,使用 Charset 的名称而不是 Charset 对象 + sqlFiles.add(new SqlFileContent(entry.getName(), baos.toString(StandardCharsets.UTF_8.name()))); + } + } + } + return sqlFiles; + } + + private String replaceTaskCodeInSql(String sqlContent, String originalTaskCode, String newTaskCode, int localStorageId, int backupStorageId) { + if (StrUtil.isBlank(originalTaskCode)) { + return sqlContent; + } + + // 同时替换 ts_task 表中的 task_code 值和存储空间ID值 + Pattern taskPattern = Pattern.compile( + "(INSERT\\s+INTO\\s+`?ts_task`?\\s*\\([^)]*?task_code[^)]*?\\)\\s*VALUES\\s*\\([^)]*?)('"+Pattern.quote(originalTaskCode)+"')([^)]*)(? parseSqlStatements(String sqlContent) { + List sqlList = new ArrayList<>(); + String[] lines = sqlContent.split("\n"); + StringBuilder currentStatement = new StringBuilder(); + LOGGER.debug("开始解析SQL内容,总行数: {}", lines.length); + for (String line : lines) { + String trimmedLine = line.trim(); + + // 跳过纯注释行 + if (trimmedLine.startsWith("--")) { + continue; + } + + // 跳过空行 + if (trimmedLine.isEmpty()) { + continue; + } + + // 添加当前行到语句构建器 + currentStatement.append(trimmedLine).append(" "); + + // 如果当前行以分号结尾,说明是一个完整语句 + if (trimmedLine.endsWith(";")) { + String statement = currentStatement.toString().trim(); + if (!statement.isEmpty()) { + sqlList.add(statement); + LOGGER.debug("解析到SQL语句: {}", statement.length() > 200 ? statement.substring(0, 200) + "..." : statement); + + } + currentStatement.setLength(0); // 重置构建器 + } + } + + // 处理可能残留的未完成语句(虽然理论上不应该有) + String remaining = currentStatement.toString().trim(); + if (!remaining.isEmpty() && remaining.endsWith(";")) { + sqlList.add(remaining); + LOGGER.debug("解析到残留SQL语句: {}", remaining.length() > 200 ? remaining.substring(0, 200) + "..." : remaining); + + } + + return sqlList; + } + + + // =========================== 高性能导入部分 =========================== +// 批量执行: 使用batchExecute方法进行批量处理 +// INSERT语句合并: 通过mergeInsertStatements方法将多个INSERT语句合并为批量插入 +// 事务优化: 导入过程中关闭了外键检查和唯一性检查 +// 禁用自动提交: 使用SET AUTOCOMMIT=0来提高性能 + + @Transactional(rollbackFor = Exception.class) + public boolean executeSqlImport(List sqlStatements) { + int total = 0; // 在方法开始处声明 total 变量 + try { + jdbcTemplate.execute("SET FOREIGN_KEY_CHECKS=0;"); + jdbcTemplate.execute("SET UNIQUE_CHECKS=0;"); + jdbcTemplate.execute("SET AUTOCOMMIT=0;"); + + int batchSize = 2000; + List batch = new ArrayList<>(batchSize); + + for (String sql : sqlStatements) { + if (StringUtils.isBlank(sql)) continue; + batch.add(sql); + if (batch.size() >= batchSize) { + batchExecute(batch); + total += batch.size(); + LOGGER.info("已执行 {} 条SQL语句", total); + batch.clear(); + } + } + if (!batch.isEmpty()) { + batchExecute(batch); + total += batch.size(); + } + + jdbcTemplate.execute("SET FOREIGN_KEY_CHECKS=1;"); + jdbcTemplate.execute("SET UNIQUE_CHECKS=1;"); + jdbcTemplate.execute("COMMIT;"); + + LOGGER.info("批量导入完成,共执行 {} 条SQL", total); + return true; + } catch (Exception e) { + LOGGER.error("SQL导入失败,已执行 {} 条SQL", total, e); + try { + jdbcTemplate.execute("ROLLBACK;"); + } catch (Exception rollbackEx) { + LOGGER.error("回滚事务失败", rollbackEx); + } + throw new RuntimeException("SQL导入失败:" + e.getMessage(), e); + } + } + + + private void batchExecute(List sqlList) { + try { + jdbcTemplate.batchUpdate(sqlList.toArray(new String[0])); + } catch (DataAccessException e) { + LOGGER.warn("批量执行失败,分步重试:{}", e.getMessage()); + for (String sql : sqlList) { + try { + jdbcTemplate.update(sql); + } catch (Exception ex) { + LOGGER.warn("跳过失败SQL:{}", ex.getMessage()); + } + } + } + } + + // =========================== INSERT 合并优化 =========================== + private List mergeInsertStatements(List sqlStatements) { + Map> groupedStatements = new LinkedHashMap<>(); + + Pattern pattern = Pattern.compile( + "INSERT\\s+INTO\\s+`?(\\w+)`?\\s*\\(([^)]+)\\)\\s*VALUES\\s*\\((.*)\\)", + Pattern.CASE_INSENSITIVE + ); + + for (String sql : sqlStatements) { + Matcher matcher = pattern.matcher(sql); + if (matcher.find()) { + String table = matcher.group(1); + String columns = matcher.group(2); + String values = matcher.group(3); + + // 使用表名+列名作为分组键 + String key = table + ":" + columns; + + groupedStatements.computeIfAbsent(key, k -> new ArrayList<>()).add(values); + } else { + // 无法匹配的语句单独处理 + groupedStatements.computeIfAbsent("_others", k -> new ArrayList<>()).add(sql); + } + } + + List mergedSql = new ArrayList<>(); + for (Map.Entry> entry : groupedStatements.entrySet()) { + String key = entry.getKey(); + List valuesList = entry.getValue(); + + if ("_others".equals(key)) { + mergedSql.addAll(valuesList); + } else { + String[] parts = key.split(":", 2); + String table = parts[0]; + String columns = parts[1]; + + StringBuilder sb = new StringBuilder(); + sb.append("INSERT INTO `").append(table).append("` (").append(columns).append(") VALUES "); + + for (int i = 0; i < valuesList.size(); i++) { + if (i > 0) { + sb.append(","); + } + sb.append("(").append(valuesList.get(i)).append(")"); + } + sb.append(";"); + + mergedSql.add(sb.toString()); + } + } + + return mergedSql; + } + + + + // =========================== 内部类定义 =========================== + + private static class SqlFileContent { + private final String name; + private final String content; + + public SqlFileContent(String name, String content) { + this.name = name; + this.content = content; + } + + public String getName() { + return name; + } + + public String getContent() { + return content; + } + } + + + @Override + public String getMaxTaskCode() { + // 查询数据库中最大的任务编号 + String maxTaskCode = this.baseMapper.selectMaxTaskCode(); + if (StrUtil.isBlank(maxTaskCode)) { + // 如果没有任务编号记录,返回默认值 + return "00001"; + } + try { + // 解析5位数字格式的任务编号并递增 + int currentNumber = Integer.parseInt(maxTaskCode); + int nextNumber = currentNumber + 1; + + // 确保不超过5位数的最大值 + if (nextNumber > 99999) { + throw new IllegalStateException("任务编号已达到最大值99999"); + } + + // 格式化为5位数字字符串 + return String.format("%05d", nextNumber); + } catch (NumberFormatException e) { + // 如果解析失败,返回默认值 + return "00001"; + } + } + + + } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java index 681fa5e..8fe2f12 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java @@ -135,7 +135,28 @@ public class LocalServiceImpl extends AbstractProxyTransferService { checkNameSecurity(name); String fullPath = StringUtils.concat(param.getFilePath(), path, name); - return FileUtil.del(fullPath); + try { + // 检查文件是否存在 + File file = new File(fullPath); + if (!file.exists()) { + log.warn("文件不存在: {}", fullPath); + return true; // 文件不存在也算删除成功 + } + + // 检查并尝试修改文件权限 + if (!file.canWrite()) { + log.info("文件无写权限,尝试修改权限: {}", fullPath); + boolean permissionChanged = file.setWritable(true); + if (!permissionChanged) { + log.warn("无法修改文件写权限: {}", fullPath); + } + } + + return FileUtil.del(fullPath); + } catch (Exception e) { + log.error("删除文件失败: {}, 错误: {}", fullPath, e.getMessage(), e); + return false; + } } @@ -144,7 +165,61 @@ public class LocalServiceImpl extends AbstractProxyTransferService { checkPathSecurity(path); checkNameSecurity(name); - return deleteFile(path, name); + String fullPath = StringUtils.concat(param.getFilePath(), path, name); + try { + // 检查文件夹是否存在 + File folder = new File(fullPath); + if (!folder.exists()) { + log.warn("文件夹不存在: {}", fullPath); + return true; // 文件夹不存在也算删除成功 + } + + // 检查并尝试修改文件夹权限 + if (!folder.canWrite()) { + log.info("文件夹无写权限,尝试修改权限: {}", fullPath); + boolean permissionChanged = folder.setWritable(true); + if (!permissionChanged) { + log.warn("无法修改文件夹写权限: {}", fullPath); + } + } + + // 递归修改文件夹内所有文件的权限 + setWritableRecursively(folder); + + return FileUtil.del(fullPath); + } catch (Exception e) { + log.error("删除文件夹失败: {}, 错误: {}", fullPath, e.getMessage(), e); + return false; + } + } + + /** + * 递归设置文件夹及其内部所有文件的写权限 + * @param file 文件或文件夹 + */ + private void setWritableRecursively(File file) { + if (file.isFile()) { + if (!file.canWrite()) { + boolean success = file.setWritable(true); + if (!success) { + log.debug("无法设置文件写权限: {}", file.getAbsolutePath()); + } + } + } else if (file.isDirectory()) { + if (!file.canWrite()) { + boolean success = file.setWritable(true); + if (!success) { + log.debug("无法设置文件夹写权限: {}", file.getAbsolutePath()); + } + } + + File[] files = file.listFiles(); + if (files != null) { + for (File f : files) { + setWritableRecursively(f); + } + } + } } diff --git a/java/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/java/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java index cfcfaab..0b7a9dc 100644 --- a/java/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java @@ -18,7 +18,9 @@ import com.yfd.platform.system.service.IUserService; import com.yfd.platform.utils.FileUtil; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -65,20 +67,47 @@ public class UserServiceImpl extends ServiceImpl impleme ***********************************/ @Override public String getUsername() { - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - String acountname = - loginuser.getUser().getNickname(); - return acountname; - //return "admin"; + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null || !authentication.isAuthenticated() || + authentication instanceof AnonymousAuthenticationToken) { + return "anonymous"; + } + + if (authentication instanceof UsernamePasswordAuthenticationToken) { + LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + return loginuser.getUser().getNickname(); + } + + return "unknown"; } + @Override public Map getNameInfo() { - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + // 安全地获取认证信息 + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + // 检查认证信息是否有效 + if (authentication == null || !authentication.isAuthenticated() || + authentication instanceof AnonymousAuthenticationToken) { + // 返回默认值或抛出自定义异常 + Map defaultMap = new HashMap<>(); + defaultMap.put("nickname", "Anonymous"); + defaultMap.put("username", "anonymous"); + return defaultMap; + } + + // 确保是 UsernamePasswordAuthenticationToken 类型 + if (!(authentication instanceof UsernamePasswordAuthenticationToken)) { + Map defaultMap = new HashMap<>(); + defaultMap.put("nickname", "Unknown"); + defaultMap.put("username", "unknown"); + return defaultMap; + } + + UsernamePasswordAuthenticationToken usernameAuth = (UsernamePasswordAuthenticationToken) authentication; + LoginUser loginuser = (LoginUser) usernameAuth.getPrincipal(); String nickname = loginuser.getUser().getNickname(); String username = loginuser.getUser().getUsername(); Map map = new HashMap<>(); @@ -87,6 +116,7 @@ public class UserServiceImpl extends ServiceImpl impleme return map; } + @Override public SysUser getUserInfo() { UsernamePasswordAuthenticationToken authentication = diff --git a/java/src/main/resources/application-dev.yml b/java/src/main/resources/application-dev.yml index 9d46199..aa27695 100644 --- a/java/src/main/resources/application-dev.yml +++ b/java/src/main/resources/application-dev.yml @@ -20,6 +20,18 @@ spring: url: jdbc:mysql://43.138.168.68:3306/filemanagedb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true username: root password: ylfw20230626@ +# url: jdbc:mysql://127.0.0.1:3307/filemanagedb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true +# username: root +# password: 123456 + initial-size: 5 + min-idle: 5 + max-active: 20 + test-while-idle: true + test-on-borrow: false + test-on-return: false + validation-query: SELECT 1 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 mvc: pathmatch: matching-strategy: ant_path_matcher diff --git a/java/src/main/resources/application-prod.yml b/java/src/main/resources/application-prod.yml index 5b8a701..f5fca98 100644 --- a/java/src/main/resources/application-prod.yml +++ b/java/src/main/resources/application-prod.yml @@ -1,41 +1,50 @@ server: - port: 8087 + port: 8080 tomcat: connection-timeout: 300000 +#密码加密传输,前端公钥加密,后端私钥解密 +rsa: + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== spring: - #应用名称 - application: - name: Project-plateform - datasource: - type: com.alibaba.druid.pool.DruidDataSource - druid: - master: - driverClassName: com.mysql.cj.jdbc.Driver -# url: jdbc:mysql://120.27.210.161:3306/testdb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true -# username: testdb -# password: 27CTfsyJmZRESmsa - url: jdbc:mysql://121.37.111.42:33306/filemanagedb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true - username: filemanagedb - password: GAPchydbCKYFjjAa - mvc: - pathmatch: - matching-strategy: ant_path_matcher - servlet: - multipart: - max-file-size: 30MB - max-request-size: 100MB + #应用名称 + application: + name: Project-plateform + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + master: + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://db-container:3306/filemanagedb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + username: root + password: pwd@FileMgr + mvc: + pathmatch: + matching-strategy: ant_path_matcher + servlet: + multipart: + max-file-size: 50GB + max-request-size: 50GB + tomcat: + max-swallow-size: -1 + connection-timeout: 86400000 + max-http-form-post-size: -1 + redis: + host: localhost + port: 6379 + password: MySecurePass123 + database: 0 logging: - file: - path: /opt/filemgr/logs - name: logs/projectname.log - level: - com.genersoft.iot: debug - com.genersoft.iot.vmp.storager.dao: info - com.genersoft.iot.vmp.gb28181: info + file: + path: /opt/filemgr/logs/ + name: logs/projectname.log + level: + com.genersoft.iot: info + com.genersoft.iot.vmp.storager.dao: info + com.genersoft.iot.vmp.gb28181: info # 在线文档: swagger-ui(生产环境建议关闭) swagger-ui: - enabled: true + enabled: false mybatis-plus: configuration: @@ -69,7 +78,7 @@ ip: file-space: #项目文档空间 - system: D:\file\system\ #单独上传的文件 + system: /data/local-data/ #单独上传的文件 file-system: preview: diff --git a/java/src/main/resources/mapper/experimentalData/TsTaskMapper.xml b/java/src/main/resources/mapper/experimentalData/TsTaskMapper.xml index 3ed6411..e91c08d 100644 --- a/java/src/main/resources/mapper/experimentalData/TsTaskMapper.xml +++ b/java/src/main/resources/mapper/experimentalData/TsTaskMapper.xml @@ -1,5 +1,9 @@ - +