1.项目场景:

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

2.问题描述

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

3.原因分析:

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

4.解决方案:

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

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

public static void outExcelBalance(String modelFile, String newFile, Map<String, Object> map, List<FillDataExpense> fillData, HttpServletResponse response, String fileName){
        //定义model模板中默认的行数
        int firstRow = 7; //excel中表示第八行,即模板中默认的一条
        int lastRow = 7;
        InputStream is = null;
        File file = new File(modelFile);
        File file1 = new File(newFile);
        //String file1Name = file1.getName();
        BufferedInputStream bis = null;
        try {
            if (!file.exists()) {
                copyFileUsingJava7Files(file, file1);
            }

            //TODO 单元格样式
            Set<Integer> rowsBorderSet= new HashSet<>();
            CustomCellWriteHandler customCellWriteHandler = null;

            //TODO 单元格合并
            List<CellRangeAddress> cellRangeAddresss = new ArrayList<>();

            if (ListUtils.isNotNull(fillData)){
                if (fillData.size() > 1){
                    //合并每条报销单的第3-10列
                    for (int i = 1; i < fillData.size(); i  ) {
                        firstRow  ;
                        lastRow  ;

                        cellRangeAddresss.add(new CellRangeAddress(firstRow, lastRow, 2, 9));
                        cellRangeAddresss.add(new CellRangeAddress(firstRow, lastRow, 10, 11));

                        rowsBorderSet.add(firstRow);
                    }
                }
            }
            customCellWriteHandler = new CustomCellWriteHandler(rowsBorderSet);
            MyMergeStrategy myMergeStrategy = new MyMergeStrategy(cellRangeAddresss);

            ExcelWriter excelWriter = EasyExcel.write(newFile)
                    //注册单元格式
                    .registerWriteHandler(customCellWriteHandler)
                    //注册合并策略
                    .registerWriteHandler(myMergeStrategy)
                    .withTemplate(modelFile).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            if (!ListUtil.listIsEmpty(fillData)){
                excelWriter.fill(fillData, fillConfig, writeSheet);
                //excelWriter.fill(fillData, fillConfig, writeSheet);
            }
            excelWriter.fill(map, writeSheet);
            excelWriter.finish();
            response.setHeader("content-type", "text/plain");
            response.setHeader("content-type", "application/x-msdownload;");
            response.setContentType("text/plain; charset=utf-8");
            response.setHeader("Content-Disposition", "attachment; filename="   new String(fileName.getBytes("utf-8"),"ISO8859-1"));
            byte[] buff = new byte[1024];

            OutputStream os = null;
            os = response.getOutputStream();
            bis = new BufferedInputStream(new FileInputStream(file1));
            int i = bis.read(buff);

            while (i != -1) {
                os.write(buff, 0, buff.length);
                os.flush();
                i = bis.read(buff);
            }
        }
        catch (Exception e){
            LOGGER.error(e.getMessage());
        }
        finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 删除生成文件
                /*if (file1.exists()) {
                    file1.delete();
                }*/
        }
    }

单元格合并MyMergeStrategy类代码:

public class MyMergeStrategy extends AbstractMergeStrategy {

    //合并坐标集合
    private List<CellRangeAddress> cellRangeAddresss;

    //构造
    public MyMergeStrategy(List<CellRangeAddress> cellRangeAddresss) {
        this.cellRangeAddresss = cellRangeAddresss;
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
        if (ListUtils.isNotNull(cellRangeAddresss)) {
            if (cell.getRowIndex() == 7 ) {
                for (CellRangeAddress item : cellRangeAddresss) {
                    sheet.addMergedRegionUnsafe(item);
                }
            }
        }
    }
}

单元格样式CustomCellWriteHandler类代码:

