当前位置:   article > 正文

EasyExcel 复杂模板导出excel得坑(多个)实现将多个数据转成多个excel并放入压缩包中。_@cleanup outputstream outputstream = excelwriter.w

@cleanup outputstream outputstream = excelwriter.writecontext().writeworkboo

        最近有个需求是将多个记录转成excel然后集中到一个zip中并导出,在这样得背景下,我得研究路径是这样:

1.普通excel导出,write填写

2.多个excel集中到zip中并导出

3.模板导出excel-填充

4.复杂模板导出excel-填充

其中得经历以及坑如下

普通excel导出

        最普通得导出类似于这种(例子为下载模板)通过write方法写入excel表格并填写。

  1. public void excelTemplate(HttpServletResponse response) throws IOException {
  2. String fileName = URLEncoder.encode("test", "UTF-8");
  3. response.setContentType("application/vnd.ms-excel");
  4. response.setCharacterEncoding("utf-8");
  5. response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
  6. EasyExcel.write(response.getOutputStream(), ImportDTO.class).sheet("sheet1").doWrite(Lists.newArrayList());
  7. }
多个excel集中成zip导出

这一块得坑有:zip工具类,网上有很多利用zipUtil工具类来压缩的方法,我自己用的时候感觉不是很好用,没有深入,搜了别的方法,具体如下:

  1. public void exportExcel(HttpServletResponse response, Map<String, RecordDTO> map) throws IOException {
  2. ServletOutputStream outputStream = response.getOutputStream();
  3. ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
  4. try {
  5. for (Map.Entry<String, PdHandoverRecordDTO> entry : map.entrySet()) {
  6. String k = entry.getKey();
  7. //获取数据
  8. String Json = value.getSuccessionJson();
  9. List<PdRecordInfo> pdinfoList = getProdInfo(value.getSuccessionJson(), value.getHandoverTime().toString());//生产信息
  10. ClassPathResource classPathResource = new ClassPathResource("templates/交接班模板.xls");
  11. InputStream inputStream = classPathResource.getInputStream();
  12. //设置 自动换行
  13. FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
  14. //设置水平,垂直居中
  15. WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
  16. contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); //.registerWriteHandler(horizontalCellStyleStrategy)
  17. contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  18. HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(null, contentWriteCellStyle);
  19. //构建一个excel对象,这里注意type要是xls不能是xlsx,否则下面的写入后流会关闭,导致报错.registerWriteHandler(horizontalCellStyleStrategy)
  20. ExcelWriter excelWriter = EasyExcel.write(outputStream)
  21. .withTemplate(inputStream)
  22. .excelType(ExcelTypeEnum.XLS).build();
  23. //sheet
  24. WriteSheet writeSheet = EasyExcel.writerSheet().build();
  25. //构建excel表头信息
  26. // WriteTable writeTable0 = EasyExcel.writerTable(0).head(PdProductionRecordDTO.class).needHead(Boolean.TRUE).build();
  27. //自动换行
  28. //将表头和数据写入表格
  29. //excelWriter.write(value, writeSheet, writeTable0);
  30. //填充数据
  31. excelWriter.fill(new FillWrapper("data3",pdinfoList),writeSheet);
  32. //创建压缩文件
  33. ZipEntry zipEntry = new ZipEntry(k);
  34. zipOutputStream.putNextEntry(zipEntry);
  35. Workbook workbook = excelWriter.writeContext().writeWorkbookHolder().getWorkbook();
  36. //将excel对象以流的形式写入压缩流
  37. workbook.write(zipOutputStream);
  38. }
  39. zipOutputStream.flush();
  40. } catch (Exception e) {
  41. log.error("导XXX失败,原因" + e.getMessage());
  42. log.error(e.getMessage(), e);
  43. //抛出异常结束程序
  44. throw new BusinessException("数据导出接口异常");
  45. } finally {
  46. //关闭数据流,注意关闭的顺序
  47. zipOutputStream.close();
  48. outputStream.close();
  49. }
  50. }

代码有经过删减,完整版我会放到最后。总之这里主要是用了zipOutputStream,zipEntry来实现压缩

复杂模板导出excel-填充

