news 2026/3/20 6:10:01

负责处理大数据量的Excel导出功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
负责处理大数据量的Excel导出功能
/** * 数据导出控制器 * 负责处理大数据量的Excel导出功能 */ @RestController @RequestMapping("/api/export") public class ExportController { @Autowired private DataService dataService; /** * 内部类:Excel数据导出服务器 * 实现EasyPOI的IExcelExportServer接口,用于大数据量分页导出 * * 工作原理: * 1. EasyPOI的exportBigExcel方法会循环调用本类的selectListForExcelExport方法 * 2. 每次调用会传入当前的页码(page参数,从1开始递增) * 3. 本方法负责查询对应页码的数据并返回 * 4. 当返回空列表时,EasyPOI停止调用,导出结束 */ private class DataExportServer implements IExcelExportServer { /** * 每页查询的数据条数 * 推荐值:1000-5000条,根据内存和性能调整 * 太大:单次查询内存占用高 * 太小:查询次数多,IO频繁 */ private final int PAGE_SIZE = 2000; /** * Excel导出数据查询方法 * 由EasyPOI自动循环调用,用于获取分页数据 * * @param query 查询参数对象,由exportBigExcel方法的最后一个参数传入 * @param page 当前页码,从1开始,由EasyPOI自动递增传入 * @return 当前页的数据列表 * - 返回非空列表:EasyPOI继续获取下一页 * - 返回空列表/空集合:EasyPOI停止获取,导出结束 * * 注意:每次调用该方法时,EasyPOI都会传入新的page参数 * 例如: * 第1次调用:page=1 * 第2次调用:page=2 * ... * 直到返回空列表为止 */ @Override public List<Object> selectListForExcelExport(Object query, int page) { // Step 1: 参数类型转换 // 将传入的Object类型转换为具体的PageDTO类型 // 这里的query就是exportBigExcel方法传入的PageDTO对象 PageDTO pageQuery = (PageDTO) query; // Step 2: 设置分页参数 // EasyPOI传入的page参数是当前页码,需要设置到查询对象中 pageQuery.setPageNum(page); // 设置当前页码 pageQuery.setPageSize(PAGE_SIZE); // 设置每页大小 // Step 3: 调用业务服务查询数据 // 这里调用你的分页查询接口,获取当前页的数据 // dataService.getDataByPage() 应该是你已有的分页查询方法 PageResult<DataVO> pageResult = dataService.getDataByPage(pageQuery); // Step 4: 处理查询结果 // 如果查询结果为空,返回空列表,告诉EasyPOI导出结束 if (pageResult == null || pageResult.getList() == null) { return Collections.emptyList(); // 返回空列表,结束导出 } // Step 5: 返回当前页数据 // 将查询结果转换为List<Object>类型返回 // EasyPOI会接收这些数据并写入Excel,然后继续调用下一页 return new ArrayList<>(pageResult.getList()); } } /** * 大数据量Excel导出接口 * 使用EasyPOI的exportBigExcel方法进行分页导出 * * @param response HTTP响应对象,用于输出Excel文件 * * 导出流程: * 1. 设置响应头,指定文件类型和文件名 * 2. 创建导出参数对象,设置标题、sheet名等 * 3. 创建查询参数对象,可设置过滤条件 * 4. 调用exportBigExcel方法,传入: * - 导出参数 * - 数据实体类 * - 数据查询服务器实例 * - 查询参数 * 5. 将生成的Excel写入HTTP响应流 * 6. 关闭workbook释放资源 * * 性能特点: * - 支持百万级数据导出 * - 内存占用低,不会OOM * - 支持分页查询,避免数据库压力 */ @GetMapping("/big-data") public void exportBigData(HttpServletResponse response) { // Step 1: 设置HTTP响应头 // 指定响应内容为Excel文件 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); // 设置下载文件名,URLEncoder处理中文文件名 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("大数据导出.xlsx", "UTF-8")); try { // Step 2: 创建导出参数 // ExportParams用于配置导出的各种参数 ExportParams params = new ExportParams(); params.setTitle("大数据导出报表"); // Excel文件标题 params.setSheetName("数据明细"); // Sheet名称 params.setMaxNum(0); // 最大导出条数,0表示不限制 // Step 3: 创建查询参数对象 // 这里可以设置查询条件,会传递给DataExportServer PageDTO query = new PageDTO(); // 示例:设置时间范围过滤 query.setStartTime("2024-01-01"); query.setEndTime("2024-12-31"); query.setStatus(1); // 状态过滤 // 更多查询条件... // Step 4: 创建数据导出服务器实例 // DataExportServer负责分页查询数据 DataExportServer exportServer = new DataExportServer(); // Step 5: 执行大数据导出 // exportBigExcel方法会: // 1. 创建SXSSFWorkbook(流式Excel) // 2. 循环调用DataExportServer.selectListForExcelExport() // 3. 每次获取一页数据,写入Excel // 4. 直到DataExportServer返回空列表 Workbook workbook = ExcelExportUtil.exportBigExcel( params, // 导出参数配置 DataVO.class, // 数据实体类,用于映射Excel列 exportServer, // 数据查询服务器实例 query // 查询参数,会传给DataExportServer ); // Step 6: 将Excel写入HTTP响应流 // 这里会自动将数据发送给客户端 workbook.write(response.getOutputStream()); // Step 7: 关闭workbook释放资源 // 重要:必须关闭,否则会有临时文件残留 workbook.close(); } catch (IOException e) { // 处理IO异常 throw new RuntimeException("Excel导出失败", e); } } /** * 带查询条件的大数据导出接口 * * @param response HTTP响应 * @param startTime 开始时间(可选) * @param endTime 结束时间(可选) * @param keyword 关键词搜索(可选) * * 使用示例: * GET /api/export/data?startTime=2024-01-01&endTime=2024-12-31&keyword=测试 */ @GetMapping("/data") public void exportDataWithQuery( HttpServletResponse response, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String keyword) { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("数据报表.xlsx", "UTF-8")); try { // 创建导出参数 ExportParams params = new ExportParams("数据报表", "数据列表"); // 创建查询条件 PageDTO query = new PageDTO(); query.setStartTime(startTime); query.setEndTime(endTime); query.setKeyword(keyword); // 可以根据需要添加更多查询条件 query.setOrderBy("create_time"); query.setOrderType("DESC"); // 执行导出 Workbook workbook = ExcelExportUtil.exportBigExcel( params, DataVO.class, new DataExportServer(), query ); workbook.write(response.getOutputStream()); workbook.close(); } catch (IOException e) { throw new RuntimeException("导出失败", e); } } /** * 异步导出接口 * 适用于数据量特别大,导出时间较长的场景 * * @param query 查询条件 * @return 任务ID,用于查询导出进度 */ @PostMapping("/async-export") public ResponseEntity<Map<String, Object>> asyncExport(@RequestBody PageDTO query) { // 生成任务ID String taskId = UUID.randomUUID().toString(); // 启动异步导出任务 CompletableFuture.runAsync(() -> { try { // 这里可以保存导出进度到Redis或数据库 saveExportProgress(taskId, 0, "开始导出"); // 执行导出逻辑 String filePath = executeAsyncExport(taskId, query); // 更新任务状态 saveExportProgress(taskId, 100, "导出完成,文件:" + filePath); } catch (Exception e) { saveExportProgress(taskId, -1, "导出失败:" + e.getMessage()); } }); // 立即返回任务ID Map<String, Object> result = new HashMap<>(); result.put("taskId", taskId); result.put("message", "导出任务已提交,请使用taskId查询进度"); return ResponseEntity.ok(result); } /** * 查询导出进度 * * @param taskId 任务ID * @return 导出进度信息 */ @GetMapping("/export-progress/{taskId}") public ResponseEntity<Map<String, Object>> getExportProgress(@PathVariable String taskId) { // 从Redis或数据库查询进度 ExportProgress progress = getProgressFromCache(taskId); Map<String, Object> result = new HashMap<>(); result.put("taskId", taskId); result.put("progress", progress.getProgress()); result.put("status", progress.getStatus()); result.put("message", progress.getMessage()); result.put("fileUrl", progress.getFileUrl()); return ResponseEntity.ok(result); } /** * 执行异步导出的实际方法 */ private String executeAsyncExport(String taskId, PageDTO query) throws Exception { String fileName = "export_" + taskId + ".xlsx"; String filePath = "/tmp/exports/" + fileName; try (FileOutputStream fos = new FileOutputStream(filePath)) { ExportParams params = new ExportParams("异步导出报表", "数据"); Workbook workbook = ExcelExportUtil.exportBigExcel( params, DataVO.class, new DataExportServer() { private int totalProcessed = 0; @Override public List<Object> selectListForExcelExport(Object queryObj, int page) { // 更新进度 totalProcessed += PAGE_SIZE; saveExportProgress(taskId, Math.min(90, totalProcessed * 100 / 10000), // 示例计算进度 "正在导出第" + page + "页" ); return super.selectListForExcelExport(queryObj, page); } }, query ); workbook.write(fos); workbook.close(); return filePath; } } // 模拟进度保存方法 private void saveExportProgress(String taskId, int progress, String message) { // 实际项目中可以保存到Redis或数据库 System.out.println("任务" + taskId + "进度:" + progress + "%,消息:" + message); } // 模拟进度查询方法 private ExportProgress getProgressFromCache(String taskId) { // 实际项目中从Redis或数据库查询 ExportProgress progress = new ExportProgress(); progress.setProgress(50); progress.setStatus("processing"); progress.setMessage("正在导出中..."); return progress; } /** * 导出进度实体类 */ @Data static class ExportProgress { private int progress; // 进度百分比 private String status; // 状态:processing/success/failed private String message; // 状态消息 private String fileUrl; // 文件下载地址 } }
  1. 自动分页机制:EasyPOI会自动循环调用selectListForExcelExport方法

  2. 页码传递page参数从1开始,每次调用自动递增

  3. 结束条件:当返回空列表时,导出自动结束

  4. 内存优化:使用SXSSFWorkbook,不会将所有数据加载到内存

  5. 异常处理:建议在方法中添加try-catch,避免单页失败导致整个导出失败

  6. 资源释放:导出完成后一定要调用workbook.close()

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/15 11:59:08

Dify智能体平台+Qwen3-VL-30B:构建企业级视觉问答机器人

Dify智能体平台与Qwen3-VL-30B&#xff1a;打造企业级视觉问答机器人的实践路径 在金融报告自动解析、医疗影像辅助诊断、工业质检实时告警等场景中&#xff0c;企业正面临一个共同挑战&#xff1a;如何让AI真正“读懂”图像背后的复杂语义&#xff1f;传统的OCR工具能提取文字…

作者头像 李华
网站建设 2026/3/17 4:49:19

2583.一款视频帧批量提取工具的技术实现与实用价值(附源码及成品软件)

作为一名经常处理视频素材的开发者&#xff0c;我深知从视频中精准提取关键帧的痛点。手动截图效率低下&#xff0c;专业软件操作复杂&#xff0c;批量处理更是难上加难。直到我们团队基于 OpenCV 和 PyQt5 开发了这款视频帧提取工具&#xff0c;才真正实现了从繁琐操作到高效处…

作者头像 李华
网站建设 2026/3/14 16:11:14

物流系统越来越复杂,数字孪生正在发挥关键作用

概述 随着物流行业规模不断扩大&#xff0c;业务链条愈发复杂&#xff0c;单靠经验和静态数据已难以支撑高效运营。仓储调度、运输路径、车辆管理、人员安排等环节彼此关联&#xff0c;一处变化就可能引发连锁反应。在这样的背景下&#xff0c;数字孪生技术逐渐走进物流行业视…

作者头像 李华
网站建设 2026/3/15 16:51:55

雷科电力-REKE-SZH SF6综合测试仪

一、概述&#xff1a;雷科电力-REKE-SZH SF6综合测试仪将SF6露点测试、SF6纯度测试集为一体&#xff0c;将原来要用多台仪器才能实现的功能&#xff0c;集中在一台仪器上。一次现场测量&#xff0c;即可以完成多项指标检测&#xff0c;大大节省设备中的气体。同时也减少了用户的…

作者头像 李华
网站建设 2026/3/20 0:42:52

开题报告(毕业设计 )基于nodejs汽车后市场管理系统项目源码+论文 PPT

摘 要 随着汽车保有量的持续攀升&#xff0c;汽车后市场管理系统应运而生&#xff0c;旨在为汽车产业链各环节提供全方位的信息化解决方案。该系统涵盖管理员、4S店、配件供应商及用户四大部分&#xff0c;功能丰富多样。车主可通过系统查询车辆信息、预约售后服务、进行服务…

作者头像 李华