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

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

3.原因分析:
首先可以直观的看到excel进行数据插入并自动换行的时候,换行的数据并没有按照上一行的样式进行自动合并。
于是便想着用代码把这几列手动合并,然后再加上边框样式就可以解决了。
4.解决方案:
- 需要注意的是,按照以上的思路,直接进行单元格合并,然后加上边框并不能直接解决问题。
- 需要将后边空的每一个单元格先创建出来,然后将其一块合并才可以解决,创建单元格代码在下方
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单元格合并内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!