easyExcel导出(非注解)

思路:先拿到表头数据,再去封装表数据。
一.动态表头
List<List<String>> headTitles = Lists.newArrayList();//表头数据
   说明:外层list表示的表头接口,内层list表示的是表头每一列的数据,而内层list的每一位元素,代表这该行的数据,位序为0的是第一行数据,位序为1的是第二行数据,依次往下。
下面展示一些 代码片段

     List<List<String>> headTitles = Lists.newArrayList();headTitles.add(Lists.newArrayList(basicTitle,day,day));//第一列的第一二三行headTitles.add(Lists.newArrayList(basicTitle,week,week));//第二列的四一二三行headTitles.add(Lists.newArrayList(basicTitle,dutyPosition1,dutyPosition1));//第三列的一二三行headTitles.add(Lists.newArrayList(basicTitle,dutyPosition2,dutyPosition2));//第四列的一二三行headTitles.add(Lists.newArrayList(basicTitle,dutyPosition3,dutyPosition3));//第五列的一二三行headTitles.add(Lists.newArrayList(basicTitle,dutyPosition4,dutyPosition4));//第六列的一二三行headTitles.add(Lists.newArrayList(basicTitle,dutyPosition5,dutyPosition5));//第七列的一二三行

注意:这里的表头都是固定的,后面的表头是动态生成的,动态表头的生成方法有很多种,例如可以通过横向填充的方法,不过如果表头比较复杂,还涉及到合并操作,建议使用一下这种方法,不需要合并策略就可以实现复杂表头的导出。

  teamList.forEach(item->{headTitles.add(Lists.newArrayList(basicTitle,empty,item));});//这里的empty是空串,

表头会自动合并,依据是相邻列的行数据如果值相同会自动合并单元格
最终效果展现:
二.表头数据
   表头数据的封装是需要返回一个List<List>,不过不同的是,外层list的数据的位序,代表的是行数,内层list的数据的位序代表的列数,封装的时候,位序不能乱,否则导出的时候,会对不上。这里的代码就不贴了,一个一个塞吧,每一行的数据封装进一个list里面,注意位序,位序为0代表第一列,依次往后

 List<List<String>> rowList= new ArrayList<>(fixedTitleSize+DynamicTitle.size())

三.结果封装返回
   使用response输出文件流,浏览器下载导出Excel文件

             List<List<String>> headTitles = (List<List<String>>)responseMap.get("headTitles");//表头数据,通过service查出来就好了List<List<String>> rowList = (List<List<String>>)responseMap.get("rowList"); //表数据String newFilePath = folder + newFileName;ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(new FileOutputStream(newFilePath));excelWriterBuilder.head(headTitles);ExcelWriter excelWriter = excelWriterBuilder.build();WriteSheet writeSheet = EasyExcel.writerSheet("sheet0").build();excelWriter.write(rowList,writeSheet);excelWriter.finish();

下面的代码片等同,会自动关闭输出流

         String sheetName = URLEncoder.encode("表名", "UTF-8");String fileName = sheetName.concat(String.valueOf(System.currentTimeMillis())).concat(".xls");List<List<String>> headTitles = (List<List<String>>)returnMap.get("headTitles");//表数据List<List<String>> rowList = (List<List<String>>)returnMap.get("rowList");//response输出文件流response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));//写入表头,表数据EasyExcel.write(response.getOutputStream()).excelType(ExcelTypeEnum.XLS).head(headTitles).sheet("Sheet0").doWrite(rowList);catch(Excpetion e){response.reset();response.setCharacterEncoding("utf-8");response.setContentType("application/json");response.getWriter().println("导出失败");}

导出的合并策略,样式还没设置,以后再补全,优化代码去了。
参考文档:easyexcel语雀官方文档


以下补上导出合并策略
合并分向上合并以及左右合并
向上合并引用别的代码如下,加上一些注释吧

   public class ExcelFileCellMergeStrategy implements CellWriteHandler {private int[] mergeColumnIndex;//要合并的列 从0开始索引private int mergeRowIndex;//合并起始行行 从0开始索引public ExcelFileCellMergeStrategy(int[] mergeColumnIndex, int mergeRowIndex) {this.mergeColumnIndex = mergeColumnIndex;this.mergeRowIndex = mergeRowIndex;}public ExcelFileCellMergeStrategy() {}@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {}@Overridepublic void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {//当前行int curRowIndex = cell.getRowIndex();//当前列int curColIndex = cell.getColumnIndex();if (curColIndex > mergeRowIndex){for (int columnIndex : mergeColumnIndex) {if (curColIndex == columnIndex){mergeWithPrevRow(writeSheetHolder, cell ,curRowIndex, curColIndex);break;}}}}/*** 当前单元格向上合并* @param writeSheetHolder* @param cell* @param curRowIndex* @param curColIndex*/private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {//获取当前行的当前列的数据和上一行的当前列数据,通过上一行数据是否相同进行合并Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();Cell preCell = cell.getSheet().getRow(curRowIndex - 1 ).getCell(curColIndex);Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();//比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行if (curData.equals(preData)){Sheet sheet = writeSheetHolder.getSheet();List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();boolean isMerged = false;for (int i = 0; i < mergedRegions.size() && !isMerged; i++) {CellRangeAddress cellAddresses = mergedRegions.get(i);//若上 一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元if (cellAddresses.isInRange(curRowIndex - 1 , curColIndex)){sheet.removeMergedRegion(i);cellAddresses.setLastRow(curRowIndex);sheet.addMergedRegion(cellAddresses);isMerged = true;}}//若上一个单元格未被合并,则新增合并单元if (!isMerged){CellRangeAddress cellAddresses = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);sheet.addMergedRegion(cellAddresses);}}}
}

