多级动态表头导出-easyexcel
导出如下动态表头

主要的构造tabCols和tableData,
注意表头的字段,基本构造出了该格式所有的都能适配
@GetMapping("/exportData") public void excelExport(TbDtTargetHealthMon tbDtTargetHealthMon, HttpServletResponse response) throws IOException { response.reset(); response.setCharacterEncoding("UTF-8"); //响应内容格式 response.setContentType("application/vnd.ms-excel"); //设置文件名 // String fileName =System.currentTimeMillis() + ".xlsx"; try { //设置前端下载文件名 String urlFileName = URLEncoder.encode(tbDtTargetHealthMon.getModuleName() + "健康度详情" + System.currentTimeMillis() , "UTF-8"); response.setHeader("content-disposition", "attachment; filename=" + urlFileName + ".xlsx"); // *代表所有请求都可访问 response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET"); response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, " + "If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ExcelWriter excelWriter = null; try { Map<String, Object> result = tbDtTargetHealthMonService.getTabCols(tbDtTargetHealthMon); List<Map<String, String>> tabCols = (List<Map<String, String>>) result.get("tabCols"); List<List<String>> excelHead = head(tabCols); // 第一页数据 List<Map<String, String>> dataOne = (List<Map<String, String>>) result.get("tableData"); //5w数据一个sheet int batchSize = AutoExportConstants.SHEET_PAGE_SIZE; int totalSize = dataOne.size(); int sheetCount = (int) Math.ceil((double) totalSize / batchSize); excelWriter = EasyExcelFactory.write(response.getOutputStream()).build(); for (int i = 0; i < sheetCount; i++) { int fromIndex = i * batchSize; int toIndex = Math.min((i + 1) * batchSize, totalSize); List<Map<String, String>> currentData = dataOne.subList(fromIndex, toIndex); WriteSheet writeSheet = EasyExcel .writerSheet("sheet" + (i + 1)) .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) .registerWriteHandler(horizontalCellStyleStrategy()) .head(excelHead) .build(); excelWriter.write(dataList(tabCols, currentData), writeSheet); } } catch (Exception e) { e.printStackTrace(); } catch (Throwable throwable) { throwable.printStackTrace(); } finally { if (excelWriter != null) { excelWriter.finish(); } if(response.getOutputStream() != null){ response.getOutputStream().close(); } } } private List<List<String>> head(List<Map<String, String>> tabCols) { return tabCols.stream() .map(e -> Stream.of(e.get("columnParent"), e.get("columnName")).filter(Objects::nonNull).collect(Collectors.toList())) .collect(Collectors.toList()); } private List<List<Object>> dataList(List<Map<String, String>> tabCols, List<Map<String, String>> mapList) { List<List<Object>> list = new ArrayList<List<Object>>(); for (int i = 0; i < mapList.size(); i++) { Map row = mapList.get(i); List<Object> data = new ArrayList<Object>(); for (int j = 0; j < tabCols.size(); j++) { String filed = tabCols.get(j).get("columnField"); Object objVal = row.get(filed); String val = Objects.toString(objVal, ""); data.add(val); } list.add(data); } return list; } private HorizontalCellStyleStrategy horizontalCellStyleStrategy() { // 头的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景设置为红色 headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); WriteFont headWriteFont = new WriteFont(); headWriteFont.setFontHeightInPoints((short) 14); headWriteCellStyle.setWriteFont(headWriteFont); // 内容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); // 背景绿色 contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex()); WriteFont contentWriteFont = new WriteFont(); contentWriteFont.setFontHeightInPoints((short) 10); contentWriteFont.setColor(IndexedColors.GREY_80_PERCENT.getIndex()); contentWriteCellStyle.setWriteFont(contentWriteFont); contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); contentWriteCellStyle.setBorderTop(BorderStyle.THIN); contentWriteCellStyle.setBorderRight(BorderStyle.THIN); contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); contentWriteCellStyle.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); contentWriteCellStyle.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); contentWriteCellStyle.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); contentWriteCellStyle.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); }
tabCols的格式
这个tabCols的顺序就是导出表头的顺序,columnField相当于就是取值映射的key,columnName就是表头的中文,columnParent就是父级表头,这些名字可以自己定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | [{ "columnField" : "monthId" , "columnName" : "月份" }, { "columnField" : "latnName" , "columnName" : "本地网" }, { "columnField" : "销售费用整体效能" , "columnName" : "销售费用整体效能得分" }, { "columnParent" : "销售费用占收比" , "columnField" : "targetValue_xsfy_001" , "columnName" : "指标值" }, { "columnParent" : "销售费用占收比" , "columnField" : "targetGrades_xsfy_001" , "columnName" : "指标得分" }, { "columnParent" : "百元基础费拉动增量基础业务收入" , "columnField" : "targetValue_xsfy_002" , "columnName" : "指标值" }, { "columnParent" : "百元基础费拉动增量基础业务收入" , "columnField" : "targetGrades_xsfy_002" , "columnName" : "指标得分" }, { "columnParent" : "百元销售费用拉动增量主营收入" , "columnField" : "targetValue_xsfy_003" , "columnName" : "指标值" }, { "columnParent" : "百元销售费用拉动增量主营收入" , "columnField" : "targetGrades_xsfy_003" , "columnName" : "指标得分" }, { "columnParent" : "新增用户户均销售费用" , "columnField" : "targetValue_xsfy_004" , "columnName" : "指标值" }, { "columnParent" : "新增用户户均销售费用" , "columnField" : "targetGrades_xsfy_004" , "columnName" : "指标得分" }, { "columnField" : "渠道费用效能" , "columnName" : "渠道费用效能得分" }, { "columnParent" : "价值积分平均单价" , "columnField" : "targetValue_xsfy_008" , "columnName" : "指标值" }, { "columnParent" : "价值积分平均单价" , "columnField" : "targetGrades_xsfy_008" , "columnName" : "指标得分" }, { "columnParent" : "建店12月以上门店月均价值积分" , "columnField" : "targetValue_xsfy_009" , "columnName" : "指标值" }, { "columnParent" : "建店12月以上门店月均价值积分" , "columnField" : "targetGrades_xsfy_009" , "columnName" : "指标得分" }, { "columnParent" : "价值积分同比增长" , "columnField" : "targetValue_xsfy_010" , "columnName" : "指标值" }, { "columnParent" : "价值积分同比增长" , "columnField" : "targetGrades_xsfy_010" , "columnName" : "指标得分" }, { "columnParent" : "千分店占比" , "columnField" : "targetValue_xsfy_011" , "columnName" : "指标值" }, { "columnParent" : "千分店占比" , "columnField" : "targetGrades_xsfy_011" , "columnName" : "指标得分" }, { "columnField" : "客户服务费效能" , "columnName" : "客户服务费效能得分" }, { "columnParent" : "客户服务费占收比" , "columnField" : "targetValue_xsfy_012" , "columnName" : "指标值" }, { "columnParent" : "客户服务费占收比" , "columnField" : "targetGrades_xsfy_012" , "columnName" : "指标得分" }, { "columnParent" : "单位用户客户服务费" , "columnField" : "targetValue_xsfy_013" , "columnName" : "指标值" }, { "columnParent" : "单位用户客户服务费" , "columnField" : "targetGrades_xsfy_013" , "columnName" : "指标得分" }, { "columnParent" : "客户保有率" , "columnField" : "targetValue_xsfy_014" , "columnName" : "指标值" }, { "columnParent" : "客户保有率" , "columnField" : "targetGrades_xsfy_014" , "columnName" : "指标得分" }, { "columnParent" : "收入保有率" , "columnField" : "targetValue_xsfy_015" , "columnName" : "指标值" }, { "columnParent" : "收入保有率" , "columnField" : "targetGrades_xsfy_015" , "columnName" : "指标得分" }] |
tableData的格式
这个顺序无所谓,key就对应的就是tabCols的columnField
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | [{ "targetValue_xsfy_008" : "2.6900" , "targetGrades_xsfy_012" : "86.67" , "targetValue_xsfy_009" : "3542.0100" , "targetGrades_xsfy_013" : "93.33" , "targetGrades_xsfy_010" : "6.67" , "targetGrades_xsfy_011" : "86.67" , "targetValue_xsfy_004" : "227.9600" , "targetValue_xsfy_002" : "0.0000" , "targetGrades_xsfy_014" : "0.00" , "targetValue_xsfy_003" : "73.8400" , "渠道费用效能" : "58.67" , "targetGrades_xsfy_015" : "0.00" , "monthId" : "202401" , "销售费用整体效能" : "21.67" , "targetValue_xsfy_011" : "0.8081" , "targetValue_xsfy_012" : "1.64%" , "targetValue_xsfy_010" : "76.18%" , "targetGrades_xsfy_001" : "13.33" , "targetGrades_xsfy_002" : "0.00" , "targetValue_xsfy_015" : "0.00%" , "targetGrades_xsfy_003" : "0.00" , "targetValue_xsfy_013" : "0.7500" , "客户服务费效能" : "54.00" , "targetGrades_xsfy_004" : "73.33" , "targetValue_xsfy_014" : "0.00%" , "targetGrades_xsfy_009" : "40.00" , "targetGrades_xsfy_008" : "80.00" , "targetValue_xsfy_001" : "10.19%" , "latnName" : "合肥" }] |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通