package com.ruoyi.service.impl; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.domain.ModuleSearchResult; import com.ruoyi.domain.PeopleSea; import com.ruoyi.service.ModuleSearchable; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.function.Function; import java.util.stream.Collectors; @Service @Slf4j public class InterfaceBasedSearchRouter { private final Map moduleSearchMap; // 模块分割符 private static final String MODULE_SEPARATOR = ","; // 全模块标识 private static final String ALL_MODULES_FLAG = "all"; /** * 自动收集所有实现ModuleSearchable接口的Bean */ @Autowired public InterfaceBasedSearchRouter(List searchServices) { this.moduleSearchMap = searchServices.stream() .collect(Collectors.toMap( ModuleSearchable::getModuleCode, Function.identity(), (existing, replacement) -> { log.warn("发现重复的模块编码: {}, 使用先注册的服务", existing.getModuleCode()); return existing; } )); log.info("已注册搜索模块: {}", moduleSearchMap.keySet()); } @Async public CompletableFuture searchModuleAsync(String moduleCode, ModuleSearchable service, String companion, Date startTime, Date endTime, String hasAttachment, Integer pageNum, Integer pageSize) { long start = System.currentTimeMillis(); try { // 调用搜索方法,返回 List List data = service.search(companion, startTime, endTime, hasAttachment); long searchTime = System.currentTimeMillis() - start; int count = 0; if (data != null) { count = data.size(); } // 获取模块名称 String moduleName = getModuleName(moduleCode); ModuleSearchResult result = ModuleSearchResult.success( moduleCode, moduleName, data, count, searchTime ); return CompletableFuture.completedFuture(result); } catch (Exception e) { log.error("模块[{}]搜索失败: {}", moduleCode, e.getMessage(), e); String errorMessage = e.getMessage(); if (e.getCause() != null) { errorMessage += " (" + e.getCause().getMessage() + ")"; } ModuleSearchResult result = ModuleSearchResult.error(moduleCode, errorMessage); return CompletableFuture.completedFuture(result); } } /** * 通用的路由搜索请求 */ public AjaxResult routeSearch(PeopleSea peopleS, Integer pageNum, Integer pageSize) { String moduleCode = null; // 安全处理 String[] 类型的 modules if (peopleS != null && peopleS.getModules() != null && peopleS.getModules().length != 0) { String[] modulesArray = peopleS.getModules(); // 过滤掉空字符串和空白字符 List validModules = Arrays.stream(modulesArray) .filter(StringUtils::isNotBlank) .map(String::trim) .collect(Collectors.toList()); if (!validModules.isEmpty()) { // 用逗号连接有效的模块代码 moduleCode = String.join(",", validModules); } } log.info("路由搜索: moduleCode={}, peopleS={}, pageNum={}, pageSize={}", moduleCode, peopleS, pageNum, pageSize); // 解析模块代码 List targetModules = parseModuleCodes(moduleCode); if (targetModules.isEmpty()) { // 不选模块的情况 return handleNoModuleSelected(); } // 统一处理:单个模块、多个模块都使用同样的处理逻辑 return executeModulesSearch(targetModules, peopleS, pageNum, pageSize); } /** * 统一执行模块搜索 */ private AjaxResult executeModulesSearch(List moduleCodes, PeopleSea peopleS, Integer pageNum, Integer pageSize) { log.info("执行模块搜索: moduleCodes={}, 模块数量={}", moduleCodes, moduleCodes.size()); // 验证所有模块是否存在 List invalidModules = moduleCodes.stream() .filter(code -> !moduleSearchMap.containsKey(code)) .collect(Collectors.toList()); if (!invalidModules.isEmpty()) { String availableModules = String.join(", ", moduleSearchMap.keySet()); String errorMsg = String.format("以下模块不支持: %s。可用模块: [%s]", invalidModules, availableModules); return AjaxResult.error(errorMsg); } // 提取参数 String companion = extractCompanion(peopleS); Date startTime = extractStartTime(peopleS); Date endTime = extractEndTime(peopleS); String hasAttachment = extractHasAttachment(peopleS); // 设置分页默认值 if (pageNum == null || pageNum <= 0) { pageNum = 1; } if (pageSize == null || pageSize <= 0) { pageSize = 10; } // 并发搜索 Integer finalPageNum = pageNum; Integer finalPageSize = pageSize; List> futures = moduleCodes.stream() .map(code -> searchModuleAsync(code, moduleSearchMap.get(code), companion, startTime, endTime, hasAttachment, finalPageNum, finalPageSize)) .collect(Collectors.toList()); // 等待完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 合并数据 List allData = new ArrayList<>(); for (CompletableFuture future : futures) { try { ModuleSearchResult result = future.get(); if (result.isSuccess() && result.getData() != null) { allData.addAll(result.getData()); } } catch (Exception e) { // 记录错误但继续处理其他模块 log.error("获取模块搜索结果失败", e); } } // 对数据进行排序(如果需要) sortData(allData); // 分页 int startIndex = (pageNum - 1) * pageSize; List paginatedData = allData.stream() .skip(startIndex) .limit(pageSize) .collect(Collectors.toList()); // 返回结果 Map data = new HashMap<>(); data.put("list", paginatedData); data.put("total", allData.size()); data.put("pageNum", pageNum); data.put("pageSize", pageSize); return AjaxResult.success(data); } /** * 对数据进行排序 * 默认按创建时间降序排列 */ private void sortData(List allData) { if (CollectionUtils.isEmpty(allData)) { return; } // 如果数据是 Map 类型,尝试按 createTime 排序 if (allData.get(0) instanceof Map) { allData.sort((a, b) -> { Map mapA = (Map) a; Map mapB = (Map) b; Object timeA = mapA.get("createTime"); Object timeB = mapB.get("createTime"); if (timeA instanceof Date && timeB instanceof Date) { // 降序排列:最新的在前 return ((Date) timeB).compareTo((Date) timeA); } else if (timeA instanceof String && timeB instanceof String) { // 如果时间是字符串,尝试解析 try { Date dateA = parseDate((String) timeA); Date dateB = parseDate((String) timeB); if (dateA != null && dateB != null) { return dateB.compareTo(dateA); } } catch (Exception e) { // 解析失败,不排序 } } return 0; }); } } /** * 解析日期字符串 */ private Date parseDate(String dateStr) { if (dateStr == null || dateStr.isEmpty()) { return null; } try { // 尝试常见的日期格式 String[] formats = { "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd" }; for (String format : formats) { try { return new java.text.SimpleDateFormat(format).parse(dateStr); } catch (Exception e) { // 继续尝试下一个格式 } } } catch (Exception e) { log.warn("无法解析日期字符串: {}", dateStr, e); } return null; } /** * 获取模块名称 */ private String getModuleName(String moduleCode) { ModuleSearchable service = moduleSearchMap.get(moduleCode); return service != null ? service.getModuleName() : "未知模块"; } /** * 安全的参数提取方法 */ private String extractCompanion(PeopleSea peopleS) { if (peopleS == null) { return ""; } return peopleS.getPeoples() == null ? "" : peopleS.getPeoples().trim(); } private Date extractStartTime(PeopleSea peopleS) { if (peopleS == null) { return null; } return peopleS.getStartTime(); } private Date extractEndTime(PeopleSea peopleS) { if (peopleS == null) { return null; } return peopleS.getEndTime(); } private String extractHasAttachment(PeopleSea peopleS) { if (peopleS == null) { return ""; } return peopleS.getHasAttachment() == null ? "" : peopleS.getHasAttachment().trim(); } /** * 解析模块代码 */ private List parseModuleCodes(String moduleCode) { if (StringUtils.isBlank(moduleCode)) { // 空/空白/null -> 全模块搜索 return new ArrayList<>(moduleSearchMap.keySet()); } String trimmedCode = moduleCode.trim(); // 处理全模块标识 if (ALL_MODULES_FLAG.equalsIgnoreCase(trimmedCode)) { return new ArrayList<>(moduleSearchMap.keySet()); } // 处理不选模块的情况 if ("none".equalsIgnoreCase(trimmedCode) || "null".equalsIgnoreCase(trimmedCode)) { return Collections.emptyList(); } // 检查是否包含逗号(多个模块) if (trimmedCode.contains(MODULE_SEPARATOR)) { String[] moduleArray = trimmedCode.split(MODULE_SEPARATOR); return Arrays.stream(moduleArray) .map(String::trim) .filter(code -> !code.isEmpty()) .collect(Collectors.toList()); } // 单个模块 return Collections.singletonList(trimmedCode); } /** * 不选模块的处理逻辑 */ private AjaxResult handleNoModuleSelected() { Map result = new LinkedHashMap<>(); result.put("list", Collections.emptyList()); result.put("total", 0); result.put("pageNum", 1); result.put("pageSize", 10); return AjaxResult.success("未选择搜索模块,请选择要搜索的模块", result); } /** * 获取可用模块列表 */ public AjaxResult getAvailableModules() { Map result = new HashMap<>(); List> modules = moduleSearchMap.values().stream() .map(service -> { Map moduleInfo = new HashMap<>(); moduleInfo.put("moduleCode", service.getModuleCode()); moduleInfo.put("moduleName", service.getModuleName()); return moduleInfo; }) .collect(Collectors.toList()); result.put("modules", modules); result.put("total", modules.size()); return AjaxResult.success("获取可用模块成功", result); } /** * 验证模块代码是否存在 */ public boolean validateModule(String moduleCode) { if (StringUtils.isBlank(moduleCode)) { return false; } // 处理多个模块的情况 if (moduleCode.contains(MODULE_SEPARATOR)) { String[] moduleArray = moduleCode.split(MODULE_SEPARATOR); for (String code : moduleArray) { String trimmedCode = code.trim(); if (!moduleSearchMap.containsKey(trimmedCode) && !ALL_MODULES_FLAG.equalsIgnoreCase(trimmedCode)) { return false; } } return true; } // 单个模块的情况 String trimmedCode = moduleCode.trim(); return moduleSearchMap.containsKey(trimmedCode) || ALL_MODULES_FLAG.equalsIgnoreCase(trimmedCode); } }