From f9064be39b7190dcd154052cb1acc61d34e7f12b Mon Sep 17 00:00:00 2001 From: wxlong Date: Tue, 25 Nov 2025 18:08:41 +0800 Subject: [PATCH] =?UTF-8?q?20251125GET=E6=8C=87=E5=AE=9A=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=9A=84=E6=89=80=E6=9C=89Media?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PhotoMediaExportController.java | 878 ++++++++++++++++++ .../controller/TaskManagementController.java | 29 + 2 files changed, 907 insertions(+) create mode 100644 src/main/java/cn/edu/whu/boot/lydcextend/controller/PhotoMediaExportController.java diff --git a/src/main/java/cn/edu/whu/boot/lydcextend/controller/PhotoMediaExportController.java b/src/main/java/cn/edu/whu/boot/lydcextend/controller/PhotoMediaExportController.java new file mode 100644 index 0000000..dc72a9f --- /dev/null +++ b/src/main/java/cn/edu/whu/boot/lydcextend/controller/PhotoMediaExportController.java @@ -0,0 +1,878 @@ +package cn.edu.whu.boot.lydcextend.controller; + +import cn.edu.whu.boot.collection.service.IBaseService; +import cn.edu.whu.boot.common.domain.CommonConstant; +import cn.edu.whu.boot.common.domain.ResultMessage; +import cn.edu.whu.boot.common.domain.SqlStringConstant; +import cn.edu.whu.boot.common.utils.collection.OtherUtil; +import cn.edu.whu.boot.common.utils.collection.PostgreSqlUtil; +import cn.edu.whu.boot.common.utils.collection.TableOperationUtil; +import cn.edu.whu.boot.xml.domain.Task; +import cn.edu.whu.boot.xml.service.ITaskService; +import cn.edu.whu.boot.xml.xmlreader.bean.Config; +import cn.edu.whu.boot.xml.xmlreader.bean.Field; +import cn.edu.whu.boot.xml.xmlreader.bean.Table; +import com.alibaba.fastjson.JSON; +import org.apache.commons.io.FileUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.*; + +/** + * 照片和媒体路径导出控制器 + * 根据 taskId 遍历任务的所有表: + * 1. 对于以 _media 为后缀的表,提取表名、id、media_id、media_path 以及位置和相机相关字段 + * 2. 对于其他表,如果包含 photo 和 parentID 字段,则提取表名、ID、parentID 和 photo 字段 + */ +@RestController +@RequestMapping("lydcextend") +public class PhotoMediaExportController { + private static final Logger logger = LoggerFactory.getLogger(PhotoMediaExportController.class); + + private final ITaskService taskService; + private final IBaseService baseService; + + @Autowired + public PhotoMediaExportController(ITaskService taskService, IBaseService baseService) { + this.taskService = taskService; + this.baseService = baseService; + } + + /** + * 获取照片和媒体路径数据 + * 根据 taskId 遍历任务的所有表: + * 1. 对于以 _media 为后缀的表,提取表名、id、media_id、media_path 以及位置和相机相关字段 + * 2. 对于其他表,如果包含 photo 和 parentID 字段,则提取表名、ID、parentID 和 photo 字段 + * + * @param taskId 任务ID + * @return 照片和媒体数据列表(包含 relationsource 字段) + */ + @RequestMapping(value = "getPhotoMedia", produces = "text/html;charset=UTF-8") + public String getPhotoMedia(@RequestParam Integer taskId) { + try { + // 获取任务 + Task task = taskService.getTaskById(taskId); + if (task == null) { + return ResultMessage.failed("任务不存在").toString(); + } + + // 收集所有需要返回的数据 + List> dataList = new ArrayList<>(); + String schemaName = task.getDatabaseName(); + + // 缓存任务名、用户名和姓名,避免重复查询 + Map taskNameCache = new HashMap<>(); + Map userNameCache = new HashMap<>(); + Map realNameCache = new HashMap<>(); + + // 从数据库直接查询 schema 中的所有表 + String getAllTablesSql = "SELECT table_name FROM information_schema.tables " + + "WHERE table_schema = '" + schemaName + "' AND table_type = 'BASE TABLE' " + + "ORDER BY table_name"; + List> allTablesResult = baseService.selectData(getAllTablesSql); + + if (allTablesResult == null || allTablesResult.isEmpty()) { + return ResultMessage.failed("schema 中没有找到表").toString(); + } + + // 解析配置获取表配置(用于字段检查) + Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class); + Map tableMap = config.getTables() != null ? config.getTables() : new HashMap<>(); + String configString = task.getConfig(); + + // 遍历数据库中的所有表 + for (Map tableRow : allTablesResult) { + String tableName = (String) tableRow.get("table_name"); + if (tableName == null) { + continue; + } + + // 从配置中获取表信息(如果存在) + Table table = tableMap.get(tableName); + + // 如果表名以 _media 为后缀,获取相关字段 + if (tableName.endsWith("_media")) { + // 查询表数据 + String tableNameInDb = PostgreSqlUtil.buildTableNameString(schemaName, tableName, false, false); + String selectSql = MessageFormat.format(SqlStringConstant.SELECT_ALLDATA_SQL, tableNameInDb); + List> tableDataList = baseService.selectData(selectSql); + + if (tableDataList != null && !tableDataList.isEmpty()) { + // 处理每条数据 + for (Map rowData : tableDataList) { + Map dataRow = new HashMap<>(); + dataRow.put("schema名称", schemaName); + dataRow.put("表名", tableName); + + // id(父表ID) + Object idValue = rowData.get("id"); + dataRow.put("ID", idValue != null ? idValue.toString() : ""); + + // media_id + Object mediaIdValue = rowData.get("media_id"); + dataRow.put("media_id", mediaIdValue != null ? mediaIdValue.toString() : ""); + + // media_path + Object mediaPathValue = rowData.get("media_path"); + dataRow.put("media_path", mediaPathValue != null ? mediaPathValue.toString() : ""); + + // longitude(经度) + Object longitudeValue = rowData.get("longitude"); + dataRow.put("longitude", longitudeValue != null ? longitudeValue.toString() : ""); + + // latitude(纬度) + Object latitudeValue = rowData.get("latitude"); + dataRow.put("latitude", latitudeValue != null ? latitudeValue.toString() : ""); + + // altitude(高程) + Object altitudeValue = rowData.get("altitude"); + dataRow.put("altitude", altitudeValue != null ? altitudeValue.toString() : ""); + + // accuracy + Object accuracyValue = rowData.get("accuracy"); + dataRow.put("accuracy", accuracyValue != null ? accuracyValue.toString() : ""); + + // camera_angle + Object cameraAngleValue = rowData.get("camera_angle"); + dataRow.put("camera_angle", cameraAngleValue != null ? cameraAngleValue.toString() : ""); + + // camera_pitch + Object cameraPitchValue = rowData.get("camera_pitch"); + dataRow.put("camera_pitch", cameraPitchValue != null ? cameraPitchValue.toString() : ""); + + // camera_roll + Object cameraRollValue = rowData.get("camera_roll"); + dataRow.put("camera_roll", cameraRollValue != null ? cameraRollValue.toString() : ""); + + // 非 _media 表的字段设为空 + dataRow.put("parentID", ""); + dataRow.put("photo", ""); + + // 解析任务名、账号和姓名 + String mediaPathStr = mediaPathValue != null ? mediaPathValue.toString() : ""; + parseAndSetTaskAndUser(dataRow, mediaPathStr, taskNameCache, userNameCache, realNameCache); + + // 构建 relationsource(对于 _media 表,id 是父表ID) + Object parentIdForMedia = idValue; + String relationsource = buildRelationSource(schemaName, tableName, parentIdForMedia, + tableMap, configString, baseService); + dataRow.put("relationsource", relationsource); + + dataList.add(dataRow); + } + } + } else { + // 其他表:检查表是否有 photo 和 parentID 字段 + // 先从数据库查询表的列信息 + List tableColumns = baseService.getTableColumns(schemaName, tableName); + boolean hasPhoto = tableColumns != null && tableColumns.contains("photo"); + + // 从配置中获取 parentID 字段名(如果配置存在) + String parentIdFieldName = null; + if (table != null) { + parentIdFieldName = TableOperationUtil.getParentID(table); + } else { + // 如果配置中没有,尝试从数据库列中查找(通常 parentID 字段名可能不同) + if (tableColumns != null) { + for (String col : tableColumns) { + if (col.toLowerCase().contains("parent") || col.toLowerCase().contains("parentid")) { + parentIdFieldName = col; + break; + } + } + } + } + + if (hasPhoto && parentIdFieldName != null) { + // 查询表数据 + String tableNameInDb = PostgreSqlUtil.buildTableNameString(schemaName, tableName, false, false); + String selectSql = MessageFormat.format(SqlStringConstant.SELECT_ALLDATA_SQL, tableNameInDb); + List> tableDataList = baseService.selectData(selectSql); + + if (tableDataList != null && !tableDataList.isEmpty()) { + // 获取主键字段名 + String primaryKey = null; + if (table != null) { + primaryKey = TableOperationUtil.getPrimaryKey(table); + } + + // 如果配置中没有主键信息,尝试从数据库查询 + if (primaryKey == null && tableColumns != null) { + // 查询主键信息 + String getPrimaryKeySql = "SELECT a.attname " + + "FROM pg_index i " + + "JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey) " + + "WHERE i.indrelid = '\"" + schemaName + "\".\"" + tableName + "\"'::regclass " + + "AND i.indisprimary " + + "LIMIT 1"; + List> pkResult = baseService.selectData(getPrimaryKeySql); + if (pkResult != null && !pkResult.isEmpty()) { + primaryKey = (String) pkResult.get(0).get("attname"); + } + } + + if (primaryKey == null) { + logger.warn("表 {} 没有主键,跳过", tableName); + continue; + } + + // 处理每条数据 + for (Map rowData : tableDataList) { + Map dataRow = new HashMap<>(); + dataRow.put("schema名称", schemaName); + dataRow.put("表名", tableName); + + // ID(主键) + Object idValue = rowData.get(primaryKey); + dataRow.put("ID", idValue != null ? idValue.toString() : ""); + + // parentID + Object parentIdValue = rowData.get(parentIdFieldName); + dataRow.put("parentID", parentIdValue != null ? parentIdValue.toString() : ""); + + // photo + Object photoValue = rowData.get("photo"); + dataRow.put("photo", photoValue != null ? photoValue.toString() : ""); + + // 非 _media 表,相关字段设为空 + dataRow.put("media_id", ""); + dataRow.put("media_path", ""); + dataRow.put("longitude", ""); + dataRow.put("latitude", ""); + dataRow.put("altitude", ""); + dataRow.put("accuracy", ""); + dataRow.put("camera_angle", ""); + dataRow.put("camera_pitch", ""); + dataRow.put("camera_roll", ""); + + // 解析任务名、账号和姓名(从 photo 字段) + String photoStr = photoValue != null ? photoValue.toString() : ""; + parseAndSetTaskAndUser(dataRow, photoStr, taskNameCache, userNameCache, realNameCache); + + // 构建 relationsource + String relationsource = buildRelationSource(schemaName, tableName, parentIdValue, + tableMap, configString, baseService); + dataRow.put("relationsource", relationsource); + + dataList.add(dataRow); + } + } + } + } + } + + if (dataList.isEmpty()) { + return ResultMessage.failed("没有找到符合条件的数据").toString(); + } + + return ResultMessage.success(dataList).toString(); + } catch (Exception e) { + logger.error("获取照片和媒体数据失败", e); + return ResultMessage.failed("获取照片和媒体数据失败: " + e.getMessage()).toString(); + } + } + + /** + * 导出照片和媒体路径数据到 Excel + * + * @param taskId 任务ID + * @param response HTTP响应对象 + * @return 操作结果 + */ + @RequestMapping(value = "exportPhotoMedia", produces = "text/html;charset=UTF-8") + public String exportPhotoMedia(@RequestParam Integer taskId, HttpServletResponse response) throws IOException { + // 获取任务 + Task task = taskService.getTaskById(taskId); + if (task == null) { + return ResultMessage.failed("任务不存在").toString(); + } + + // 收集所有需要导出的数据 + List> exportDataList = new ArrayList<>(); + String schemaName = task.getDatabaseName(); + + // 缓存任务名、用户名和姓名,避免重复查询 + Map taskNameCache = new HashMap<>(); + Map userNameCache = new HashMap<>(); + Map realNameCache = new HashMap<>(); + + // 从数据库直接查询 schema 中的所有表 + String getAllTablesSql = "SELECT table_name FROM information_schema.tables " + + "WHERE table_schema = '" + schemaName + "' AND table_type = 'BASE TABLE' " + + "ORDER BY table_name"; + List> allTablesResult = baseService.selectData(getAllTablesSql); + + if (allTablesResult == null || allTablesResult.isEmpty()) { + return ResultMessage.failed("schema 中没有找到表").toString(); + } + + // 解析配置获取表配置(用于字段检查) + Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class); + Map tableMap = config.getTables() != null ? config.getTables() : new HashMap<>(); + String configString = task.getConfig(); + + // 遍历数据库中的所有表 + for (Map tableRow : allTablesResult) { + String tableName = (String) tableRow.get("table_name"); + if (tableName == null) { + continue; + } + + // 从配置中获取表信息(如果存在) + Table table = tableMap.get(tableName); + + // 如果表名以 _media 为后缀,获取相关字段 + if (tableName.endsWith("_media")) { + // 查询表数据 + String tableNameInDb = PostgreSqlUtil.buildTableNameString(schemaName, tableName, false, false); + String selectSql = MessageFormat.format(SqlStringConstant.SELECT_ALLDATA_SQL, tableNameInDb); + List> tableDataList = baseService.selectData(selectSql); + + if (tableDataList != null && !tableDataList.isEmpty()) { + // 处理每条数据 + for (Map rowData : tableDataList) { + Map exportRow = new HashMap<>(); + exportRow.put("schema名称", schemaName); + exportRow.put("表名", tableName); + + // id(父表ID) + Object idValue = rowData.get("id"); + exportRow.put("ID", idValue != null ? idValue.toString() : ""); + + // media_id + Object mediaIdValue = rowData.get("media_id"); + exportRow.put("media_id", mediaIdValue != null ? mediaIdValue.toString() : ""); + + // media_path + Object mediaPathValue = rowData.get("media_path"); + exportRow.put("media_path", mediaPathValue != null ? mediaPathValue.toString() : ""); + + // longitude(经度) + Object longitudeValue = rowData.get("longitude"); + exportRow.put("longitude", longitudeValue != null ? longitudeValue.toString() : ""); + + // latitude(纬度) + Object latitudeValue = rowData.get("latitude"); + exportRow.put("latitude", latitudeValue != null ? latitudeValue.toString() : ""); + + // altitude(高程) + Object altitudeValue = rowData.get("altitude"); + exportRow.put("altitude", altitudeValue != null ? altitudeValue.toString() : ""); + + // accuracy + Object accuracyValue = rowData.get("accuracy"); + exportRow.put("accuracy", accuracyValue != null ? accuracyValue.toString() : ""); + + // camera_angle + Object cameraAngleValue = rowData.get("camera_angle"); + exportRow.put("camera_angle", cameraAngleValue != null ? cameraAngleValue.toString() : ""); + + // camera_pitch + Object cameraPitchValue = rowData.get("camera_pitch"); + exportRow.put("camera_pitch", cameraPitchValue != null ? cameraPitchValue.toString() : ""); + + // camera_roll + Object cameraRollValue = rowData.get("camera_roll"); + exportRow.put("camera_roll", cameraRollValue != null ? cameraRollValue.toString() : ""); + + // 非 _media 表的字段设为空 + exportRow.put("parentID", ""); + exportRow.put("photo", ""); + + // 解析任务名、账号和姓名 + String mediaPathStr = mediaPathValue != null ? mediaPathValue.toString() : ""; + parseAndSetTaskAndUser(exportRow, mediaPathStr, taskNameCache, userNameCache, realNameCache); + + // 构建 relationsource(对于 _media 表,id 是父表ID) + Object parentIdForMedia = idValue; + String relationsource = buildRelationSource(schemaName, tableName, parentIdForMedia, + tableMap, configString, baseService); + exportRow.put("relationsource", relationsource); + + exportDataList.add(exportRow); + } + } + } else { + // 其他表:检查表是否有 photo 和 parentID 字段 + // 先从数据库查询表的列信息 + List tableColumns = baseService.getTableColumns(schemaName, tableName); + boolean hasPhoto = tableColumns != null && tableColumns.contains("photo"); + + // 从配置中获取 parentID 字段名(如果配置存在) + String parentIdFieldName = null; + if (table != null) { + parentIdFieldName = TableOperationUtil.getParentID(table); + } else { + // 如果配置中没有,尝试从数据库列中查找(通常 parentID 字段名可能不同) + // 这里可以根据实际情况调整查找逻辑 + if (tableColumns != null) { + for (String col : tableColumns) { + if (col.toLowerCase().contains("parent") || col.toLowerCase().contains("parentid")) { + parentIdFieldName = col; + break; + } + } + } + } + + if (hasPhoto && parentIdFieldName != null) { + // 查询表数据 + String tableNameInDb = PostgreSqlUtil.buildTableNameString(schemaName, tableName, false, false); + String selectSql = MessageFormat.format(SqlStringConstant.SELECT_ALLDATA_SQL, tableNameInDb); + List> tableDataList = baseService.selectData(selectSql); + + if (tableDataList != null && !tableDataList.isEmpty()) { + // 获取主键字段名 + String primaryKey = null; + if (table != null) { + primaryKey = TableOperationUtil.getPrimaryKey(table); + } + + // 如果配置中没有主键信息,尝试从数据库查询 + if (primaryKey == null && tableColumns != null) { + // 查询主键信息 + String getPrimaryKeySql = "SELECT a.attname " + + "FROM pg_index i " + + "JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey) " + + "WHERE i.indrelid = '\"" + schemaName + "\".\"" + tableName + "\"'::regclass " + + "AND i.indisprimary " + + "LIMIT 1"; + List> pkResult = baseService.selectData(getPrimaryKeySql); + if (pkResult != null && !pkResult.isEmpty()) { + primaryKey = (String) pkResult.get(0).get("attname"); + } + } + + if (primaryKey == null) { + logger.warn("表 {} 没有主键,跳过", tableName); + continue; + } + + // 处理每条数据 + for (Map rowData : tableDataList) { + Map exportRow = new HashMap<>(); + exportRow.put("schema名称", schemaName); + exportRow.put("表名", tableName); + + // ID(主键) + Object idValue = rowData.get(primaryKey); + exportRow.put("ID", idValue != null ? idValue.toString() : ""); + + // parentID + Object parentIdValue = rowData.get(parentIdFieldName); + exportRow.put("parentID", parentIdValue != null ? parentIdValue.toString() : ""); + + // photo + Object photoValue = rowData.get("photo"); + exportRow.put("photo", photoValue != null ? photoValue.toString() : ""); + + // 非 _media 表,相关字段设为空 + exportRow.put("media_id", ""); + exportRow.put("media_path", ""); + exportRow.put("longitude", ""); + exportRow.put("latitude", ""); + exportRow.put("altitude", ""); + exportRow.put("accuracy", ""); + exportRow.put("camera_angle", ""); + exportRow.put("camera_pitch", ""); + exportRow.put("camera_roll", ""); + + // 解析任务名、账号和姓名(从 photo 字段) + String photoStr = photoValue != null ? photoValue.toString() : ""; + parseAndSetTaskAndUser(exportRow, photoStr, taskNameCache, userNameCache, realNameCache); + + // 构建 relationsource + String relationsource = buildRelationSource(schemaName, tableName, parentIdValue, + tableMap, configString, baseService); + exportRow.put("relationsource", relationsource); + + exportDataList.add(exportRow); + } + } + } + } + } + + if (exportDataList.isEmpty()) { + return ResultMessage.failed("没有找到符合条件的数据").toString(); + } + + // 生成 Excel 文件 + String exportDir = CommonConstant.TEMP_FILE_PATHNAME + "/" + System.currentTimeMillis(); + File exportDirFile = new File(exportDir); + exportDirFile.mkdirs(); + + String excelFileName = task.getTaskName() + "_照片媒体导出.xlsx"; + File excelFile = new File(exportDir, excelFileName); + + try { + createExcelFile(exportDataList, excelFile); + + // 设置响应头 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.addHeader("Content-Disposition", + "attachment;fileName=" + new String(excelFileName.getBytes(StandardCharsets.UTF_8), "iso-8859-1")); + + // 将文件写入响应 + String result = OtherUtil.uploadFileByResponse(excelFile, response); + + // 清理临时文件 + FileUtils.deleteDirectory(exportDirFile); + + return CommonConstant.FAILED.equals(result) + ? ResultMessage.failed("导出失败").toString() + : ResultMessage.success(null).toString(); + + } catch (Exception e) { + logger.error("导出 Excel 文件失败", e); + FileUtils.deleteDirectory(exportDirFile); + return ResultMessage.failed("导出失败:" + e.getMessage()).toString(); + } + } + + /** + * 创建 Excel 文件 + */ + private void createExcelFile(List> dataList, File excelFile) throws IOException { + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("照片媒体数据"); + + // 创建样式 + // 表头样式:居中、加粗、有边框 + CellStyle headerStyle = workbook.createCellStyle(); + Font headerFont = workbook.createFont(); + headerFont.setBold(true); + headerStyle.setFont(headerFont); + headerStyle.setAlignment(HorizontalAlignment.CENTER); + headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); + headerStyle.setBorderTop(BorderStyle.THIN); + headerStyle.setBorderBottom(BorderStyle.THIN); + headerStyle.setBorderLeft(BorderStyle.THIN); + headerStyle.setBorderRight(BorderStyle.THIN); + headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + // 数据样式:居中、有边框 + CellStyle dataStyle = workbook.createCellStyle(); + dataStyle.setAlignment(HorizontalAlignment.CENTER); + dataStyle.setVerticalAlignment(VerticalAlignment.CENTER); + dataStyle.setBorderTop(BorderStyle.THIN); + dataStyle.setBorderBottom(BorderStyle.THIN); + dataStyle.setBorderLeft(BorderStyle.THIN); + dataStyle.setBorderRight(BorderStyle.THIN); + + // 创建表头 + Row headerRow = sheet.createRow(0); + String[] headers = {"schema名称", "表名", "ID", "parentID", "photo", "media_id", "media_path", + "longitude", "latitude", "altitude", "accuracy", "camera_angle", "camera_pitch", "camera_roll", + "任务名", "账号", "姓名", "relationsource"}; + for (int i = 0; i < headers.length; i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers[i]); + cell.setCellStyle(headerStyle); + } + + // 写入数据 + int rowNum = 1; + for (Map rowData : dataList) { + Row row = sheet.createRow(rowNum++); + + for (int i = 0; i < headers.length; i++) { + String header = headers[i]; + Object value = rowData.get(header); + Cell cell = row.createCell(i); + cell.setCellStyle(dataStyle); + + if (value == null) { + cell.setBlank(); + } else if (value instanceof Number) { + cell.setCellValue(((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + cell.setCellValue((Boolean) value); + } else { + cell.setCellValue(value.toString()); + } + } + } + + // 自动调整列宽 + for (int i = 0; i < headers.length; i++) { + sheet.autoSizeColumn(i); + // 设置最小列宽 + int columnWidth = sheet.getColumnWidth(i); + if (columnWidth < 2000) { + sheet.setColumnWidth(i, 2000); + } else if (columnWidth > 15000) { + sheet.setColumnWidth(i, 15000); + } + } + + // 写入文件 + try (FileOutputStream fos = new FileOutputStream(excelFile)) { + workbook.write(fos); + } finally { + workbook.close(); + } + } + + /** + * 从 media_path 或 photo 字段解析任务ID和用户ID,并查询数据库获取任务名、账号和姓名 + */ + private void parseAndSetTaskAndUser(Map exportRow, String pathStr, + Map taskNameCache, Map userNameCache, + Map realNameCache) { + String taskName = ""; + String userName = ""; + String realName = ""; + + if (pathStr != null && !pathStr.isEmpty()) { + // 按 / 拆分路径 + String[] parts = pathStr.split("/"); + + Integer taskId = null; + Integer userId = null; + + // 查找 task_ 和 user_ 后的ID + for (String part : parts) { + if (part.startsWith("task_")) { + try { + String taskIdStr = part.substring(5); // 去掉 "task_" 前缀 + taskId = Integer.parseInt(taskIdStr); + } catch (NumberFormatException e) { + logger.warn("无法解析任务ID: {}", part); + } + } else if (part.startsWith("user_")) { + try { + String userIdStr = part.substring(5); // 去掉 "user_" 前缀 + userId = Integer.parseInt(userIdStr); + } catch (NumberFormatException e) { + logger.warn("无法解析用户ID: {}", part); + } + } + } + + // 查询任务名 + if (taskId != null) { + if (taskNameCache.containsKey(taskId)) { + taskName = taskNameCache.get(taskId); + } else { + String queryTaskSql = "SELECT task_name FROM public.task WHERE id = " + taskId; + List> taskResult = baseService.selectData(queryTaskSql); + if (taskResult != null && !taskResult.isEmpty()) { + Object taskNameObj = taskResult.get(0).get("task_name"); + taskName = taskNameObj != null ? taskNameObj.toString() : ""; + taskNameCache.put(taskId, taskName); + } else { + taskNameCache.put(taskId, ""); + } + } + } + + // 查询用户名和姓名 + if (userId != null) { + if (userNameCache.containsKey(userId) && realNameCache.containsKey(userId)) { + userName = userNameCache.get(userId); + realName = realNameCache.get(userId); + } else { + String queryUserSql = "SELECT username, real_name FROM public.user_staff WHERE id = " + userId; + List> userResult = baseService.selectData(queryUserSql); + if (userResult != null && !userResult.isEmpty()) { + Map userRow = userResult.get(0); + Object userNameObj = userRow.get("username"); + userName = userNameObj != null ? userNameObj.toString() : ""; + userNameCache.put(userId, userName); + + Object realNameObj = userRow.get("real_name"); + realName = realNameObj != null ? realNameObj.toString() : ""; + realNameCache.put(userId, realName); + } else { + userNameCache.put(userId, ""); + realNameCache.put(userId, ""); + } + } + } + } + + exportRow.put("任务名", taskName); + exportRow.put("账号", userName); + exportRow.put("姓名", realName); + } + + /** + * 构建表层次关系JSON字符串 + * + * @param schemaName schema名称 + * @param currentTableName 当前表名 + * @param parentIdValue 父表ID值(可能为null) + * @param tableMap 表配置映射 + * @param configString 配置字符串 + * @param baseService 数据库服务 + * @return JSON格式的层次关系字符串 + */ + private String buildRelationSource(String schemaName, String currentTableName, Object parentIdValue, + Map tableMap, String configString, IBaseService baseService) { + try { + // 如果 parentID 为空,说明是根表,返回空对象 + if (parentIdValue == null || parentIdValue.toString().trim().isEmpty()) { + return "{}"; + } + + // 查找当前表的父表 + String parentTableName = findParentTableName(currentTableName, tableMap); + if (parentTableName == null) { + return "{}"; + } + + // 构建当前层的关系 + Map relationMap = new HashMap<>(); + relationMap.put("parentTableName", parentTableName); + relationMap.put("parentID", parentIdValue.toString()); + + // 递归查找父表的父表 + Table parentTable = tableMap.get(parentTableName); + if (parentTable != null) { + String parentParentIdField = TableOperationUtil.getParentID(parentTable); + if (parentParentIdField != null) { + // 查询父表记录,获取其 parentID + String parentTableNameInDb = PostgreSqlUtil.buildTableNameString(schemaName, parentTableName, false, false); + String parentPrimaryKey = TableOperationUtil.getPrimaryKey(parentTable); + if (parentPrimaryKey != null) { + // 获取主键字段的数据库类型 + String parentPrimaryKeyDbType = null; + Map parentFields = parentTable.getFields(); + if (parentFields != null) { + Field primaryKeyField = parentFields.get(parentPrimaryKey); + if (primaryKeyField != null) { + parentPrimaryKeyDbType = primaryKeyField.getDbType(); + } + } + + // 构建安全的SQL查询,根据字段类型处理 + String parentPrimaryKeyTransformed = PostgreSqlUtil.transformString(parentPrimaryKey); + String parentParentIdFieldTransformed = PostgreSqlUtil.transformString(parentParentIdField); + String parentIdValueStr = parentIdValue.toString(); + + // 根据字段类型构建WHERE子句 + String whereClause; + if (parentPrimaryKeyDbType != null && + (parentPrimaryKeyDbType.toLowerCase().equals("integer") || + parentPrimaryKeyDbType.toLowerCase().equals("long") || + parentPrimaryKeyDbType.toLowerCase().equals("bigint") || + parentPrimaryKeyDbType.toLowerCase().equals("double") || + parentPrimaryKeyDbType.toLowerCase().equals("numeric"))) { + // 数字类型,不需要引号 + whereClause = parentPrimaryKeyTransformed + " = " + parentIdValueStr; + } else { + // 字符串或其他类型,需要加引号并转义单引号 + String escapedValue = parentIdValueStr.replace("'", "''"); + whereClause = parentPrimaryKeyTransformed + " = '" + escapedValue + "'"; + } + String selectParentSql = "SELECT " + parentParentIdFieldTransformed + " FROM " + parentTableNameInDb + " WHERE " + whereClause; + List> parentResult = baseService.selectData(selectParentSql); + + if (parentResult != null && !parentResult.isEmpty()) { + Object parentParentIdValue = parentResult.get(0).get(parentParentIdField); + if (parentParentIdValue != null && !parentParentIdValue.toString().trim().isEmpty()) { + // 递归构建父表的父表关系 + String parentParentRelation = buildRelationSource(schemaName, parentTableName, + parentParentIdValue, tableMap, configString, baseService); + if (!parentParentRelation.equals("{}")) { + relationMap.put("parentParent", JSON.parseObject(parentParentRelation)); + } else { + relationMap.put("parentParent", new HashMap<>()); + } + } else { + relationMap.put("parentParent", new HashMap<>()); + } + } else { + relationMap.put("parentParent", new HashMap<>()); + } + } else { + relationMap.put("parentParent", new HashMap<>()); + } + } else { + relationMap.put("parentParent", new HashMap<>()); + } + } else { + relationMap.put("parentParent", new HashMap<>()); + } + + return JSON.toJSONString(relationMap); + } catch (Exception e) { + logger.error("构建 relationsource 失败: {}", e.getMessage(), e); + return "{}"; + } + } + + /** + * 查找指定表的父表名 + * 通过遍历所有表,找到哪些表的 associate 或 collection 字段指向当前表 + * 对于 _media 表,父表名就是去掉 _media 后缀的表名 + * + * @param childTableName 子表名 + * @param tableMap 表配置映射 + * @return 父表名,如果找不到返回 null + */ + private String findParentTableName(String childTableName, Map tableMap) { + if (childTableName == null || childTableName.trim().isEmpty()) { + return null; + } + + // 对于 _media 表,父表名就是去掉 _media 后缀的表名 + if (childTableName.endsWith("_media")) { + String parentTableName = childTableName.substring(0, childTableName.length() - 6); // 去掉 "_media" + // 验证父表是否存在于配置中 + if (tableMap != null && tableMap.containsKey(parentTableName)) { + return parentTableName; + } + } + + if (tableMap == null || tableMap.isEmpty()) { + return null; + } + + // 遍历所有表,查找哪些表的 associate 或 collection 字段指向当前表 + for (Map.Entry entry : tableMap.entrySet()) { + Table table = entry.getValue(); + if (table == null || table.getFields() == null) { + continue; + } + + // 检查该表的字段中是否有 associate 或 collection 指向当前表 + for (Map.Entry fieldEntry : table.getFields().entrySet()) { + Field field = fieldEntry.getValue(); + if (field == null) { + continue; + } + + // 检查 associate 字段 + String associate = field.getAssociate(); + if (associate != null && !associate.trim().isEmpty() && associate.equals(childTableName)) { + return entry.getKey(); + } + + // 检查 collection 字段 + String collection = field.getCollection(); + if (collection != null && !collection.trim().isEmpty() && collection.equals(childTableName)) { + return entry.getKey(); + } + } + } + + return null; + } +} + diff --git a/src/main/java/cn/edu/whu/boot/xml/controller/TaskManagementController.java b/src/main/java/cn/edu/whu/boot/xml/controller/TaskManagementController.java index d6eb0a8..298302f 100644 --- a/src/main/java/cn/edu/whu/boot/xml/controller/TaskManagementController.java +++ b/src/main/java/cn/edu/whu/boot/xml/controller/TaskManagementController.java @@ -335,6 +335,35 @@ public class TaskManagementController{ return ResultMessage.success(result).toString(); } + /** + * 网页端任务管理模块根据关键词模糊查找任务相关信息 + * 可以根据任务名称或数据库名中包含keyword的任务 + */ + @RequestMapping(value = "selectAllWithKeyword", produces = "text/html;charset=UTF-8") + public String selectAllWithKeyword(String keyword){ + List allTaskList = taskService.getAllTask(); + List filteredTaskList = new ArrayList<>(); + + // 如果keyword为空或null,返回所有任务 + if(keyword == null || keyword.trim().isEmpty()){ + String result = getTaskInfo(allTaskList); + return ResultMessage.success(result).toString(); + } + + // 模糊匹配任务名称或数据库名 + String lowerKeyword = keyword.toLowerCase().trim(); + for(Task task : allTaskList){ + String taskName = task.getTaskName() != null ? task.getTaskName().toLowerCase() : ""; + String databaseName = task.getDatabaseName() != null ? task.getDatabaseName().toLowerCase() : ""; + if(taskName.contains(lowerKeyword) || databaseName.contains(lowerKeyword)){ + filteredTaskList.add(task); + } + } + + String result = getTaskInfo(filteredTaskList); + return ResultMessage.success(result).toString(); + } + /** * 网页端决策管理模块获取任务相关信息,有任务名称、数据库名、任务下所有根表名 */