经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Java使用EasyExcel进行单元格合并的问题详解
来源:jb51  时间:2022/6/20 12:22:31  对本文有异议

1.项目场景:

简介:报销单导出要根据指定的excel模板去自动替换对应,然后重新生成一份新的excel。在给定的excel模板中,有部分字段进行了单元格合并,如下所示。

2.问题描述

由于一张报销单可能存在多条报销内容,可以看到,当超过模板中预先给定的一条时,则会自动换行,但换行时并不会自动依照模板中的样式进行单元格合并,如下所示。

3.原因分析:

首先可以直观的看到excel进行数据插入并自动换行的时候,换行的数据并没有按照上一行的样式进行自动合并。
于是便想着用代码把这几列手动合并,然后再加上边框样式就可以解决了。

4.解决方案:

  1. 需要注意的是,按照以上的思路,直接进行单元格合并,然后加上边框并不能直接解决问题。
  2. 需要将后边空的每一个单元格先创建出来,然后将其一块合并才可以解决,创建单元格代码在下方CustomCellWriteHandler类中说明。

这也算是耗费一整天时间踩的坑。。。

  1. public static void outExcelBalance(String modelFile, String newFile, Map<String, Object> map, List<FillDataExpense> fillData, HttpServletResponse response, String fileName){
  2. //定义model模板中默认的行数
  3. int firstRow = 7; //excel中表示第八行,即模板中默认的一条
  4. int lastRow = 7;
  5. InputStream is = null;
  6. File file = new File(modelFile);
  7. File file1 = new File(newFile);
  8. //String file1Name = file1.getName();
  9. BufferedInputStream bis = null;
  10. try {
  11. if (!file.exists()) {
  12. copyFileUsingJava7Files(file, file1);
  13. }
  14.  
  15. //TODO 单元格样式
  16. Set<Integer> rowsBorderSet= new HashSet<>();
  17. CustomCellWriteHandler customCellWriteHandler = null;
  18.  
  19. //TODO 单元格合并
  20. List<CellRangeAddress> cellRangeAddresss = new ArrayList<>();
  21.  
  22. if (ListUtils.isNotNull(fillData)){
  23. if (fillData.size() > 1){
  24. //合并每条报销单的第3-10列
  25. for (int i = 1; i < fillData.size(); i++) {
  26. firstRow++;
  27. lastRow++;
  28.  
  29. cellRangeAddresss.add(new CellRangeAddress(firstRow, lastRow, 2, 9));
  30. cellRangeAddresss.add(new CellRangeAddress(firstRow, lastRow, 10, 11));
  31.  
  32. rowsBorderSet.add(firstRow);
  33. }
  34. }
  35. }
  36. customCellWriteHandler = new CustomCellWriteHandler(rowsBorderSet);
  37. MyMergeStrategy myMergeStrategy = new MyMergeStrategy(cellRangeAddresss);
  38.  
  39. ExcelWriter excelWriter = EasyExcel.write(newFile)
  40. //注册单元格式
  41. .registerWriteHandler(customCellWriteHandler)
  42. //注册合并策略
  43. .registerWriteHandler(myMergeStrategy)
  44. .withTemplate(modelFile).build();
  45. WriteSheet writeSheet = EasyExcel.writerSheet().build();
  46. FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
  47. if (!ListUtil.listIsEmpty(fillData)){
  48. excelWriter.fill(fillData, fillConfig, writeSheet);
  49. //excelWriter.fill(fillData, fillConfig, writeSheet);
  50. }
  51. excelWriter.fill(map, writeSheet);
  52. excelWriter.finish();
  53. response.setHeader("content-type", "text/plain");
  54. response.setHeader("content-type", "application/x-msdownload;");
  55. response.setContentType("text/plain; charset=utf-8");
  56. response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes("utf-8"),"ISO8859-1"));
  57. byte[] buff = new byte[1024];
  58.  
  59. OutputStream os = null;
  60. os = response.getOutputStream();
  61. bis = new BufferedInputStream(new FileInputStream(file1));
  62. int i = bis.read(buff);
  63.  
  64. while (i != -1) {
  65. os.write(buff, 0, buff.length);
  66. os.flush();
  67. i = bis.read(buff);
  68. }
  69. }
  70. catch (Exception e){
  71. LOGGER.error(e.getMessage());
  72. }
  73. finally {
  74. if (bis != null) {
  75. try {
  76. bis.close();
  77. } catch (IOException e) {
  78. e.printStackTrace();
  79. }
  80. }
  81. // 删除生成文件
  82. /*if (file1.exists()) {
  83. file1.delete();
  84. }*/
  85. }
  86. }

单元格合并MyMergeStrategy类代码:

  1. public class MyMergeStrategy extends AbstractMergeStrategy {
  2.  
  3. //合并坐标集合
  4. private List<CellRangeAddress> cellRangeAddresss;
  5.  
  6. //构造
  7. public MyMergeStrategy(List<CellRangeAddress> cellRangeAddresss) {
  8. this.cellRangeAddresss = cellRangeAddresss;
  9. }
  10.  
  11. @Override
  12. protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
  13. if (ListUtils.isNotNull(cellRangeAddresss)) {
  14. if (cell.getRowIndex() == 7 ) {
  15. for (CellRangeAddress item : cellRangeAddresss) {
  16. sheet.addMergedRegionUnsafe(item);
  17. }
  18. }
  19. }
  20. }
  21. }