这两点应该是坑最多的。正常情况下拿到数据-data后,直接excelWriter.fill()就好了,自己在模板中配置好相应位置得数据(map类型 填{xx},List类型填{.xx}//xx为属性名)。但是既然是模板导出,肯定希望导出得样式是正常得,起码不会这里缺一块,那里又缺少一块边框等等。

而这其中,涉及得就有-自动换行,合并单元格,边框样式等

自动换行: fillConfig 和 合并单元格中onceabsolutemergestrategy(进行一次单元格得合并得方法)在一起使用时 会失效!!    然后easyexcel版本3.0.5和2.1.6在填充和自动换行上很大区别,网上搜到很多都是用2.1.6来举的例子。

合并单元格:11合并单元格网上有很多方法,基本上离不开CellRangeAddress这个类

CellRangeAddress:用于合并单元格,但是普通的使用得在excelWriter.write(),而不是fill得时候使用(目前我没看到可以直接用在fill上)

所以就得找合并策略,合并策略有很多,但是咱毕竟只是用一用而已,不会深入理解,有些发的合并策略没仔细看还不会用。我这也是找的别人得,然后稍微修改了一下,应该容易理解。边框也在有注释得地方写了。自行查看

  1. package com.chem.mes.business.util;
  2. import com.alibaba.excel.metadata.Head;
  3. import com.alibaba.excel.metadata.data.CellData;
  4. import com.alibaba.excel.metadata.data.WriteCellData;
  5. import com.alibaba.excel.write.handler.CellWriteHandler;
  6. import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
  7. import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
  8. import org.apache.poi.hssf.usermodel.HSSFCellStyle;
  9. import org.apache.poi.ss.usermodel.BorderStyle;
  10. import org.apache.poi.ss.usermodel.Cell;
  11. import org.apache.poi.ss.usermodel.Row;
  12. import org.apache.poi.ss.usermodel.Sheet;
  13. import org.apache.poi.ss.util.CellRangeAddress;
  14. import org.apache.poi.ss.util.RegionUtil;
  15. import java.util.HashMap;
  16. import java.util.List;
  17. import java.util.Map;
  18. //列合并工具类
  19. public class ExcelFillCellMergePrevColUtils implements CellWriteHandler {
  20. private static final String KEY ="%s-%s";
  21. //所有的合并信息都存在了这个map里面
  22. Map<String, Integer> mergeInfo = new HashMap<>();
  23. public ExcelFillCellMergePrevColUtils() {
  24. }
  25. @Override
  26. public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
  27. }
  28. @Override
  29. public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {
  30. }
  31. public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
  32. }
  33. @Override
  34. public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
  35. //当前行
  36. int curRowIndex = cell.getRowIndex();
  37. //当前列
  38. int curColIndex = cell.getColumnIndex();
  39. //HSSFCellStyle style = writeTableHolder.cr
  40. Integer num = mergeInfo.get(String.format(KEY, curRowIndex, curColIndex));
  41. if(null != num){
  42. // 合并最后一行 ,列
  43. mergeWithPrevCol(writeSheetHolder, cell, curRowIndex, curColIndex,num);
  44. }
  45. }
  46. public void mergeWithPrevCol(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex, int num) {
  47. Sheet sheet = writeSheetHolder.getSheet();
  48. CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex, curRowIndex, curColIndex, curColIndex + num);
  49. RegionUtil.setBorderBottom(BorderStyle.THIN, cellRangeAddress, sheet);//设置边框
  50. RegionUtil.setBorderLeft(BorderStyle.THIN, cellRangeAddress, sheet);
  51. RegionUtil.setBorderRight(BorderStyle.THIN, cellRangeAddress, sheet);
  52. RegionUtil.setBorderTop(BorderStyle.THIN, cellRangeAddress, sheet);
  53. sheet.addMergedRegion(cellRangeAddress);
  54. }
  55. //num从第几列开始增加多少列,(6,2,7)代表的意思就是第6行的第2列至第2+7也就是9列开始合并
  56. // public void add (int curRowIndex, int curColIndex , int num){
  57. // mergeInfo.put(String.format(KEY, curRowIndex, curColIndex),num);
  58. // }
  59. //起始行,结束行,起始列,起始列加num列, 每一行的 curcolindex 到 curcolindex+num 进行合并。
  60. public void add(int curRowIndex,int endRowindex,int curColIndex,int num){
  61. while(curRowIndex <= endRowindex){
  62. mergeInfo.put(String.format(KEY, curRowIndex, curColIndex),num);
  63. curRowIndex++;
  64. }
  65. }
  66. //将0-4列,5-9列合并
  67. public void addall(int curRowIndex,int endRowindex,int curColIndex,int num){
  68. add(curRowIndex,endRowindex,curColIndex,num);
  69. add(curRowIndex,endRowindex,curColIndex+5,num);
  70. }
  71. }

 至于为什么说搜到的一些合并单元格策略有问题,主要是我这是复杂模板填充,要填好几个list。位置也不同,所以得对每个不同得list进行区分,具体做法就是,将模板里得{.xxx}变为{data1.xxx}

然后填充语句变为:

  1. excelWriter.fill(new FillWrapper("data2",atteList),fillConfig,writeSheet);
  2. excelWriter.fill(new FillWrapper("data1",succList),fillConfig,writeSheet);//fillConfig

类似这样,就能区分,其中fillConfig是自动换行相关策略。

有些问题做的时候记得很清楚,到写的时候就想不起来了,很烦。

