EasyExcel一单元格导出多图片

这里导出excel需要使用阿里的EasyExcel组件,项目需要引入EasyExcel依赖,版本可自己选择,博主这里使用2.2.7版本

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>2.2.7</version>
</dependency>

说到多图片导出,先要说下EasyExel的单图片导出,单图片导出比较简单,
直接使用下EasyExel自带的类UrlImageConverter(Converter的子类)实现,ExcelModel设置如下:

@Data
@ContentRowHeight(20)
@HeadRowHeight(20)
@ColumnWidth(25)
@HeadStyle(horizontalAlignment = HorizontalAlignment.CENTER)
@ContentStyle(horizontalAlignment = HorizontalAlignment.CENTER)
public class ExcelDemo {

    @ExcelProperty(value = "图片", converter = UrlImageConverter.class)
    private URL imageUrl;
    
}

我们先来看一下UrlImageConverter的实现:

package com.alibaba.excel.converters.url;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.IoUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class UrlImageConverter implements Converter<URL> {
    public UrlImageConverter() {
    }

    public Class supportJavaTypeKey() {
        return URL.class;
    }

    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.IMAGE;
    }

    public URL convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
        throw new UnsupportedOperationException("Cannot convert images to url.");
    }

    // 核心方法 读取图片url的io流
    public CellData convertToExcelData(URL value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException {
        InputStream inputStream = null;

        CellData var6;
        try {
            inputStream = value.openStream();
            byte[] bytes = IoUtils.toByteArray(inputStream);
            var6 = new CellData(bytes);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }

        }

        return var6;
    }
}

其实转化的方法很简单,只是读取图片url的io,写进Excel的cellData对象里,那多图片的转化只需要加个for循环一次读取转化就行里吧?我们来自己实现下多图片的转换器(实现easyexcel的扩展接口Converter)

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.IoUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description: easyecxel多图片导出到单元格转换工具类
 * @Author guowang
 * @Date: 2021/7/7 15:56
 * @Version 1.0
 */
public class ListUrlConverterUtil implements Converter<List<URL>> {
    @Override
    public Class supportJavaTypeKey() {
        return List.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        /**
         *这里记得枚举类型为IMAGE
         */
        return CellDataTypeEnum.IMAGE;
    }

    @Override
    public List convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return null;
    }

    @Override
    public CellData convertToExcelData(List<URL> value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        // 这里进行对数据实体类URL集合处理
        List<CellData> data = new ArrayList<>();
        // for 循环一次读取
        for (URL url : value) {
            InputStream inputStream = null;
            try {
                inputStream = url.openStream();
                byte[] bytes = IoUtils.toByteArray(inputStream);
                data.add(new CellData(bytes));
            } catch (Exception e) {
                throw new IOException("导出excel图片读取异常");
            } finally {
                if (inputStream != null){
                    inputStream.close();
                }
            }
        } 
        
        // 这种方式并不能返回一个List,所以只好通过CellData cellData = new CellData(data);将这个list对象塞到返回值CellData对象的data属性中;
        CellData cellData = new CellData(data);
        cellData.setType(CellDataTypeEnum.IMAGE);
        return cellData;
    }
}

ExcelModel设置如下:

@Data
@ContentRowHeight(20)
@HeadRowHeight(20)
@ColumnWidth(25)
@HeadStyle(horizontalAlignment = HorizontalAlignment.CENTER)
@ContentStyle(horizontalAlignment = HorizontalAlignment.CENTER)
public class ExcelDemo {

    @ExcelProperty(value = "图片", converter = ListUrlConverterUtil.class)
    private List<URL> imageUrls;

}

图片统一大小返回, 这里需要实现CellWriteHandler 的afterCellDataConverted 方法,将 CellData 的 type 设置成 EMPTY ,这样 EasyExcel 不会帮忙填充该单元格的数据,然后实现 CellWriteHandler 的 afterCellDispose 方法,将图片信息填充上去

注意:每列的单元格图片张数不确定,单元格宽度需按照张数最多的长度来设置

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.commons.collections.CollectionUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.Units;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: 图片信息修改拦截器
 * @Author GreenArrow
 * @Date: 2021/7/7 16:05
 * @Version 1.0
 */