单元格样式CustomCellWriteHandler类代码:

  1. public class CustomCellWriteHandler implements CellWriteHandler {
  2. private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class);
  3.  
  4. //标黄行宽集合
  5. private Set<Integer> rowIndexs;
  6.  
  7. //构造
  8. public CustomCellWriteHandler(Set<Integer> rowIndexs) {
  9. this.rowIndexs = rowIndexs;
  10. }
  11.  
  12. public CustomCellWriteHandler() {
  13. }
  14.  
  15. @Override
  16. public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
  17. LOGGER.info("beforeCellCreate~~~~");
  18. }
  19.  
  20. @Override
  21. public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
  22. LOGGER.info("afterCellCreate~~~~");
  23. }
  24.  
  25. @Override
  26. public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
  27.  
  28. }
  29.  
  30. @Override
  31. public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
  32.  
  33. //获取工作簿
  34. // HSSFWorkbook wb = new HSSFWorkbook();
  35. // //获取sheet
  36. // HSSFSheet sheet = wb.createSheet();
  37. // HSSFRow row = sheet.createRow();
  38. // HSSFCellStyle style = wb.createCellStyle();
  39.  
  40. // 这里可以对cell进行任何操作
  41. if (CollectionUtils.isNotEmpty(rowIndexs)) {
  42. Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
  43. CellStyle cellStyle = workbook.createCellStyle();
  44.  
  45. Sheet sheet = writeSheetHolder.getSheet();
  46. cellStyle.setAlignment(new HSSFWorkbook().createCellStyle().getAlignment());
  47. cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
  48. cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
  49. cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
  50. cellStyle.setBorderTop(BorderStyle.THIN);//上边框
  51. cellStyle.setBorderRight(BorderStyle.THIN);//右边框
  52. cellStyle.setWrapText(true);//自动换行
  53.  
  54. //字体
  55. // Font cellFont = workbook.createFont();
  56. // cellFont.setBold(true);
  57. // cellStyle.setFont(cellFont);
  58. // //标黄,要一起设置
  59. // cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); //设置前景填充样式
  60. // cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());//前景填充色
  61.  
  62. if (rowIndexs.contains(cell.getRowIndex())) {
  63. Row row = null;
  64. //循环创建空白单元格
  65. for (int i = 0; i < rowIndexs.size(); i++) {
  66. for (Integer rowIndex : rowIndexs){
  67. //创建4-10列的空白格
  68. row = sheet.getRow(rowIndex.intValue());
  69. if (row == null){
  70. row = sheet.createRow(rowIndex.intValue());
  71. }
  72. for (int j = 3; j <= 9; j++) {
  73. //获取8行的cell列
  74. cell = row.createCell(j);
  75. cell.setCellStyle(cellStyle);
  76. cell.setCellValue(" ");
  77. LOGGER.info("第{}行,第{}列创建空白格。", cell.getRowIndex(), j);
  78. }
  79. //创建12列的红白格
  80. cell = row.createCell(11);
  81. cell.setCellStyle(cellStyle);
  82. cell.setCellValue(" ");
  83. LOGGER.info("第{}行,第11列创建空白格。", cell.getRowIndex());
  84. //创建21列的空白格
  85. cell = row.createCell(21);
  86. cell.setCellStyle(cellStyle);
  87. cell.setCellValue(" ");
  88. LOGGER.info("第{}行,第21列创建空白格。", cell.getRowIndex());
  89. }
  90. }
  91. }
  92. }
  93. }
  94. }

5.总结

核心步骤:

  1. 1.
  2. //创建单元格样式
  3. CustomCellWriteHandler customCellWriteHandler = new CustomCellWriteHandler(参数按需给定);
  4. 2.
  5. //单元格进行合并
  6. List<CellRangeAddress> cellRangeAddresss = new ArrayList<>();
  7. //例如:从firstRow行到lastRow行的2列到9列合并
  8. cellRangeAddresss.add(new CellRangeAddress(firstRow, lastRow, 2, 9));
  9. cellRangeAddresss.add(new CellRangeAddress(firstRow, lastRow, 10, 11));
  10. MyMergeStrategy myMergeStrategy = new MyMergeStrategy(cellRangeAddresss);
  11. 3.
  12. //注册以上两种策略
  13. ExcelWriter excelWriter = EasyExcel.write(newFile)
  14. //注册单元格式
  15. .registerWriteHandler(customCellWriteHandler)
  16. //注册合并策略
  17. .registerWriteHandler(myMergeStrategy)
  18. .withTemplate(modelFile).build();
  19.  

说明:刚开始修复的时候,并没有想过后边每个空的单元格需要先创建出来,才可以进行合并。一直以为是工具类的问题,后来不断的翻阅解决方案,看到有说需要先进行创建空白单元格,然后再进行合并,最终完美解决了。

关于代码部分,由于是业务代码,中间夹杂了许多不需要的。

总结

到此这篇关于Java使用EasyExcel进行单元格合并的文章就介绍到这了,更多相关EasyExcel单元格合并内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号