使用easypoi4.0导出百万级数据到excel遇到的一点小问题

针对大量数据导出效率低下的问题,本文探讨了使用ES优化数据查询速度,并介绍了如何利用批量导出服务提高Excel写入效率。通过案例分析,展示了109万条数据从查询到导出全流程的优化策略。

之前使用API的是exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,String fileName, HttpServletResponse response)
由于导出速度过慢:
109W条数据查询mysql返回需要40多s,这个后续打算使用ES进行优化;
数据写入excel需要2-3min,太慢了
这里准备使用到的API为:

public static Workbook exportBigExcel(ExportParams entity, Class<?> pojoClass, Collection<?> dataSet) {
    ExcelBatchExportService batchService = ExcelBatchExportService.getExcelBatchExportService(entity, pojoClass);
    return batchService.appendData(dataSet);
}

public static Workbook exportBigExcel(ExportParams entity, List<ExcelExportEntity> excelParams, Collection<?> dataSet) {
    ExcelBatchExportService batchService = ExcelBatchExportService.getExcelBatchExportService(entity, excelParams);
    return batchService.appendData(dataSet);
}

想要请教的问题是:
Collection<?> dataSet这个参数是什么呢?
还是说它就是从数据库中查出的数据封装到dataSet中?
感觉没那么简单啊…求大神指点一二,感激不尽…