public class CustomImageModifyHandler implements CellWriteHandler {
    private List<String> repeats = new ArrayList<>();
    // 单元格的图片最大张数(每列的单元格图片张数不确定,单元格宽度需按照张数最多的长度来设置)
    private Integer maxDataSize = 0;
    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

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

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        //  在 数据转换成功后 不是头就把类型设置成空
        if (isHead) {
            return;
        }
        //将要插入图片的单元格的type设置为空,下面再填充图片
        if(cellData.getImageValue()!=null||cellData.getData() instanceof ArrayList){
            cellData.setType(CellDataTypeEnum.EMPTY);
        }
    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        //  在 单元格写入完毕后 ,自己填充图片
        if (isHead || CollectionUtils.isEmpty(cellDataList)) {
            return;
        }
        Boolean listFlag = false;
        ArrayList data = null;
        Sheet sheet = cell.getSheet();
        // 此处为ListUrlConverterUtil的返回值
        if (cellDataList.get(0).getData() instanceof ArrayList){
            data = (ArrayList) cellDataList.get(0).getData();
            if (CollectionUtils.isEmpty(data)) {
                return;
            }
            if (data.get(0) instanceof CellData){
                CellData cellData = (CellData) data.get(0);
                if (cellData.getImageValue() == null){
                    return;
                }else {
                    listFlag = true;
                }
            }
        }
        if (!listFlag && cellDataList.get(0).getImageValue() == null){
            return;
        }
        String key = cell.getRowIndex() + "_" + cell.getColumnIndex();
        if (repeats.contains(key)){
            return;
        }
        repeats.add(key);
        if (data.size() > maxDataSize) {
            maxDataSize = data.size();
        }
        // 默认要导出的图片大小为175*175px,175px的行高大约是900,175px列宽大概是25*256
        sheet.getRow(cell.getRowIndex()).setHeight((short)1800);
        sheet.setColumnWidth(cell.getColumnIndex(),listFlag?25*256*maxDataSize:25*256);

        if (listFlag){
            for (int i = 0; i < data.size(); i++) {
                CellData cellData= (CellData) data.get(i);
                if(cellData.getImageValue()==null){
                    continue;
                }
                this.insertImage(sheet,cell,cellData.getImageValue(),i);
            }
        }else {
            // cellDataList 是list的原因是 填充的情况下 可能会多个写到一个单元格 但是如果普通写入 一定只有一个
            this.insertImage(sheet,cell,cellDataList.get(0).getImageValue(),0);
        }

    }

    private void insertImage(Sheet sheet,Cell cell,byte[] pictureData,int i){
        int picWidth = Units.pixelToEMU(175);
        int index = sheet.getWorkbook().addPicture(pictureData, HSSFWorkbook.PICTURE_TYPE_PNG);
        Drawing drawing = sheet.getDrawingPatriarch();
        if (drawing == null) {
            drawing = sheet.createDrawingPatriarch();
        }
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();
        ClientAnchor anchor = helper.createClientAnchor();
        // 设置图片坐标
        anchor.setDx1(picWidth*i);
        anchor.setDx2(picWidth+picWidth*i);
        anchor.setDy1(0);
        anchor.setDy2(0);
        //设置图片位置
        anchor.setCol1(cell.getColumnIndex());
        anchor.setCol2(cell.getColumnIndex());
        anchor.setRow1(cell.getRowIndex());
        anchor.setRow2(cell.getRowIndex() + 1);
        // 设置图片可以随着单元格移动
        anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
        drawing.createPicture(anchor, index);
    }
}

使用EasyExcel的write方法将数据写到excel中,这里比较重要的是需要.registerWriteHandler,这里需要将自己写的图片拦截器注入进去

EasyExcel.write(outputStream, ExcelDemo.class)
    .registerWriteHandler(new CustomImageModifyHandler()).sheet().doWrite(查询出来并且完成数据转换的Excel数据集合)

导出的excel图片结果如下(博主这里每列的图片张数不固定,单元格宽度按张数最多的那一列长度设置):
在这里插入图片描述

  • 7
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Java中,如果一个单元格中有多张图片,则可以通过遍历DrawingPatriarch对象中的所有Picture对象,找到包含在该单元格中的所有图片。下面是一个示例代码,演示如何导入Excel文件中某个单元格中的多个图片: ```java import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFShape; import org.apache.poi.xssf.usermodel.XSSFPicture; public class ExcelMultiImageImporter { public static void main(String[] args) throws IOException { InputStream inputStream = new FileInputStream("path/to/excel/file.xlsx"); Workbook workbook = WorkbookFactory.create(inputStream); Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表 for (Row row : sheet) { for (Cell cell : row) { if (cell.getCellType() == Cell.CELL_TYPE_STRING && cell.getStringCellValue().startsWith("image_")) { // 如果单元格的值以"image_"开头,说明该单元格包含图片 List<XSSFShape> shapes = ((XSSFDrawing) cell.getSheet().createDrawingPatriarch()).getShapes(); for (XSSFShape shape : shapes) { if (shape instanceof XSSFPicture) { XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor(); if (anchor.getRow1() == cell.getRowIndex() && anchor.getCol1() == cell.getColumnIndex()) { // 如果该图片所在的位置与单元格的位置相同,说明该图片包含在该单元格中 byte[] imageBytes = ((XSSFPicture) shape).getPictureData().getData(); // imageBytes即为导入的图片数据 // 接下来可以将图片数据保存到文件或者数据库中 } } } } } } IOUtils.closeQuietly(inputStream); // 关闭输入流 workbook.close(); // 关闭工作簿 } } ``` 在上面的示例代码中,我们遍历了Excel文件中的每个单元格,如果单元格的值以"image_"开头,就说明该单元格包含图片。接着,我们遍历DrawingPatriarch对象中的所有Picture对象,找到包含在该单元格中的所有图片。对于每张图片,我们都检查其所在的位置是否与单元格的位置相同,如果相同,就说明该图片包含在该单元格中。最后,我们从该图片中获取图片数据,并对其进行处理。这里我们只是简单地获取了图片数据,实际应用中可以将图片数据保存到文件或者数据库中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值