public class CustomCellWriteHandler implements CellWriteHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class);

    //标黄行宽集合
    private Set<Integer> rowIndexs;

    //构造
    public CustomCellWriteHandler(Set<Integer> rowIndexs) {
        this.rowIndexs = rowIndexs;
    }

    public CustomCellWriteHandler() {
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
        LOGGER.info("beforeCellCreate~~~~");
    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        LOGGER.info("afterCellCreate~~~~");
    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

          //获取工作簿
//        HSSFWorkbook wb = new HSSFWorkbook();
//        //获取sheet
//        HSSFSheet sheet = wb.createSheet();
//        HSSFRow row = sheet.createRow();
//        HSSFCellStyle style = wb.createCellStyle();

        // 这里可以对cell进行任何操作
        if (CollectionUtils.isNotEmpty(rowIndexs)) {
            Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
            CellStyle cellStyle = workbook.createCellStyle();

            Sheet sheet = writeSheetHolder.getSheet();
            cellStyle.setAlignment(new HSSFWorkbook().createCellStyle().getAlignment());
            cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
            cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
            cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
            cellStyle.setBorderTop(BorderStyle.THIN);//上边框
            cellStyle.setBorderRight(BorderStyle.THIN);//右边框
            cellStyle.setWrapText(true);//自动换行

            //字体
//            Font cellFont = workbook.createFont();
//            cellFont.setBold(true);
//            cellStyle.setFont(cellFont);
//            //标黄,要一起设置
//            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); //设置前景填充样式
//            cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());//前景填充色

            if (rowIndexs.contains(cell.getRowIndex())) {
                Row row = null;
                //循环创建空白单元格
                for (int i = 0; i < rowIndexs.size(); i  ) {
                    for (Integer rowIndex : rowIndexs){
                        //创建4-10列的空白格
                        row = sheet.getRow(rowIndex.intValue());
                        if (row == null){
                            row = sheet.createRow(rowIndex.intValue());
                        }
                        for (int j = 3; j <= 9; j  ) {
                            //获取8行的cell列
                            cell = row.createCell(j);
                            cell.setCellStyle(cellStyle);
                            cell.setCellValue(" ");
                            LOGGER.info("第{}行,第{}列创建空白格。", cell.getRowIndex(), j);
                        }
                        //创建12列的红白格
                        cell = row.createCell(11);
                        cell.setCellStyle(cellStyle);
                        cell.setCellValue(" ");
                        LOGGER.info("第{}行,第11列创建空白格。", cell.getRowIndex());
                        //创建21列的空白格
                        cell = row.createCell(21);
                        cell.setCellStyle(cellStyle);
                        cell.setCellValue(" ");
                        LOGGER.info("第{}行,第21列创建空白格。", cell.getRowIndex());
                    }
                }
            }
        }
    }
}

5.总结

核心步骤:

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

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

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

总结

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

Java使用EasyExcel进行单元格合并的问题详解的更多相关文章

  1. html5教你做炫酷的碎片式图片切换 (canvas)

    本篇文章主要介绍了html5教你做炫酷的碎片式图片切换 (canvas) ,具有一定参考价值,有兴趣的可以了解一下

  2. ios – 如何将UICollectionViewCell从一个UICollectionView拖到另一个UICollectionView?

    如果是这样,我将如何实施它?

  3. xcode – 在自定义表视图单元格中嵌入集合视图

    我有一个故事板的图像,你可以看到自定义表格单元格然后底部是一个集合视图,我想填充图像–只是不知道如何?我也不确定哪些信息可能会有所帮助,所以如果有信息遗失,我很抱歉.解决方法您应该将UICollectionView的Delagate和DataSource放在自定义UITableViewCell类中.这是一个nicetutorial.它是关于tableview单元格中的tableview,但这个想法非常相似.祝好运!

  4. ios – 使用动态单元格高度时,将表格视图滚动到底部

    使用动态单元格高度时,如何将表格视图滚动到底部?出于某种原因,此代码在此方案中不起作用:谢谢!

  5. ios – 渲染模式设置为图像目录中的矢量pdf模板,但UIImageView不会在自定义单元格中设置图像

    我已将所有图像文件迁移到资产目录.所有这些都是大小为1x的pdf向量.它们设置为呈现为模板.它们在大小和颜色方面都显得很好.但是有一个来自xib的自定义TableViewCell,我有6个UIImageView链接到目录中的6个这些图像.不知何故,他们不尊重色调,既不是默认也不是自定义.尝试以编程方式更改它们,但也没有工作.这些相同的图像在主故事板内的静态单元格的另一个tableview中显示正常

  6. ios – 我的表视图在滚动时在SWIFT中重用所选单元格

    实例变量

  7. ios – 带图像而不是标题的UITableViewRowAction

    可以告诉我如何解决它,或者其他方式来做到这一点?

  8. iOS – 自定义表格单元格不是UITableView的全宽度

    我可能会犯这个错误.所以我创建了一个UITableView,它基本上有一个设置为主视图的自动布局尾随空间.我正在为这个表创建一个自定义单元格,所以我在原型单元格上进行了定制,定制了它,并为它创建了我的类.这一切都很好.我似乎无法解决的是自定义单元格不是实际表格单元格的全宽,因此只显示白色背景.如果我不使用自定义单元格,则可以使用整个宽度表单元格.我为单元格内容设置了约束,以便背景图像填充单元格.我究竟做错了什么?

  9. UITableViewCellAccessoryCheckmark涵盖iOS 7上的单元格分隔符

    在iOS7上使用此代码会导致分隔符视图被覆盖或缩短:如何修复分隔符视图?

  10. ios – 在UITableviewcell swift中设置水平渐变

    我想在每个单元格上从左到右创建一个水平渐变我使用CAGradientLayey创建自定义图层并将此图层添加到tableview单元格这是我在swift中的代码但是渐变并不覆盖所有tableview单元格,它在渐变单元格和正常单元格背景颜色之间切换,似乎渐变覆盖了单元格文本.我不知道我做错了什么有什么建议吗?谢谢解决方法而不是使用框架,使用单元格的边界,也在索引0处插入子图层,因此它将落后于包括您的标签在内的所有其他图层

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部