最近遇到一个需求要求将excel的内容作为图片导出,经过一系列研究之后决定使用apache poi和 Graphics2D 进行导出图片。实现方案是:扫描每一行的单元格的内容然后画出对应的矩形并照着单元格的样式画图。但是由于并不是每个单元格都需要,所以要获取最小非空单元格和最大非空单元格中间的范围地址,具体如下:
导出单元格如下:
内容是使用单元格的边框画出线条,和方框组成一个树形图。其他单元格内容为空背景是白色如果使用 “Sheet.getLastRowNum()”,和“row.getLastCellNum()” 方法 返回的最大是J列和16行,很显然超出了目标单元格的范围这种方法不适用。
循环遍历单元格找出需用的部分代码如下:(注:遇到合并单元格需要特殊处理)
/**
* 获取最大非空单元格的范围
*
* @param sheet 目标sheet页面
* @return 范围地址
*/
public static CellRangeAddress getMaxNotBlankRangeAddress(XSSFSheet sheet) {
DataFormatter dataFormatter = new DataFormatter();
int maxRow = -1;
int maxCol = -1;
int minRow = -1;
int minCol = -1;
//获取合并所有单元格
List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
for (int i = 0; i < sheet.getLastRowNum(); i++) {
XSSFRow row = sheet.getRow(i);
for (int j = 0; j < row.getLastCellNum(); j++) {
XSSFCell cell = row.getCell(j);
String x = dataFormatter.formatCellValue(cell);
if (Strings.isNotBlank(x)){
CellRangeAddress address = getMergedCellRangeAddress(mergedRegions, i, j);
// 判断是否是合并单元格
if (address == null){
if (minCol==-1 || minRow == -1){
minCol = j;
minRow = i;
}else {
minCol = Math.min(minCol,j);
minRow = Math.min(minRow,i);
}
maxCol = Math.max(maxCol,j);
maxRow = Math.max(maxRow,i);
}else {
if (minCol==-1 || minRow == -1){
minCol = address.getFirstColumn();
minRow = address.getFirstRow();
}else {
minCol = Math.min(minCol,address.getFirstColumn());
minRow = Math.min(minRow,address.getFirstRow());
}
maxCol = Math.max(maxCol,address.getLastColumn());
maxRow = Math.max(maxRow,address.getLastRow());
}
}
}
}
return new CellRangeAddress(minRow, maxRow, minCol, maxCol);
}
// 获取合并单元格地址
static private CellRangeAddress getMergedCellRangeAddress(List<CellRangeAddress> mergedRegions,int x,int y){
for (CellRangeAddress cellAddresses : mergedRegions) {
if (cellAddresses.isInRange(x, y)) {
return cellAddresses;
}
}
return null;
}