言而总之,最后总算是完成了,具体代码如下,有其他问题可以评论,我看到了会回复,

具体代码如下:部分代码被我xxx掉了,别在意

  1. public void exportExcel(HttpServletResponse response, Map<String, PdRecordDTO> map) throws IOException {
  2. ServletOutputStream outputStream = response.getOutputStream();
  3. ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
  4. //设置 自动换行
  5. FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
  6. //设置水平,垂直居中
  7. WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
  8. contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); //.registerWriteHandler(horizontalCellStyleStrategy)
  9. contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  10. HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(null, contentWriteCellStyle);
  11. //创建模板
  12. ClassPathResource classPathResource = new ClassPathResource("templates/交接班模板.xls");
  13. try {
  14. for (Map.Entry<String, PdRecordDTO> entry : map.entrySet()) {
  15. String k = entry.getKey();
  16. PdRecordDTO value = entry.getValue();
  17. //合并单元格策略
  18. ExcelFillCellMergePrevColUtils excelFillCellMergePrevColUtils = new ExcelFillCellMergePrevColUtils();
  19. //获取数据
  20. try {
  21. if (!isValid(value)) {//判断数据是否合法,完整
  22. //throw new BusinessException("传入记录不合法");
  23. continue;
  24. }
  25. }catch (BusinessException e){//更离谱的不合法报错直接跳过
  26. continue;
  27. }
  28. List<SuccessorExport> succList = getSuccessorData(xxx);//接班人
  29. List<AttendantExport> atteList = getAttendtantData(xxx);//交班人
  30. List<EquipExport> bequip = getEquipData(xxx);//设备
  31. List<PdRecordInfo> pdinfoList = getProdInfo(xxx);//生产信息
  32. HandoverMessage hdm = getMessage(xxx);//安全信息
  33. InputStream inputStream = classPathResource.getInputStream();
  34. int succsize = succList.size();
  35. int attsize = atteList.size();
  36. //添加要合并的行列
  37. excelFillCellMergePrevColUtils.addall( 5,5+attsize-1, 0, 4);//模板对应位置
  38. excelFillCellMergePrevColUtils.addall( 22+succsize-1,22+succsize+attsize-2, 0, 4);
  39. //构建一个excel对象,这里注意type要是xls不能是xlsx,否则下面的写入后流会关闭,导致报错.registerWriteHandler(horizontalCellStyleStrategy)
  40. ByteArrayOutputStream tempStream = new ByteArrayOutputStream();//用不同得流对应不同得excel导出流
  41. ExcelWriter excelWriter = EasyExcel.write(tempStream)
  42. .withTemplate(inputStream)
  43. .registerWriteHandler(horizontalCellStyleStrategy)
  44. .registerWriteHandler(excelFillCellMergePrevColUtils)
  45. .excelType(ExcelTypeEnum.XLS).build();
  46. //sheet
  47. WriteSheet writeSheet = EasyExcel.writerSheet().build();
  48. //构建excel表头信息
  49. // WriteTable writeTable0 = EasyExcel.writerTable(0).head(PdRecordDTO.class).needHead(Boolean.TRUE).build();
  50. //自动换行
  51. //将表头和数据写入表格
  52. //excelWriter.write(value, writeSheet, writeTable0);
  53. //填充数据
  54. excelWriter.fill(new FillWrapper("data2",atteList),fillConfig,writeSheet);
  55. excelWriter.fill(new FillWrapper("data1",succList),fillConfig,writeSheet);//fillConfig
  56. excelWriter.fill(new FillWrapper("data4",bequip),fillConfig,writeSheet);
  57. excelWriter.fill(new FillWrapper("data3",pdinfoList),writeSheet);
  58. excelWriter.fill(hdm,writeSheet);
  59. excelWriter.fill(value, writeSheet);
  60. //创建压缩文件
  61. ZipEntry zipEntry = new ZipEntry(k);
  62. zipOutputStream.putNextEntry(zipEntry);
  63. Workbook workbook = excelWriter.writeContext().writeWorkbookHolder().getWorkbook();
  64. //将excel对象以流的形式写入压缩流
  65. workbook.write(tempStream);
  66. tempStream.writeTo(zipOutputStream);
  67. excelWriter.finish();
  68. workbook.close();
  69. tempStream.close();
  70. }
  71. zipOutputStream.flush();
  72. } catch (Exception e) {
  73. log.error("导XXX失败,原因" + e.getMessage());
  74. log.error(e.getMessage(), e);
  75. //抛出异常结束程序
  76. throw new BusinessException("数据导出接口异常");
  77. } finally {
  78. //关闭数据流,注意关闭的顺序
  79. zipOutputStream.close();
  80. outputStream.close();
  81. }
  82. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/216059
推荐阅读
相关标签
  

闽ICP备14008679号