EasyExcel导出图片的实际应用。

背景:要求在不同的条件下导出的文件格式不同。其中每个文件中都包含了图片。

1、实体


import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import lombok.Builder;
import lombok.Data;

import java.net.URL;


/**
 * @date        2021-03-10 23:32:49
 * @author      林渊
 */
@Data
@Builder
@ContentRowHeight(200)
@ColumnWidth(50)
public class OtherGoodsInfoData {

    @ExcelProperty(index = 0, value = "商品链接")
    private String goodsLink;

    @ExcelProperty(index = 1, value = "侵权截图")
    private URL tortPicture;

}

复制代码
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import lombok.Builder;
import lombok.Data;

import java.net.URL;


/**
 * @date        2021-03-10 23:32:49
 * @author      林渊
 */
@Data
@Builder
@ContentRowHeight(200)
@ColumnWidth(50)
public class OtherCopyrightGoodsInfoData {

    @ExcelProperty(index = 0, value = "商品链接")
    private String goodsLink;

    @ExcelProperty(index = 1, value = "侵权截图")
    private URL tortPicture;

    @ExcelProperty(index = 2, value = "对比截图")
    private URL comparePicture;

    @ExcelProperty(index = 3, value = "对比链接")
    private String compareUrl;
}

复制代码
  • 采用的是直接URL导出图片的方式。

遇到的问题

1、导出的图片不会随着单元格的移动而移动,就像是一块膏药,贴在那不动。

2、设置好移动之后,会出现一个单元格内有两张图的情况。

3、图片会随着移动,但是不会自适应大小。

解决办法

问题1:EasyExcel需要配置Handler。其中afterCellDataConverted这个方法中,cellData.setType(CellDataTypeEnum.EMPTY);属性这么设置,也就表示EasyExcel在写的时候会忽略这个cell。从而不会出现图片填充两次的情况。但是因为这个需要通用,所以获取导出实体类中的URL字段的属性,获取index,也就是图片的cell需要EasyExcel写入的时候忽略。


import cn.afterturn.easypoi.util.PoiPublicUtil;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.*;

import java.util.List;

import static org.apache.poi.ss.usermodel.ClientAnchor.AnchorType.*;

/**
 * easyExcel图片导出处理器
 *
 * @author      linyuan
 * @date        2021-03-15 10:45:49
 */
public class ImageModifyHandler implements CellWriteHandler {

    private final List<Integer> ignoreIndexes;

    public ImageModifyHandler(List<Integer> ignoreIndexes) {
        this.ignoreIndexes = ignoreIndexes;
    }


    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
        if (!ignoreIndexes.isEmpty()) {
            if (!ignoreIndexes.contains(head.getColumnIndex()) || aBoolean) {
                return;
            }
            cellData.setType(CellDataTypeEnum.EMPTY);
        }

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
        //  在 单元格写入完毕后 ,自己填充图片
        if (head.getColumnIndex() != 1 || aBoolean || list.isEmpty() || list.get(0).getImageValue() == null) {
            return;
        }
        Sheet sheet = cell.getSheet();
        // cellDataList 是list的原因是 填充的情况下 可能会多个写到一个单元格 但是如果普通写入 一定只有一个
        int index = sheet.getWorkbook().addPicture(list.get(0).getImageValue(), getImageType(list.get(0).getImageValue()));
        Drawing drawing = sheet.getDrawingPatriarch();
        if (drawing == null) {
            drawing = sheet.createDrawingPatriarch();
        }
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();
        ClientAnchor anchor = helper.createClientAnchor();
        // 设置图片坐标
        anchor.setDx1(1);
        anchor.setDx2(1);
        anchor.setDy1(0);
        anchor.setDy2(0);
        //设置图片位置
        anchor.setCol1(cell.getColumnIndex());
        anchor.setCol2(cell.getColumnIndex() + 1);
        anchor.setRow1(cell.getRow().getRowNum());
        anchor.setRow2(cell.getRow().getRowNum() + 1);
        // 设置图片可以随着单元格移动
        anchor.setAnchorType(MOVE_AND_RESIZE);
        drawing.createPicture(anchor, index);
    }

    /**
     * 获取图片类型,设置图片插入类型
     * @author JueYue 2013年11月25日
     */
    public static int getImageType(byte[] value) {
        String type = PoiPublicUtil.getFileExtendName(value);
        if ("JPG".equalsIgnoreCase(type)) {
            return Workbook.PICTURE_TYPE_JPEG;
        } else if ("PNG".equalsIgnoreCase(type)) {
            return Workbook.PICTURE_TYPE_PNG;
        }

        return Workbook.PICTURE_TYPE_JPEG;
    }

}

复制代码
  • 最后写的时候,带上这个handler
 EasyExcel.write(excelPath + fileName,clazz )
                                        .registerWriteHandler(new ImageModifyHandler(getIgnoreIndexes(clazz)))
                                        .sheet()
                                        .doWrite(tempList);
                                        
                                         /**
     * 获取类中URL属性的字段的index集合
     * @param clazz     clazz
     * @return          List<Integer></>
     */
    private List<Integer> getIgnoreIndexes(Class clazz) {
        if (clazz == null) {
            return Collections.emptyList();
        }
        List<Integer> indexes = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        Arrays.asList(fields).forEach(f -> {
            if (f.getGenericType().equals(URL.class)) {
                ExcelProperty excelProperty= f.getAnnotation(ExcelProperty.class);
                if (excelProperty != null && excelProperty.index() >= 0) {
                    indexes.add(excelProperty.index());
                }
            }
        });
        return indexes;
    }
复制代码

问题2:在问题1中已经解决了。设置属性。

问题3:设置anchor的属性。图片如果完全在这个单元格内,四周都没碰到单元格,图片是可以跟随单元格移动的。

  ClientAnchor anchor = helper.createClientAnchor();
        // 设置图片坐标
        anchor.setDx1(1);
        anchor.setDx2(1);
        anchor.setDy1(0);
        anchor.setDy2(0);
        //设置图片位置
        anchor.setCol1(cell.getColumnIndex());
        anchor.setCol2(cell.getColumnIndex() + 1);
        anchor.setRow1(cell.getRow().getRowNum());
        anchor.setRow2(cell.getRow().getRowNum() + 1);
        // 设置图片可以随着单元格移动
        anchor.setAnchorType(MOVE_AND_RESIZE);
复制代码