Bootstrap

【EasyExcel】根据单元格内容自动调整列宽

1.自定义Excel列宽样式策略类

import com.alibaba.excel.enums.CellDataTypeEnum;
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.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 自定义Excel列宽样式策略类,用于根据单元格内容自动调整列宽。
 * 继承自 AbstractColumnWidthStyleStrategy 以提供列宽调整功能。
 */
public class ExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {

    // 定义单元格最大列宽,避免列宽过大
    private static final int MAX_COLUMN_WIDTH = 30;
    // 缓存每个sheet中每列的最大列宽
    private final Map<Integer, Map<Integer, Integer>> columnWidthCache = new HashMap<>(8);

    /**
     * 设置列宽的方法,根据单元格内容的长度动态调整列宽。
     *
     * @param writeSheetHolder 写入Sheet的持有者
     * @param cellDataList 当前列的单元格数据列表
     * @param cell 当前单元格
     * @param head 表头
     * @param relativeRowIndex 当前行的相对索引
     * @param isHead 是否为表头
     */
    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder,
                                  List<WriteCellData<?>> cellDataList,
                                  Cell cell,
                                  Head head,
                                  Integer relativeRowIndex,
                                  Boolean isHead) {

        // 如果是表头或者单元格数据列表不为空,则需要设置列宽
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);

        if (needSetWidth) {
            // 获取当前sheet的列宽缓存
            Map<Integer, Integer> columnWidthMap =
                    columnWidthCache.computeIfAbsent(writeSheetHolder.getSheetNo(), k -> new HashMap<>(16));

            // 计算当前单元格的数据长度
            Integer columnWidth = computeCellDataLength(cellDataList, cell, isHead);

            if (columnWidth >= 0) {
                // 确保列宽不会超过最大值
                columnWidth = Math.min(columnWidth, MAX_COLUMN_WIDTH);

                // 获取当前列的最大列宽
                Integer maxColumnWidth = columnWidthMap.get(cell.getColumnIndex());

                // 如果当前列宽大于缓存中的最大列宽,则更新缓存并设置列宽
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    columnWidthMap.put(cell.getColumnIndex(), columnWidth);
                    // 设置列宽,乘以512是因为Excel中列宽单位与字符长度有关
                    writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 512);
                }
            }
        }
    }

    /**
     * 计算单元格内容的字节长度
     *
     * @param cellDataList 当前列的单元格数据列表
     * @param cell 当前单元格
     * @param isHead 是否为表头
     * @return 单元格内容的字节长度
     */
    private Integer computeCellDataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            // 表头直接计算字符串的字节长度
            return cell.getStringCellValue().getBytes().length;
        } else {
            if (cellDataList == null || cellDataList.isEmpty()) {
                return -1; // 如果数据列表为空,则返回-1
            }
            WriteCellData<?> cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();

            if (type == null) {
                return -1; // 如果类型未知,则返回-1
            } else {
                switch (type) {
                    case STRING:
                        return cellData.getStringValue().getBytes().length;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1; // 对于其他类型,返回-1
                }
            }
        }
    }
}

2.使用策略

        excelWriter.write(ExcelData, EasyExcel.writerSheet(sheetName)
                    .head(Product.class)
                    .registerWriteHandler(new ExcelWidthStyleStrategy())
                    .build());
;