# 用户导入504超时错误修复说明 ## 问题描述 在导入用户档案数据时,出现 **504 Gateway Time-out** 错误。这是因为: 1. 数据量较大,导入处理时间超过了网关(Nginx)的超时限制 2. 同步处理导致HTTP请求长时间等待响应 ## 修复方案 采用**异步导入**方式,将耗时的导入操作放到后台线程执行,HTTP请求立即返回,通过进度轮询查看导入状态。 ## 修改内容 ### 1. Controller层修改 ✅ **文件**: `ry-xinli-admin/src/main/java/com/ddnai/web/controller/psychology/PsyUserProfileController.java` **修改内容**: - 修改 `importData` 方法,调用异步导入方法 `importProfileAsync` - 立即返回响应,告知前端导入任务已启动 - 前端通过 `/importProgress` 接口轮询获取进度 ```java @PostMapping("/importData") public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { ExcelUtil util = new ExcelUtil(PsyUserProfile.class); List profileList = util.importExcel(file.getInputStream()); String operName = getUsername(); // 异步执行导入任务,立即返回 profileService.importProfileAsync(profileList, updateSupport, operName); // 立即返回响应,告知前端导入任务已启动 return success("导入任务已启动,共 " + profileList.size() + " 条数据。请稍候查看导入进度..."); } ``` ### 2. Service接口层修改 ✅ **文件**: `ry-xinli-system/src/main/java/com/ddnai/system/service/psychology/IPsyUserProfileService.java` **修改内容**: - 添加异步导入方法接口 `importProfileAsync` ```java /** * 异步导入用户档案数据(避免超时) */ public void importProfileAsync(List profileList, Boolean isUpdateSupport, String operName); ``` ### 3. Service实现层修改 ✅ **文件**: `ry-xinli-system/src/main/java/com/ddnai/system/service/impl/psychology/PsyUserProfileServiceImpl.java` **修改内容**: - 添加 `@Async` 注解导入 - 实现异步导入方法,使用 `@Async` 注解标记 ```java import org.springframework.scheduling.annotation.Async; @Override @Async public void importProfileAsync(List profileList, Boolean isUpdateSupport, String operName) { try { log.info("异步导入任务开始,操作人:{},数据量:{}", operName, profileList.size()); // 调用同步导入方法执行实际导入逻辑 importProfile(profileList, isUpdateSupport, operName); log.info("异步导入任务完成,操作人:{}", operName); } catch (Exception e) { log.error("异步导入任务失败,操作人:{},错误:{}", operName, e.getMessage(), e); } } ``` ### 4. 启动类修改 ✅ **文件**: `ry-xinli-admin/src/main/java/com/ddnai/XinliApplication.java` **修改内容**: - 添加 `@EnableAsync` 注解启用异步支持 - 配置异步任务线程池 ```java import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) @EnableAsync public class XinliApplication { @Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); // 核心线程数 executor.setMaxPoolSize(10); // 最大线程数 executor.setQueueCapacity(100); // 队列容量 executor.setThreadNamePrefix("async-import-"); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60); executor.initialize(); return executor; } } ``` ### 5. 配置文件修改 ✅ **文件**: `ry-xinli-admin/src/main/resources/application.yml` **修改内容**: - 增加MVC异步请求超时配置(作为保险) ```yaml spring: mvc: async: # 异步请求超时时间(毫秒),设置为10分钟 request-timeout: 600000 ``` ## 工作原理 1. **文件上传**: 用户上传Excel文件 2. **解析数据**: Controller解析Excel文件为对象列表 3. **启动异步任务**: 调用 `importProfileAsync` 方法,Spring会在独立线程中执行 4. **立即返回**: HTTP请求立即返回成功响应 5. **进度管理**: 后台线程执行导入,通过 `ImportProgressManager` 记录进度 6. **前端轮询**: 前端通过 `/importProgress` 接口定期查询导入进度 7. **完成通知**: 导入完成后,前端获取到最终结果并显示 ## 优势 ✅ **避免超时**: HTTP请求立即返回,不会因导入时间长而超时 ✅ **用户体验好**: 前端实时显示导入进度 ✅ **不阻塞服务器**: 导入任务在独立线程池中执行 ✅ **支持大批量**: 可以处理大量数据而不影响其他请求 ✅ **向后兼容**: 保留了同步导入方法,不影响其他功能 ## 注意事项 ⚠️ **重启应用**: 修改完成后需要重启Spring Boot应用才能生效 ⚠️ **数据库连接**: 异步线程需要数据库连接,确保连接池配置足够 ⚠️ **事务管理**: 异步方法中的事务与主线程独立,需注意事务边界 ⚠️ **线程池监控**: 生产环境建议监控线程池状态,避免资源耗尽 ## 如何测试 1. 重启Spring Boot应用 2. 准备一个包含较多数据的Excel文件(建议500+条) 3. 在用户档案管理页面点击"导入" 4. 上传文件后,应该立即收到"导入任务已启动"的提示 5. 观察进度条实时更新 6. 等待导入完成,查看结果统计 ## 进一步优化建议(可选) 如果仍然遇到问题,可以考虑: 1. **增加Nginx超时配置** (如果使用了Nginx反向代理): ```nginx proxy_connect_timeout 600s; proxy_send_timeout 600s; proxy_read_timeout 600s; ``` 2. **优化批量插入性能**: - 已实现分批处理(每批500条) - 可以根据实际情况调整批次大小 3. **数据库优化**: - 确保相关字段有索引 - 检查批量插入SQL性能 --- **修复完成日期**: 2025-12-01 **修复人员**: Cascade AI **影响范围**: 用户档案导入功能 **风险评估**: 低(仅改变执行方式,核心逻辑未变)