700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > easyExcel实现动态表头的数据导出 合并单元格 列宽策略

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

时间:2022-05-21 19:16:29

相关推荐

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

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;}}}}}

以后还有遗漏我再补充。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。