Administrator
06-02 08:39

流式分页导出

/**
     * 流式导出方法,用于处理大数据量,避免内存溢出
     * @param dataFetcher 数据获取函数,接收页码和页面大小,返回分页结果
     * @param fileName 文件名
     * @param columns 列定义
     * @param response HTTP响应
     * @param pageSize 每页大小
     */
    public static void exportStream(
            BiFunction<Integer, Integer, IPage<?>> dataFetcher,
            String fileName,
            List<Alias> columns,
            HttpServletResponse response,
            int pageSize) {

        SXSSFWorkbook workbook = null;
        try {
            // 设置响应头
            setResponseHeaders(response, fileName);

            // 创建SXSSFWorkbook,设置窗口大小为100行(保留在内存中的行数)
            workbook = new SXSSFWorkbook(100);

            // 创建工作表
            Sheet sheet = workbook.createSheet("数据");

            // 创建表头
            Row headerRow = sheet.createRow(0);
            for (int i = 0; i < columns.size(); i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(columns.get(i).getLabel());
            }

            // 分批获取数据并写入
            int currentPage = 1;
            int rowNum = 1; // 从第二行开始写数据(第一行是表头)

            while (true) {
                // 获取当前页数据
                IPage<?> pageResult = dataFetcher.apply(currentPage, pageSize);
                List<?> records = pageResult.getRecords();

                // 如果没有数据了,退出循环
                if (records == null || records.isEmpty()) {
                    break;
                }

                // 将数据写入Excel
                for (Object record : records) {
                    Row row = sheet.createRow(rowNum++);

                    // 根据字段名获取对应的值并写入单元格
                    for (int col = 0; col < columns.size(); col++) {
                        String fieldName = columns.get(col).getProp();
                        Object value = getFieldValue(record, fieldName);

                        Cell cell = row.createCell(col);
                        if (value != null) {
                            cell.setCellValue(value.toString());
                        } else {
                            cell.setCellValue("");
                        }
                    }
                }

                // 如果当前页数据少于页面大小,说明已经是最后一页
                if (records.size() < pageSize) {
                    break;
                }

                currentPage++;
            }

            // 写入输出流
            workbook.write(response.getOutputStream());

        } catch (Exception e) {
            log.error("流式导出Excel失败", e);
            throw new RuntimeException("导出Excel失败", e);
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                    // 清理临时文件
                    workbook.dispose();
                } catch (Exception e) {
                    log.warn("关闭Excel工作簿时发生异常", e);
                }
            }
        }
    }

    /**
     * 通过反射获取对象字段值
     */
    private static Object getFieldValue(Object obj, String fieldName) {
        try {
            java.lang.reflect.Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (Exception e) {
            log.warn("获取字段值失败: " + fieldName, e);
            return null;
        }
    }

0