| ruoyi-admin/src/main/java/com/ruoyi/web/controller/zhang/EsSearchController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ruoyi-common/src/main/java/com/ruoyi/common/config/AsyncConfig.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ruoyi-framework/pom.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| zhang-content/src/main/java/com/ruoyi/domain/ModuleSearchResult.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| zhang-content/src/main/java/com/ruoyi/domain/ZfDoctor.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| zhang-content/src/main/java/com/ruoyi/service/impl/InterfaceBasedSearchRouter.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| zhang-content/src/main/java/com/ruoyi/service/impl/ZfDoctorServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| zhang-content/src/main/java/com/ruoyi/service/impl/ZfEconomyServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
ruoyi-admin/src/main/java/com/ruoyi/web/controller/zhang/EsSearchController.java
@@ -6,6 +6,8 @@ import com.ruoyi.service.ZfEconomyService; import com.ruoyi.service.impl.InterfaceBasedSearchRouter; import com.ruoyi.service.impl.ZfEconomyServiceImpl; import com.ruoyi.system.service.ISysMenuService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; @@ -63,9 +65,25 @@ System.out.println("[[[[[["+happenStartTime); System.out.println("[[[[[["+happenEndTime); zfEconomyService.clearAllCache(); return interfaceBasedSearchRouter.routeSearch(moduleCode,companion,happenStartTime,happenEndTime); } /** * 新增全模块搜索接口(不指定moduleCode) */ @GetMapping("/companion") public AjaxResult getAllModulesByCompanion(@RequestParam(value = "companion", required = false) String companion, @RequestParam(value = "happenStartTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date happenStartTime, @RequestParam(value = "happenEndTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date happenEndTime) { System.out.println("全模块搜索 - 同伴: " + companion); System.out.println("全模块搜索 - 开始时间: " + happenStartTime); System.out.println("全模块搜索 - 结束时间: " + happenEndTime); zfEconomyService.clearAllCache(); // 使用null或空字符串表示全模块搜索 return interfaceBasedSearchRouter.routeSearch(null, companion, happenStartTime, happenEndTime); } } ruoyi-common/src/main/java/com/ruoyi/common/config/AsyncConfig.java
New file @@ -0,0 +1,23 @@ package com.ruoyi.common.config; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor; import org.springframework.core.task.SimpleAsyncTaskExecutor; import java.util.concurrent.Executor; @Configuration @EnableAsync // 启用异步支持 public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { // 1. 创建一个基础的异步任务执行器 SimpleAsyncTaskExecutor delegate = new SimpleAsyncTaskExecutor(); // 2. 使用DelegatingSecurityContextAsyncTaskExecutor进行包装 // 它会自动将主线程的安全上下文绑定到异步任务的线程上 return new DelegatingSecurityContextAsyncTaskExecutor(delegate); } } ruoyi-framework/pom.xml
@@ -76,4 +76,4 @@ </plugins> </build> </project> </project> zhang-content/src/main/java/com/ruoyi/domain/ModuleSearchResult.java
New file @@ -0,0 +1,39 @@ package com.ruoyi.domain; import java.util.List; public class ModuleSearchResult { private final String moduleCode; private final List<?> data; private final int count; private final long searchTime; private final boolean success; private final String errorMessage; private ModuleSearchResult(String moduleCode, String moduleName, List<?> data, int count, long searchTime, boolean success, String errorMessage) { this.moduleCode = moduleCode; this.data = data; this.count = count; this.searchTime = searchTime; this.success = success; this.errorMessage = errorMessage; } public static ModuleSearchResult success(String moduleCode, String moduleName, List<?> data, int count, long searchTime) { return new ModuleSearchResult(moduleCode, moduleName, data, count, searchTime, true, null); } public static ModuleSearchResult error(String moduleCode, String errorMessage) { return new ModuleSearchResult(moduleCode, null, null, 0, 0, false, errorMessage); } // getters... public String getModuleCode() { return moduleCode; } public List<?> getData() { return data; } public int getCount() { return count; } public long getSearchTime() { return searchTime; } public boolean isSuccess() { return success; } public String getErrorMessage() { return errorMessage; } } zhang-content/src/main/java/com/ruoyi/domain/ZfDoctor.java
@@ -14,7 +14,7 @@ /** * <p> * * * </p> * * @author ojq @@ -97,4 +97,22 @@ private Integer ownData; private Long shareId; /** * 参与者 */ private String companion; /** * 开始时间 */ @TableField(exist = false) private Date happenStartTime; /** * 结束时间 */ @TableField(exist = false) private Date happenEndTime; } zhang-content/src/main/java/com/ruoyi/service/impl/InterfaceBasedSearchRouter.java
@@ -2,16 +2,19 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.domain.ModuleSearchResult; import com.ruoyi.service.ModuleSearchable; import lombok.extern.slf4j.Slf4j; import org.apache.commons.logging.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; import javax.annotation.Resource; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Function; import java.util.stream.Collectors; @@ -20,6 +23,7 @@ public class InterfaceBasedSearchRouter { private final Map<String, ModuleSearchable> moduleSearchMap; /** * 自动收集所有实现ModuleSearchable接口的Bean @@ -39,6 +43,21 @@ log.info("已注册搜索模块: {}", moduleSearchMap.keySet()); } @Async // 声明此方法异步执行,将使用我们上面配置的Executor public CompletableFuture<ModuleSearchResult> searchModuleAsync(String moduleCode, ModuleSearchable service, String companion, Date startTime, Date endTime) { // 将原来在lambda表达式中的搜索逻辑移到这里 long start = System.currentTimeMillis(); try { List<?> data = service.search(companion, startTime, endTime); long searchTime = System.currentTimeMillis() - start; ModuleSearchResult result = ModuleSearchResult.success(moduleCode, service.getModuleName(), data, data.size(), searchTime); return CompletableFuture.completedFuture(result); } catch (Exception e) { log.error("模块[{}]搜索失败: {}", moduleCode, e.getMessage()); ModuleSearchResult result = ModuleSearchResult.error(moduleCode, e.getMessage()); return CompletableFuture.completedFuture(result); } } /** * 通用的路由搜索请求(支持不同参数类型) */ @@ -48,6 +67,12 @@ public AjaxResult routeSearch(String moduleCode, Object... args) { log.info("路由搜索: moduleCode={}, args={}", moduleCode, Arrays.toString(args)); // 全模块搜索:当moduleCode为空或特定标识时 if (moduleCode == null || moduleCode.isEmpty() || "all".equalsIgnoreCase(moduleCode)) { return searchAllModules(args); } // 单个模块搜索(原有逻辑) ModuleSearchable searchService = moduleSearchMap.get(moduleCode); if (searchService == null) { String availableModules = String.join(", ", moduleSearchMap.keySet()); @@ -55,7 +80,6 @@ } try { // 根据参数数量进行路由 if (args.length == 3) { return handleFourArgs(searchService, args); } else { @@ -67,9 +91,6 @@ } } /** * 处理3个参数的情况(companion + happenStartTime + happenEndTime) */ private AjaxResult handleFourArgs(ModuleSearchable searchService, Object[] args) { String companion = null; Date happenStartTime = null; @@ -108,6 +129,98 @@ return AjaxResult.success("搜索成功", result); } /** * 全模块搜索:获取所有模块的数据并分类 */ private AjaxResult searchAllModules(Object[] args) { log.info("执行全模块搜索,参数数量: {}", args.length); try { Map<String, Object> result = new LinkedHashMap<>(); int totalCount = 0; int successCount = 0; // 处理搜索参数 String companion = extractCompanion(args); Date happenStartTime = extractStartTime(args); Date happenEndTime = extractEndTime(args); System.out.println("全模块搜索 ------ 同伴: " + companion); System.out.println("全模块搜索 ------ 开始时间: " + happenStartTime); System.out.println("全模块搜索 ------ 结束时间: " + happenEndTime); // 并行处理所有模块搜索(提高性能) List<CompletableFuture<ModuleSearchResult>> futures = moduleSearchMap.entrySet().stream().map(entry -> searchModuleAsync(entry.getKey(), entry.getValue(), companion, happenStartTime, happenEndTime)) .collect(Collectors.toList()); // 等待所有搜索完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 收集结果 for (CompletableFuture<ModuleSearchResult> future : futures) { ModuleSearchResult moduleResult = future.get(); if (moduleResult.isSuccess()) { // 创建一个可变的HashMap并填入数据 Map<String, Object> resultMap = new HashMap<>(); resultMap.put("data", moduleResult.getData()); resultMap.put("count", moduleResult.getCount()); resultMap.put("searchTime", moduleResult.getSearchTime()); // 将构建好的Map放入最终结果中 result.put(moduleResult.getModuleCode(), resultMap); successCount++; totalCount += moduleResult.getCount(); } else { Map<String, Object> errorInfo = new HashMap<>(); errorInfo.put("error", moduleResult.getErrorMessage()); errorInfo.put("success", false); result.put(moduleResult.getModuleCode(), errorInfo); } } // 构建返回结果 Map<String, Object> finalResult = new LinkedHashMap<>(); finalResult.put("totalModules", moduleSearchMap.size()); finalResult.put("successModules", successCount); finalResult.put("totalRecords", totalCount); finalResult.put("searchTime", new Date()); finalResult.put("modules", result); log.info("全模块搜索完成: 成功{}/{}个模块,总计{}条记录", successCount, moduleSearchMap.size(), totalCount); return AjaxResult.success("全模块搜索成功", finalResult); } catch (Exception e) { log.error("全模块搜索执行失败", e); return AjaxResult.error("全模块搜索失败: " + e.getMessage()); } } /** * 单个模块搜索包装方法 */ private ModuleSearchResult searchSingleModule(String moduleCode, ModuleSearchable service, String companion, Date startTime, Date endTime) { long start = System.currentTimeMillis(); try { List<?> data = service.search(companion, startTime, endTime); long searchTime = System.currentTimeMillis() - start; return ModuleSearchResult.success(moduleCode, service.getModuleName(), data, data.size(), searchTime); } catch (Exception e) { log.error("模块[{}]搜索失败: {}", moduleCode, e.getMessage()); return ModuleSearchResult.error(moduleCode, e.getMessage()); } } // // /** // * 获取所有可搜索的模块信息 @@ -122,16 +235,22 @@ // } /** * 检查模块是否支持搜索 * 参数提取辅助方法 */ public boolean supports(String moduleCode) { return moduleSearchMap.containsKey(moduleCode); private String extractCompanion(Object[] args) { if (args.length > 0 && args[0] instanceof String) { return (String) args[0]; } else if (args.length > 0 && args[0] != null) { return args[0].toString(); } return null; } /** * 获取模块服务实例 */ public ModuleSearchable getModuleService(String moduleCode) { return moduleSearchMap.get(moduleCode); private Date extractStartTime(Object[] args) { return (args.length > 1 && args[1] instanceof Date) ? (Date) args[1] : null; } private Date extractEndTime(Object[] args) { return (args.length > 2 && args[2] instanceof Date) ? (Date) args[2] : null; } } zhang-content/src/main/java/com/ruoyi/service/impl/ZfDoctorServiceImpl.java
@@ -39,7 +39,7 @@ */ @Service @Slf4j public class ZfDoctorServiceImpl extends ServiceImpl<ZfDoctorMapper, ZfDoctor> implements ZfDoctorService { public class ZfDoctorServiceImpl extends ServiceImpl<ZfDoctorMapper, ZfDoctor> implements ZfDoctorService,ModuleSearchable { @Resource ZInfoUserService zInfoUserService; @@ -465,6 +465,9 @@ .like(StringUtils.isNotEmpty(zfDoctor.getWmedical()), ZfDoctor::getWmedical, zfDoctor.getWmedical()) .like(StringUtils.isNotEmpty(zfDoctor.getCmedical()), ZfDoctor::getCmedical, zfDoctor.getCmedical()) .like(StringUtils.isNotEmpty(zfDoctor.getRemark()), ZfDoctor::getRemark, zfDoctor.getRemark()); lqw.like(StringUtils.isNotEmpty(zfDoctor.getCompanion()),ZfDoctor::getCompanion,zfDoctor.getCompanion()); lqw.between(zfDoctor.getHappenStartTime() != null && zfDoctor.getHappenEndTime() != null, ZfDoctor::getCreateTime, zfDoctor.getHappenStartTime(), zfDoctor.getHappenEndTime()); if (StringUtils.isNotEmpty(zfDoctor.getPrescription())) { lqw.and(wrapper -> { wrapper.like(StringUtils.isNotEmpty(zfDoctor.getPrescription()), ZfDoctor::getWmedical, zfDoctor.getPrescription()) @@ -473,6 +476,21 @@ }); } return lqw; } @Override public String getModuleCode() { return "2043"; } @Override public List<?> search(String companion, Date happenStartTime, Date happenEndTime) { ZfDoctor zfDoctor = new ZfDoctor(); zfDoctor.setCompanion(companion); zfDoctor.setHappenStartTime(happenStartTime); zfDoctor.setHappenEndTime(happenEndTime); return selectByCondition(zfDoctor); } // public LambdaQueryWrapper<ZfDoctor> buildCondition2(List<Long> ids) { @@ -516,4 +534,4 @@ // } } } zhang-content/src/main/java/com/ruoyi/service/impl/ZfEconomyServiceImpl.java
@@ -627,7 +627,6 @@ zfEconomy.setCompanion(companion); zfEconomy.setHappenStartTime(happenStartTime); zfEconomy.setHappenEndTime(happenEndTime); System.out.println("ssssss"+zfEconomy); return selectByCondition(zfEconomy); }