Java 导出Excel根据单元格内容计算并设置列宽度、行高

发布时间 2023-10-11 17:54:44作者: ヤBig、Bossづ

话不多说,上代码:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 根据单元格内容计算并设置列宽度、行高
 */
public class ExcelUtil {

    // sheet.setColumnWidth()参数的单位是1/256个字符宽度,这里使用300计算用于保留部分空白位置
    public static final Integer CELL_CARDINAL = 300;

    /**
     * 根据单元格内容计算并设置列宽度
     *
     * @param sheet           需要设置的Sheet对象
     * @param cellValue       单元格内容
     * @param cellIndex       单元格下标
     * @param allCellWidthMap 所有需要设定的单元格列宽度
     * @return 所有需要设定的单元格列宽度
     */
    public static Map<Integer, Integer> setCellWidth(Sheet sheet, String cellValue, int cellIndex, Map<Integer, Integer> allCellWidthMap) {
        if (StringUtils.isBlank(cellValue)) {
            return allCellWidthMap;
        }
        // 根据单元格内容计算宽度
        Integer cellWidth = cellValue.getBytes().length * CELL_CARDINAL;
        // 限定最大宽度
        int maxCellWidth = 60 * CELL_CARDINAL;
        Integer oldCellWidth = allCellWidthMap.get(cellIndex);
        if (Objects.nonNull(oldCellWidth)) {
            // 当前宽度不超过已设定宽度时,保留原宽度
            if (oldCellWidth > cellWidth) {
                cellWidth = oldCellWidth;
            }
            // 宽度超过最大限度时,使用最大宽度限度
            // 如果需要全部展示单元格内容可使用setWrapText(true)设置单元格自动换行
            if (cellWidth > maxCellWidth) {
                cellWidth = maxCellWidth;
            }
        }
        sheet.setColumnWidth(cellIndex, cellWidth);
        allCellWidthMap.put(cellIndex, cellWidth);
        return allCellWidthMap;
    }

    /**
     * 设置并获取单元格样式
     *
     * @param workbook
     * @return 单元格样式
     */
    public static CellStyle getCellStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        // 左对齐
        //style.setAlignment(HorizontalAlignment.LEFT);
        // 居中
        style.setAlignment(HorizontalAlignment.CENTER);
        /*//设置解析格式
        DataFormat format = workbook.createDataFormat();
        style.setDataFormat(format.getFormat("@"));*/
        // 自动换行
        style.setWrapText(true);
        /*// 设置背景色
        style.setFillForegroundColor(IndexedColors.RED.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);*/
        /*// 单元格是否锁定
        style.setLocked(false);*/
        return style;
    }

    /**
     * 根据单元格内容计算并设置行高
     *
     * @param sourceRow
     */
    public static void setRowHeight(Row sourceRow) {
        double maxHeight = sourceRow.getHeight();
        for (int cellIndex = sourceRow.getFirstCellNum(); cellIndex <= sourceRow.getPhysicalNumberOfCells(); cellIndex++) {
            if (cellIndex < 0) {
                continue;
            }
            Cell sourceCell = sourceRow.getCell(cellIndex);
            String cellContent = getCellContentAsString(sourceCell);
            if (StringUtils.isBlank(cellContent)) {
                continue;
            }
            //单元格的宽高及单元格信息
            Map<String, Object> cellInfoMap = getCellInfo(sourceCell);
            Integer cellWidth = (Integer) cellInfoMap.get("width");
            Integer cellHeight = (Integer) cellInfoMap.get("height");
            if (cellHeight > maxHeight) {
                maxHeight = cellHeight;
            }
            //XSSFCellStyle cellStyle = sourceCell.getCellStyle();
            //XSSFFont font = cellStyle.getFont();
            //short fontHeight = font.getFontHeight();
            //int cellContentWidth = cellContent.getBytes().length * 256;
            int cellContentWidth = cellContent.getBytes().length * CELL_CARDINAL;
            int stringNeedsRows = cellContentWidth / cellWidth + 1;
            double stringNeedsHeight = (double) cellHeight * stringNeedsRows;

            if (stringNeedsHeight > maxHeight) {
                maxHeight = stringNeedsHeight;
                /*if (maxHeight / cellHeight > 5) {
                    maxHeight = 4 * cellHeight;
                }*/
                maxHeight = Math.ceil(maxHeight);
                /*Boolean isPartOfRowsRegion = (Boolean) cellInfoMap.get("isPartOfRowsRegion");
                if (isPartOfRowsRegion) {
                    Integer firstRow = (Integer) cellInfoMap.get("firstRow");
                    Integer lastRow = (Integer) cellInfoMap.get("lastRow");
                    //平均每行需要增加的行高
                    double addHeight = (maxHeight - cellHeight) / (lastRow - firstRow + 1);
                    for (int i = firstRow; i <= lastRow; i++) {
                        double rowsRegionHeight = sourceRow.getSheet().getRow(i).getHeight() + addHeight;
                        sourceRow.getSheet().getRow(i).setHeight((short) rowsRegionHeight);
                    }
                } else {
                    sourceRow.setHeight((short) maxHeight);
                }*/
            }
        }
        sourceRow.setHeight((short) maxHeight);
    }

    private static String getCellContentAsString(Cell cell) {
        if (null == cell) {
            return "";
        }
        String result = "";
        switch (cell.getCellType()) {
            case NUMERIC:
                String s = String.valueOf(cell.getNumericCellValue());
                if (s != null && s.endsWith(".0")) {
                    s = s.substring(0, s.length() - 2);
                }
                result = s;
                break;
            case STRING:
                result = String.valueOf(cell.getRichStringCellValue());
                break;
            case BLANK:
                break;
            case BOOLEAN:
                result = String.valueOf(cell.getBooleanCellValue());
                break;
            case ERROR:
                break;
            default:
                break;
        }
        return result;
    }

    private static Map<String, Object> getCellInfo(Cell cell) {
        Map<String, Object> map = new HashMap();
        Sheet sheet = cell.getSheet();
        int rowIndex = cell.getRowIndex();
        int columnIndex = cell.getColumnIndex();
        boolean isPartOfRegion = false;
        int firstColumn = 0;
        int lastColumn = 0;
        int firstRow = 0;
        int lastRow = 0;
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress c = sheet.getMergedRegion(i);
            firstColumn = c.getFirstColumn();
            lastColumn = c.getLastColumn();
            firstRow = c.getFirstRow();
            lastRow = c.getLastRow();
            if (rowIndex >= firstRow && rowIndex <= lastRow) {
                if (columnIndex >= firstColumn && columnIndex <= lastColumn) {
                    isPartOfRegion = true;
                    break;
                }
            }
        }

        Integer width = 0;
        Integer height = 0;
        boolean isPartOfRowsRegion = false;
        if (isPartOfRegion) {
            for (int i = firstColumn; i <= lastColumn; i++) {
                width += sheet.getColumnWidth(i);
            }
            for (int i = firstRow; i <= lastRow; i++) {
                if (sheet.getRow(i) == null) {
                    height += sheet.createRow(i).getHeight();
                } else {
                    height += sheet.getRow(i).getHeight();
                }
            }
            if (lastRow > firstRow) {
                isPartOfRowsRegion = true;
            }
        } else {
            width = sheet.getColumnWidth(columnIndex);
            height += cell.getRow().getHeight();
        }
        map.put("isPartOfRowsRegion", isPartOfRowsRegion);
        map.put("firstRow", firstRow);
        map.put("lastRow", lastRow);
        map.put("width", width);
        map.put("height", height);
        return map;
    }

}