EasyExcel模板导出

导出复杂excel遇到的一些坑

1、填充Excel时填充图片到模板中合并单元格的图片,只占一行一列,并未占满整个合并后的单元格。

2、复杂填充多个list数据数据混乱

解决:

1、EasyExcel图片填充拦截器-修改图片边距-跨行-属性等

主要就是实现了AbstractCellWriteHandler,利用EasyExcel填充的不同时期调用对应方法进行拦截处理:

在数据转换完成后(afterCellDataConverted),将单元格类型设置成EMPTY,不让EasyExcel使用其默认方式处理图片;(AbstractExcelWriteExecutor#setImageValue)
在单元格上的所有操作完成后(afterCellDispose),使用我们自定义的方式对图片处理。
————————————————
版权声明:本文为CSDN博主「IMXF_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_36349646/article/details/118896257

 

package com.hafnkj.common.config;

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.Units;

import java.util.List;
import java.util.Objects;

/**
 * EasyExcel图片填充拦截器
 *
 * @author shixf on 2021/7/19
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class ImageCellWriteHandler extends AbstractCellWriteHandler {

    /**
     * 图片行列跨度
     */
    private int colSpan = 1;
    private int rowSpan = 1;
    /**
     * 左侧和右侧边框粗细
     */
    private int borderPixelX1Y1;
    private int borderPixelX2Y2;
    /**
     * 可以随着单元格一起移动,不改变大小
     */
    private AnchorType anchorType = AnchorType.MOVE_DONT_RESIZE;


    public ImageCellWriteHandler() {
        this.borderPixelX1Y1 = 5;
        this.borderPixelX2Y2 = 5;
    }

    public ImageCellWriteHandler(int borderPixel) {
        this.borderPixelX1Y1 = borderPixel;
        this.borderPixelX2Y2 = borderPixel;
    }

    public ImageCellWriteHandler(int borderPixelX1Y1, int borderPixelX2Y2) {
        this.borderPixelX1Y1 = borderPixelX1Y1;
        this.borderPixelX2Y2 = borderPixelX2Y2;
    }

    /**
     * 单元格数据转换后调用
     */
    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder,
                                       WriteTableHolder writeTableHolder,
                                       CellData cellData, Cell cell,
                                       Head head, Integer relativeRowIndex, Boolean isHead) {
        // 此处不处理表头,不处理不包含图像的
        boolean noImageValue = Objects.isNull(cellData) || Objects.isNull(cellData.getImageValue());
        if (Objects.equals(Boolean.TRUE, isHead) || noImageValue) {
            return;
        }
        // 设置单元格类型为EMPTY 让EasyExcel不去处理该单元格 由我们自己填充
        cellData.setType(CellDataTypeEnum.EMPTY);
    }

    /**
     * 在单元格上的所有操作完成后调用
     */
    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder,
                                 WriteTableHolder writeTableHolder,
                                 List<CellData> cellDataList, Cell cell,
                                 Head head, Integer relativeRowIndex, Boolean isHead) {
        if (CollectionUtils.isEmpty(cellDataList) || Objects.equals(Boolean.TRUE, isHead)) {
            return;
        }

        // cellDataList 是list的原因是 填充的情况下 可能会多个写到一个单元格 但是如果普通写入只有一个
        CellData cellData = cellDataList.get(0);

        //  在afterCellDataConverted方法里面已经将CellDataType设置为EMPTY 此处不能用cellData.getType()来判断是否图片类型
        if (Objects.isNull(cellData) || Objects.isNull(cellData.getImageValue())) {
            return;
        }

        setImageValue(cellData, cell);
    }

    private void setImageValue(CellData cellData, Cell cell) {
        Sheet sheet = cell.getSheet();
        int index = sheet.getWorkbook().addPicture(cellData.getImageValue(), HSSFWorkbook.PICTURE_TYPE_PNG);
        Drawing drawing = sheet.getDrawingPatriarch();
        if (drawing == null) {
            drawing = sheet.createDrawingPatriarch();
        }
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();
        ClientAnchor anchor = helper.createClientAnchor();
        // 图片边距:让图片不会填满整个单元格,与四周有一定边距
        final int borderWidth1 = Units.pixelToEMU(getBorderPixelX1Y1());
        final int borderWidth2 = Units.pixelToEMU(getBorderPixelX2Y2());
        // 图片左上角偏移量
        anchor.setDx1(0);
        anchor.setDy1(0);
        // 图片右下角偏移量
        anchor.setDx2(0);
        anchor.setDy2(0);
        // 图片行列
        anchor.setCol1(6);
        anchor.setCol2(8);
        anchor.setRow1(2);
        anchor.setRow2(5);
        anchor.setAnchorType(getAnchorType());
        drawing.createPicture(anchor, index);
        // 按照图片本身实际尺寸
        //Picture picture = drawing.createPicture(anchor, index);
        //picture.resize();
    }
}


主要修改以下代码

 // 图片左上角偏移量
        anchor.setDx1(0);
        anchor.setDy1(0);
        // 图片右下角偏移量
        anchor.setDx2(0);
        anchor.setDy2(0);
        // 图片行列
        anchor.setCol1(6);
        anchor.setCol2(8);
        anchor.setRow1(2);
        anchor.setRow2(5);
        anchor.setAnchorType(getAnchorType());
        drawing.createPicture(anchor, index);
        // 按照图片本身实际尺寸
        //Picture picture = drawing.createPicture(anchor, index);
        //picture.resize();

注册Handler

ImageCellWriteHandler imageCellWriteHandler = new ImageCellWriteHandler();
// imageCellWriteHandler.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
...
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
		.registerWriteHandler(imageCellWriteHandler )
		.build();
7

这样就可以改变图片位置,目前只适合一张图片

2、如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹

官网代码

 /**
     * 多列表组合填充填充
     *
     * @since 2.2.0-beta1
     */
    @Test
    public void compositeFill() {
        // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
        // {} 代表普通变量 {.} 代表是list的变量 {前缀.} 前缀可以区分不同的list
        String templateFileName =
            TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "composite.xlsx";

        String fileName = TestFileUtil.getPath() + "compositeFill" + System.currentTimeMillis() + ".xlsx";

        // 方案1
        try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
            // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹
            excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet);
            excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet);
            excelWriter.fill(new FillWrapper("data2", data()), writeSheet);
            excelWriter.fill(new FillWrapper("data2", data()), writeSheet);
            excelWriter.fill(new FillWrapper("data3", data()), writeSheet);
            excelWriter.fill(new FillWrapper("data3", data()), writeSheet);

            Map<String, Object> map = new HashMap<String, Object>();
            //map.put("date", "2019年10月9日13:28:28");
            map.put("date", new Date());

            excelWriter.fill(map, writeSheet);
        }
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值