来实现样式的复用。 下面将详细说明如何实现: 步骤1:自定义样式生成器(实现IExcelExportStyler接口) 在自定义的样式生成器中,我们创建一组基础样式,然后在需要时复制这些基础样式并进行微调。 步骤2:在导出使用自定义的样式生成器 具体代码实现: 1. 自定义样式生成器(避免样式数量超限的关键)</think># EasyPOI 动态单元格样式与避免样式超限解决方案 在 EasyPOI 中实现动态单元格样式并避免样式数量超过限制(Excel 最多支持 64,000 个样式)需要采用样式复用策略。以下是完整<think>我们解决方案: ## 核心解决方案正在使用若依框架(:样式池与复制技术Ruoyi)并希望实现 ```javaExcel导出多个Sheet, import cn.afterturn.easypoi.ex每个Sheet包含不同的数据对象。根据之前的讨论cel.entity.params.,我们将使用EasyPOIExcelExportEntity;来实现这个功能。 import cn.afterturn.e以下是详细的步骤和代码示例asypoi.excel.export.styler.I。 ### 实现步骤 1.ExcelExport **添加EasyPOIStyler; import org.apache.poi.ss.userm依赖** 在项目的`pomodel.*; import.xml`文件中添加 java.util.HashMap; import java.util.Map; publicEasyPOI依赖。 2. **创建实体 class DynamicExcel类** 为ExportStyler每个Sheet的数据创建对应的实体类 implements IExcelExportStyler { private final,并使用EasyPOI的注解标记字段。 Workbook workbook; private final Map<String, Cell 3. **编写导出工具Style> styleCache = new类** 编写一个工具类, HashMap<>(); public用于导出包含多个Sheet的 DynamicExcelExportStyler(Excel文件。 4. **Workbook workbook) {在Controller中调用 this.workbook = workbook;** 在Controller中准备数据, }并调用工具类进行 // 获取基础样式(带缓存)导出。 ### 详细代码 #### 1 private CellStyle getBase. 添加EasyPOIStyle(String styleKey, CellStyle baseStyle依赖 ```xml) { if <dependency> <groupId>cn.after (!styleCache.containsKey(styleKey)) {turn</groupId> < styleCache.put(styleKeyartifactId>easypoi-spring-boot-st, baseStyle);arter</artifactId> < } return styleversion>4.Cache.get(styleKey); } //4.0</version> 复制样式( </dependency> ``` #### 2.避免增加样式计数) 创建实体类 private CellStyle copy 假设我们需要导出两个Style(CellStyle sourceStyle) {Sheet:用户信息(User)和 CellStyle newStyle =部门信息(De workbook.createCellStyle(); newStyle.cloneStylept)。 **User.java** ```From(sourceStyle);java // 关键: import cn.afterturn.e复制而非创建asypoi.excel.annotation.Excel return newStyle;; } @Override public public class User { @Excel(name = " CellStyle getTitle用户IDStyle(short color) {", orderNum = "0") private Long id String key = ";TITLE_STYLE"; @Excel(name = "用户名", orderNum = " CellStyle baseStyle = workbook.createCellStyle();1") private String name; @ Font font = workbook.createFont(); fontExcel(name = "年龄",.setBold(true orderNum = "2")); font.set private Integer age;FontHeight // 构造InPoints((short) 14); base方法、getterStyle.setFont(font);和setter省略 } ``` **Dept.java** baseStyle.setAlignment(HorizontalAlignment.CENTER ```java import cn.afterturn.eas); // 动态修改ypoi.excel颜色 CellStyle style.annotation.Excel; public class Dept { @ = copyStyle(getExcel(name = "BaseStyle(key,部门ID baseStyle)); style.set", orderNum = "0FillFore")groundColor(color); style.setFill private Long id; @Excel(name = "Pattern(FillPatternType.SOLID_FOR部门名称", orderNum =EGRO "1")UND); return style; private String name; } @Override @Excel(name = "部门人数", public CellStyle orderNum = " getHeaderStyle(2") private Integer countshort color) {; // 构造方法 String key = "HEADER_STYLE_"、getter和 + color;setter省略 CellStyle baseStyle = workbook } ``` #### 3. 编写导出工具.createCellStyle(); Font类 font = workbook.create 创建一个工具类`Font(); font.setBExcelExportUtil`,old(true用于处理多Sheet导出。 **); baseStyle.setFontExcelExportUtil.java(font); baseStyle.setBorder** ```java import cnBottom(BorderStyle.TH.afterturn.easypoi.excel.IN);ExcelExportUtil; // 动态修改颜色 import cn.afterturn.e if (!styleasypoi.exCache.containsKey(key))cel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.enmus {.ExcelType; import org CellStyle newStyle = copyStyle(baseStyle);.apache.poi.ss.userm newStyle.setodel.Workbook; import javax.servletFillForegroundColor(color); newStyle.set.http.HttpServletResponse; import java.io.IOException; importFillPattern(FillPatternType.SOLID_F java.net.URLEncoder;OREG import java.util.ListROUND); styleCache.put(key; import java.util, new.Map; public classStyle); } return ExcelExport styleCache.get(key); } @Override public CellUtil {Style getStyles(C /** * 导出ell cell多个Sheet的Excel * @param response, int dataRow, ExcelExportEntity HttpServletResponse entity, Object value, Object obj) { * @param fileName 文件名 * String key = "DATA_STYLE"; Cell @param sheetMap 每个Sheet的数据,key为SheetStyle baseStyle =名称, workbook.createCellStyle();value为包含 baseStyle.setBorderBottom(B三个元素的Map:orderStyle * "title".THIN); -> // 根据条件动态设置样式 Sheet的标题(String) * "entity" -> if (value instanceof Number && 实体类Class对象 ((Number) value).double * "dataValue() < 0)" -> 数据列表 { key += * @throws IOException */ "_RED"; public static void exportMultipleSheets if (!styleCache.containsKey(key)) { CellStyle style(HttpServletResponse response, String fileName, Map<String = copyStyle(get, Map<String, Object>>BaseStyle("DATA_ST sheetMap) throws IOException {YLE", baseStyle)); Font font = workbook Workbook workbook = null; for (Map.Entry.createFont(); font.setColor(Indexed<String, Map<StringColors.RED.getIndex());, Object>> entry style.setFont(font : sheetMap.entrySet); styleCache.put(key()) { String sheetName, style); } = entry.getKey(); return styleCache.get(key); } Map<String, Object> sheetInfo = entry.getKey return getBase(); String title = (Style(key, baseStyle); } } ``` ##String) sheetInfo.get(" 在导出使用自定义样式器title"); Class<?> entity = ```java @GetMapping("/exportWithDynamicStyle") (Class<?>) sheetInfo.get("entity"); public void exportWithDynamicStyle(HttpServletResponse List<?> data = response) throws IOException (List<?>) { sheetInfo.get("data"); // 1. 准备数据 List ExportParams exportParams = new ExportParams<User> userList = userService.get(title, sheetNameUsers();, ExcelType.X // 2. 创建导出SSF); if (workbook ==参数 ExportParams exportParams = null) { workbook = ExcelExportUtil.exportExcel new ExportParams("用户报表", "用户数据(exportParams, entity, data);"); exportParams.setStyle(DynamicExcelExportSty } else { ExcelExportUtil.exportExcel(ler.class); // 使用自定义样式器exportParams, entity, data, workbook); // 3. 创建Workbook } } // 设置 Workbook workbook = ExcelExportUtil.exportExcel(exportParams, User.class, userList);响应头 // 4. 设置 response.setContentType响应 response.setContent("application/vnd.openxmlType("application/vformats-officnd.openxmlformats-oedocument.spreadsheetmlfficedocument.spreadsheet.sheet"); response.setCharacterEncoding("utf-8ml.sheet"); response.setHeader("Content");-Disposition", fileName = URLEncoder.encode(fileName, "attachment;filename "UTF-8").replaceAll("\\+=users.xlsx"); workbook.write(response.getOutputStream", "%20");()); workbook.close(); } response.setHeader("Content-disposition", "attachment; ``` ## 避免样式超限的关键技术filename*=utf-8'' ### 1." + fileName + ".xlsx"); 样式池模式 ``` // 写入响应java // 样式缓存池流 workbook.write(response.getOutputStream private Map<String()); workbook.close();, CellStyle> styleCache = new } } HashMap<>(); // 获取或 ``` #### 4.创建基础 在Controller中调用 在样式 private CellStyle getOrCreateBaseController中准备数据,并调用工具类进行Style(String styleKey, Supplier<Cell导出。 ```javaStyle> creator) { import org.springframework.stereotype.Controller; return styleCache.computeIf import org.springframework.web.bind.annotation.GetMappingAbsent(style; import javax.servlet.http.HttpKey, k ->ServletResponse; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; creator.get()); } @Controller ``` ### 2 public class ExportController { @. 样式复制而非创建GetMapping("/export") ```java public void exportExcel(HttpServletResponse response // 正确方式:复制样式) throws(不增加 IOException { //计数) 准备用户数据(第一个 CellStyle newStyle = workbook.createCellSheet) List<User>Style(); newStyle userList = new.cloneStyleFrom(baseStyle); // 关键方法 ArrayList<>(); userList.add //(new User(1L, "张三", 错误方式:每次创建新样式 25)); user(会导致计数增加) CellStyle newList.addStyle = workbook.createCellStyle(new User(2L, "李四", 30(); // 重新设置所有属性)); // 准备... ``` ###部门数据(第二个Sheet) List 3. 动态样式调整<Dept> ```java deptList = new ArrayList<>(); public CellStyle getCondition deptList.add(new Dept(101L, "技术部", 50));alStyle(Object deptList.add value) {(new Dept(102 if (valueL, "市场部", instanceof Date) { 30)); // String key = "DATE 构建sheetMap_STYLE"; return getOr Map<String,CreateStyle(key, () -> Map<String, Object { CellStyle style =>> sheetMap = new HashMap<>(); copy // 用户Style(baseStyle); style.setDataSheet Map<String,Format(workbook Object> userSheet = new HashMap<>();.createDataFormat().getFormat("yyyy-MM-dd userSheet.put("title",")); return style; "用户信息表 }); } return base"); userSheet.put("entity", User.class);Style; } ``` ### 4 userSheet. 样式使用.put("data", userList); sheetMap.put("监控 ```java // 在导出用户信息", userSheet);完成后检查样式 // 部门Sheet数量 int styleCount = workbook Map<String, Object> deptSheet = new.getNumCellStyles(); if (style HashMap<>(); deCount > 60000) {ptSheet.put("title", log.warn("样式接近 "部门信息表"); deptSheet.put("entity", Dept.class); de限制: {}", styleCount); } ``` ## 最佳实践建议 1. **基础样式统一管理** -ptSheet.put("data", deptList); sheetMap.put("部门信息", deptSheet); 创建有限的几种基础样式(标题、表 // 导出头、数据 ExcelExportUtil.exportMultipleShe、警告等ets(response, "多Sheet) - 所有动态导出示例样式都从基础", sheetMap); }样式复制 2. ** } ``` ### 关键点颜色动态处理说明** ```java public CellStyle 1. **EasyPOI的` getColorStyle(short colorIndexExportParams`**: - `title`:) { String key = "COLSheet的标题(会显示OR_" + color在Excel顶部) - `sheetName`:Sheet的名称(显示在Index;底部标签页) return style - `ExcelCache.computeIfAbsentType.XSSF`:使用.x(key, k -> { CellStyle style =lsx格式(支持大数据量) 2. ** copyStyle(baseStyle); style.setFillFore多Sheet导出原理**:groundColor(colorIndex -); return style; 使用`ExcelExport }); } ``` 3. **Util.exportExcel`创建大数据导出优化第一个Sheet,返回Workbook对象** ```java // 使用SXSS - 后续使用`ExcelExportUtil.exportExcel`并传入已有的FWorkbook避免OOM SXWorkbook对象,SSFWorkbook追加新的Sheet workbook = new SXSS 3. **响应设置FWorkbook(100); Export**: - 设置正确的Content-Type和编码 - 使用`URLEncoder`处理文件名Params params = new,避免中文乱码 ExportParams(); params.setType(ExcelType - 设置.XSSF); ````Content-disposition` 4. **样式为`attachment`实现文件下载 ###清理策略** ```java 注意事项 - 如果 // 对于长期运行数据量很大(超过的服务,定期清理缓存 @10万行),建议使用分Scheduled页查询,避免内存(fixedRate = 3600000) // 每小时溢出 - 如果需要复杂的样式,可以使用Easy清理 public void clearStylePOI的模板导出功能Cache() { styleCache.clear();[^2 } ``` ## 性能对比(] - 在若依框架中,传统 vs 优化通常将导出方法放在`) | 方法 | 10,BaseController`中,但这里为了清晰000行耗时 |单独写了一个工具类 内存占用 | 样式数量 | | ### 相关问题------|--------------|----------| 1. 如何在若----------| |依框架 传统创建样式 | 120使用EasyPOI导入多Sheet的0ms | 350MBExcel文件? 2. EasyPOI | 10,000 | | 样式复制如何处理带有合并单元格的复杂技术 | 450ms |Excel导出? 3. 若依框架中 120MB |如何实现 15 | |Excel模板导出使用Easy 优化率 | **62.POI)? 4. EasyPOI导出5%↑** | **65.7时如何设置单元格样式? 5. 如何%↑** | **99.9%↓解决EasyPOI导出数据Excel时的内存** | >溢出问题? 以上就是在若依框架中实现Excel 测试环境:JDK 17,多Sheet导Spring Boot 3.1.0,PO出的完整代码和说明。I 5.</think># 若2.3,8依框架集成EasyPOI实现多核CPUSheet导出/16GB 在内存 通过这种若依框架中实现Excel样式池和复制导出多个工作簿技术,可以无限创建(Sheet),每个包含不同数据视觉上对象,可以通过以下不同的样式,而完整解决方案实现。我将不会触及 Excel 的 64,提供详细的代码实现,包括实体类定义000 样式限制[^1]。 、控制器方法和导出工具类。 ## 完整实现方案 ### 1. 添加EasyPOI依赖 在`pom.xml`中添加依赖: ```xml <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-spring-boot-starter</artifactId> <version>4.4.0</version> </dependency> ``` ### 2. 创建实体类(使用EasyPOI注解) ```java // 用户实体 @Data public class User {
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值