解决excel导出时超出最大行高409问题

前言:

​ 在excel表格中,规定了每行最大行高为409。如果有大文本需要显示,则会因为超过范围而被隐藏。如果是在本地操作excel,可以通过合并单元格来增加行高,打破409行高限制。参考此种方式,得出poi导出excel时的操作方式,先看最终方案。

image-20240418163726608

最终方案:

  1. 在模板中的大文本单元格后面,增加备用行,把备用行与大文本那一行合并
  2. 判断大文本单元格要显示的文字是否超出默认行高能显示的文字(自行根据实际情况判断)
  3. 默认高度如果不够显示大文本,则增加备用行的行高,直到判断能显示完整

过程中遇到的问题:

  1. 每行高度最大409,设置1000也没用,excel只显示到409。
  2. 按模板填充的excel导出,无法在导出过程中添加新的行。因为poi只能在最后一行的后面添加,中间插入会行号重复(报错)。这导致想要在导出过程中增加行,然后再合并单元格,打破409界限的方案走不通。
  3. 如何根据文字长度,判断需要的行高。这个只能结合实际情况去判断,影响因素有很多。

以下,是通过EasyExcel生成excel时,打破409行高限制的操作。通过AbstractColumnWidthStyleStrategy,重写单元格样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.List;

/**
* 解决excel自动行高问题(维保报告sheet2专用)
* 问题:
* 1.excel单行最大行高为409
* 2.excel合并单元格后不支持自动适应行高
* 3.使用easy-excel模板填充,不支持在行中间插入行,因为poi行号不能重复
* 解决方案:
* 1.在模板中可能超出409行高的行下面插入预留行,将预留行与之合并
* 2.通过计算该行文字长度和列宽能显示的字数,得出需要多少行展示
* 3.设置文字行的行高,还不够显示就设置预留行行高,直到能显示完整
*
* @author liji
*/
public class Sheet2RowHeightStyleStrategy extends AbstractColumnWidthStyleStrategy {
// excel最大行高
private static final short MAX_HEIGHT = 410;
// 大文本开头的一些字符
private final String cx;

public Sheet2RowHeightStyleStrategy(String cx) {
this.cx = cx;
}

@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
// 判断可能超出409行高的单元格内容
boolean isTrue = cell.getStringCellValue().startsWith(cx);
if (!isTrue) {
return;
}
Row row = cell.getRow();
Sheet sheet = writeSheetHolder.getCachedSheet();
int rows = shouldCreateNewRow(cell);
for (int i = 1; i <= rows; i++) {
//根据模板中的预留行数判断
if (i > 3) {
return;
}

//最后一行,微调样式
if (i == 3) {
sheet.getRow(row.getRowNum() + (i - 1)).setHeightInPoints(MAX_HEIGHT - 200);
} else {
sheet.getRow(row.getRowNum() + (i - 1)).setHeightInPoints(MAX_HEIGHT);
}
}
}

/**
* 该方法获取需要增高几行,根据自己情况而定
* 拓展:
* 可拓展为按单元格样式去计算
*/
private int shouldCreateNewRow(Cell cell) {
// 根据你的业务需求来判断是否需要新增行
if (cell == null) {
return 0;
}
String value = cell.getStringCellValue();
if (!value.startsWith(cx)) {
return 0;
}
//预估每行显示45个字符,得到行数
int line = value.length() / 43;
//预估行数大于16行,则需要扩大行高
if (line < 16) {
return 0;
}
//预估409高度可显示20行,除以20得出需要增高几行
return line / 20;
}
}