EasyExcel自定义设置Excel表格宽高

pom

java 复制代码
<properties>
<java.version>1.8</java.version>
<easyexcel.version>3.3.2</easyexcel.version>
<poi.version>5.2.3</poi.version>
</properties>

<!-- easyexcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>${easyexcel.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>${poi.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>${poi.version}</version>
</dependency>

CustomCellWriteHeightConfig

java 复制代码
import com.alibaba.excel.write.handler.context.RowWriteHandlerContext;
import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.util.ObjectUtils;

import java.util.Iterator;
/**
 * 自定义设置Excel表格行高的配置类。
 * 该类继承了AbstractRowHeightStyleStrategy,通过内容的长度来动态调整行高。
 *
 * <p>默认行高为40。对于字符串内容,按每10个字符添加换行,以计算所需的行数并设置相应的高度。
 *
 * @author Lance
 * @since 2024-11-13 15:29:30
 */
public class CustomCellWriteHeightConfig extends AbstractRowHeightStyleStrategy {

    /**
     * 默认高度
     */
    private static final Integer DEFAULT_HEIGHT = 50;

    /**
     * 设置表头的行高
     * @param row 当前行对象
     * @param relativeRowIndex 当前行的相对索引
     */
    @Override
    protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
        // 默认实现为空,可根据需要自定义表头行高
    }

    /**
     * 根据内容设置数据行的行高。
     * @param row 当前行对象
     * @param relativeRowIndex 当前行的相对索引
     */
    @Override
    protected void setContentColumnHeight(Row row, int relativeRowIndex) {
        Iterator<Cell> cellIterator = row.cellIterator();
        if (!cellIterator.hasNext()) {
            return;
        }

        // 初始化最大行高为1行高度
        int maxHeight = 1;

        // 遍历行中的每个单元格
        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();
            if (cell.getCellType() == CellType.STRING) {
                // 处理字符串类型的单元格内容
                String value = cell.getStringCellValue();

                // 每10个字符添加换行符,以便计算所需行数
                for (int i = 0; i < value.length(); i += 10) {
                    if (i + 10 < value.length()) {
                        value = value.substring(0, i) + "\n" + value.substring(i, i + 10) + value.substring(i + 10);
                    } else {
                        value = value.substring(0, i) + "\n" + value.substring(i);
                    }
                }

                // 计算换行后的行数,以确定行高
                if (value.contains("\n")) {
                    int length = value.split("\n").length;
                    maxHeight = Math.max(maxHeight, length);
                }
            }
        }

        // 根据最大行高设置当前行的高度
        row.setHeight((short) (maxHeight * DEFAULT_HEIGHT));
    }

    /**
     * 在行处理完成后根据行类型设置行高。
     * @param context 行写入的上下文,包含行和相对索引信息
     */
    @Override
    public void afterRowDispose(RowWriteHandlerContext context) {
        if (context.getHead() != null) {
            if (ObjectUtils.isEmpty(context.getRelativeRowIndex())) {
                return;
            }
            // 根据行是否为表头调用相应的行高设置方法
            if (Boolean.TRUE.equals(context.getHead())) {
                this.setHeadColumnHeight(context.getRow(), context.getRelativeRowIndex());
            } else {
                this.setContentColumnHeight(context.getRow(), context.getRelativeRowIndex());
            }
        }
    }
}

CustomCellWriteWidthConfig

java 复制代码
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
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.Sheet;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 自定义设置Excel表格列宽的配置类。
 * 该类继承了AbstractColumnWidthStyleStrategy,通过内容的长度来动态调整列宽。
 *
 * <p>列宽设置最大为20字符,最小为10字符。宽度值被缓存,以避免每列重复计算,提高性能。
 *
 * @author Lance
 * @since 2024-11-13 15:29:30
 */
public class CustomCellWriteWidthConfig extends AbstractColumnWidthStyleStrategy {

    // 缓存每个工作表和列的最大宽度,以优化性能
    private final Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

    /**
     * 根据内容长度设置列宽,最大为20字符。
     *
     * @param writeSheetHolder 工作表的元数据
     * @param cellDataList     单元格数据对象列表
     * @param cell             当前处理的单元格
     * @param head             列的头部信息
     * @param integer          未使用的参数
     * @param isHead           布尔值,指示当前单元格是否为表头
     */
    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
        // 判断是否需要设置列宽
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            // 获取或初始化当前工作表的宽度缓存
            Map<Integer, Integer> maxColumnWidthMap = CACHE.computeIfAbsent(writeSheetHolder.getSheetNo(), k -> new HashMap<>());
            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);

            // 在指定范围内设置列宽
            if (columnWidth > 0) {
                if (columnWidth > 10) {
                    columnWidth = 20;  // 超过阈值时设置为最大宽度
                } else {
                    columnWidth = 10;  // 设置最小宽度
                }

                // 获取当前列的最大宽度(如果已经设置)
                Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
                // 如果新宽度超过当前最大值或尚未设置最大宽度,则更新
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                    // 在工作表中设置宽度,字符间距进行适当调整
                    Sheet sheet = writeSheetHolder.getSheet();
                    sheet.setColumnWidth(cell.getColumnIndex(), 256 * columnWidth + 184);
                }
            }
        }
    }

    /**
     * 计算单元格内容的长度,用于确定列宽。
     *
     * @param cellDataList 单元格数据对象列表(用于非表头单元格)
     * @param cell         当前处理的单元格
     * @param isHead       布尔值,指示当前单元格是否为表头
     * @return 单元格内容的计算长度
     */
    private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            // 返回表头单元格内容的字节长度
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData<?> cellData = cellDataList.get(0); // 获取列表中的第一个数据项
            CellDataTypeEnum type = cellData.getType(); // 获取单元格数据类型

            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        // 处理换行符,计算到第一个换行符为止的长度
                        int index = cellData.getStringValue().indexOf("\n");
                        return index != -1 ?
                                cellData.getStringValue().substring(0, index).getBytes().length + 1
                                : cellData.getStringValue().getBytes().length + 1;
                    case BOOLEAN:
                        // 布尔类型内容的长度
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        // 数字类型内容的长度
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
}

ExcelUtil

java 复制代码
    public <T> void download(HttpServletResponse response, String name, Class<T> clazz, List<T> list) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode(name, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        EasyExcel.write(response.getOutputStream(), clazz)
                .registerWriteHandler(new CustomCellWriteHeightConfig())
                .registerWriteHandler(new CustomCellWriteWidthConfig())
                .sheet("模板").doWrite(list);
    }

Test

java 复制代码
download(response, "订单信息", DimTrackingOrderExcel.class, dimTrackingOrderExcels);

DimTrackingOrderExcel

java 复制代码
@Data
public class DimTrackingOrderExcel implements Serializable {
    
    private static final long serialVersionUID = 1L;

    @ExcelProperty(value = "联系人姓名")
    private String postReceiver;

    @ExcelProperty(value = "联系人电话")
    private String postTel;

    @ExcelProperty(value = "收货详细地址")
    private String detail;

    @ExcelProperty(value = "外部订单号")
    private String id;
}
相关推荐
zjw_rp22 分钟前
Spring-AOP
java·后端·spring·spring-aop
Oneforlove_twoforjob35 分钟前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
TodoCoder43 分钟前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
向宇it1 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行1 小时前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
星河梦瑾2 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富2 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想2 小时前
JMeter 使用详解
java·jmeter
言、雲2 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇2 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表