如果是左右合并的话:

CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex, curRowIndex, 0, curColIndex);

原理是一样的,只不过就是同行的前后比较,改下代码就可以了,自己debug走一遍就知道怎么改了。


以下是设置公共列宽的策略:

//列宽策略public class commonColWidthHandler extends AbstractColumnWidthStyleStrategy {private  Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);public commonColWidthHandler() {}protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);if (needSetWidth) {Map<Integer, Integer> maxColumnWidthMap = (Map)CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap == null) {maxColumnWidthMap = new HashMap(16);CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}Integer columnWidth = this.dataLength(cellDataList, cell, isHead);if (columnWidth >= 0) {if (columnWidth > 30) {columnWidth = 30;}Integer maxColumnWidth = (Integer)((Map)maxColumnWidthMap).get(cell.getColumnIndex());if (maxColumnWidth == null || columnWidth > maxColumnWidth) {((Map)maxColumnWidthMap).put(cell.getColumnIndex(), columnWidth);writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 190);}}}}private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {CellData cellData = cellDataList.get(0);CellDataTypeEnum type = cellData.getType();if (type == null) {return -1;} else {switch(type) {case STRING:return cellData.getStringValue().getBytes().length;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}}

以后还有遗漏我再补充。

easyExcel实现动态表头的数据导出,合并单元格,列宽策略相关推荐

  1. java实现excel导出合并单元格

    随着数据的不断增长,很多时候需要将数据导出到Excel中进行分析.处理和展示.而Java作为一种流行的编程语言,自然也提供了很多实现Excel导出的方法.本文将介绍如何使用Java实现Excel导出, ...

  2. aspose 换行写_Aspose.Cells 首次使用,用到模版填充数据,合并单元格,换行

    Aspose.Cells 首次使用,用到模版填充数据,合并单元格,换行 模版格式,图格式是最简单的格式,但实际效果不是这种,实际效果图如图2 image 图2 ,注意看红色部分,一对一是正常的,但是有 ...

  3. Excel催化剂开源第15波-VSTO开发之DataTable数据导出至单元格区域

    上篇提到如何从Excel界面上拿到用户的数据,另外反方向的怎样输出给用户数据,也是关键之处. VSTO最大的优势是,这双向的过程中,全程有用户的交互操作. 而一般IT型的程序,都是脱离用户的操作,只能 ...

  4. EasyExcel——采用自定义拦截器设置单元格列宽

    文章目录 前言 EasyExcel 版本 自定义拦截器 使用 前言 在EasyExcel的官方文档中,有一个自定义拦截器的配置与使用讲解. 自定义拦截器(上面几点都不符合但是要对单元格进行操作的参照这 ...

  5. EasyExcel导入、导出合并单元格excel文件

    原文地址:https://blog.csdn.net/weixin_42195311/article/details/110441885 <!--版本最好大于2.2.6,版本太低会导致没有ext ...

  6. poi导出excel,行相同数据自动合并单元格

    /***excel行自动合并*listData 待导出数据*/ public void test(SXSSFSheet sheet,List<FanManagerExt> listData ...

  7. excel格式导出合并单元格

    1.首先看一下,我们导出的模板: 可以看到,导出的模板需要合并单元格,其中在每个项目中工程编号是唯一的,所以需求中有一点,我们必选按照:项目名称+工程编号,作为唯一性来做每个sheet的区分.下面看代 ...

  8. java-easyExcel导出-合并单元格

    实现层: public ResultDto statisticalBudgetDetailExport(HttpServletResponse response, ReimbursementFormD ...

  9. 用XSSFWorkbook导出合并单元格样式的excel表格

    1.先从数据库获取将要导出的数据 2.建立一个表格 XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.cre ...

最新文章

  1. 决策树的C++实现(CART)
  2. P4269 [USACO18FEB]Snow Boots G
  3. TextBoxSuggest,输入框提示工具,输入建议,输入匹配,辅助输入,输入即时提示,文本编辑器,Visual Studio效果,高速查询引擎,哈希树,模糊匹配,百万条零毫秒
  4. Arduino ESP8266编程深入要点
  5. ELK安装配置及nginx日志分析
  6. 接触VC之四:COM组件模型基础
  7. python 文本处理2
  8. fck java_FCkjava三种调用方法
  9. bpython_Python机器学习(入门)
  10. Caffe︱构建lmdb数据集、binaryproto均值文件及各类难辨的文件路径名设置细解
  11. FLEX 2.01 全套下载!
  12. HiC软件安装篇之Lachesis
  13. python数字转英文_python:将数字转换成用英文表达的程序 | 学步园
  14. Java语言发展概述
  15. 图片地址正确但是无法显示问题
  16. python实现离散点图画法
  17. AJAX应用的演示和源码
  18. 李俊的人生病毒:靠熊猫烧香成毒王,网赌7000万二进宫!
  19. java中 ^ 是什么意思
  20. 西电-数据可视化-实验五-高维非空间数据可视化(pyecharts)

热门文章

  1. ios 地图大头针自定义显示图片 MKAnnotationView
  2. 关于复刻潮牌奢侈品的一些理解
  3. libmodbus使用说明
  4. 搬运工做起了石头生意,他的石雕产品深受喜爱
  5. npm install报错,npm WARN ajv-keywords@3.4.0 requires a peer of ajv@^6.9.1 but none is installed. You m
  6. Windows2016 PPTP配置
  7. 使用JsonEditor开源组件写了一个Json Viewer
  8. python 3d绘图kmeans_Python爬虫与K-means聚类算法分析多数据图片主色方法
  9. 国产RK3588+DSP+FPGA+AI工业视觉主板解决方案
  10. 金融直播平台有哪些?金融企业应该如何选?