zqy
2 天以前 28cf0afe5cb951bf34a60a1ee0f36d38c592a8c0
新增搜索 不选模块进行全局搜索 获取每个模块
6个文件已修改
2个文件已添加
278 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/zhang/EsSearchController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/config/AsyncConfig.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhang-content/src/main/java/com/ruoyi/domain/ModuleSearchResult.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhang-content/src/main/java/com/ruoyi/domain/ZfDoctor.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhang-content/src/main/java/com/ruoyi/service/impl/InterfaceBasedSearchRouter.java 151 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhang-content/src/main/java/com/ruoyi/service/impl/ZfDoctorServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhang-content/src/main/java/com/ruoyi/service/impl/ZfEconomyServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | 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);
    }