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());