Java EasyExcel导入带图片的完整过程记录

 更新时间:2024年12月07日 10:45:27   作者:王疏蔬  
这篇文章主要介绍了关于结合EasyExcel和ApachePOI来实现Excel数据批量导入并读取图片的过程,文中通过图文以及代码介绍的非常详细,需要的朋友可以参考下

前言

项目中,要求批量导入 Excel 数据并读取其中图片,目前 EasyExcel 不支持读取图片,因此需要使用 Apache POI 进行导入。然而Apache POI 需要开发者手动管理行、列、单元格等对象,相对较为底层且繁琐。

作者随即想到了一种方法,既能够使用 EasyExcel 的简便导入方式,又能够识别图片并进行处理。

相关依赖

        <!-- Apache POI -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
        </dependency>

Java 代码展示

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.bi.my.vo.ExcelVo;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.result.R;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据+图片导入
 *
 * @author wss
 */
@Slf4j
@RestController
@RequestMapping("/easy")
public class EasyExcelController {

    /**
     * 数据导入并识别图片
     *
     * @param file file
     * @return R<Object>
     * @author wss
     */
    @PostMapping("/import")
    public R<Object> dataImport(@RequestParam("file") MultipartFile file) {
        List<ExcelVo> excelVos = new ArrayList<>();
        //数据处理
        this.dataProcess(file, excelVos);
        //图像处理
        this.imageProcess(file, excelVos);
        //返回结果,这里也可以处理excelVos数据,如往mysql存储
        return R.success(excelVos);
    }

    /**
     * 图片处理
     */
    public void imageProcess(MultipartFile file, List<ExcelVo> excelVos) {
        try {
            XSSFWorkbook book = new XSSFWorkbook(file.getInputStream());
            //方式1 获取sheet数量,采用下标方式遍历读取每个工作表数据
            int sheetsNos = book.getNumberOfSheets();
            for (int sheetNo = 0; sheetNo < sheetsNos; sheetNo++) {
                Sheet sheet = book.getSheetAt(sheetNo);
                //...省略,内容为方式2
            }
            //方式2 获取sheet数量,直接遍历读取每个工作表数据
            for (Sheet sheet : book) {
                XSSFSheet xssSheet = (XSSFSheet) sheet;
                //获取工作表中绘图包
                XSSFDrawing drawing = xssSheet.getDrawingPatriarch();
                if (drawing == null) {
                    break;
                }
                //获取所有图像形状
                List<XSSFShape> shapes = drawing.getShapes();
                //遍历所有形状
                for (XSSFShape shape : shapes) {
                    //获取形状在工作表中的顶点位置信息(anchor锚点)
                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
                    //图片形状在工作表中的位置, 所在行列起点和终点位置
                    short c1 = anchor.getCol1();
                    int r1 = anchor.getRow1();
                    String key = r1 + "行," + c1 + "列";
                    if (shape instanceof XSSFPicture) {
                        try {
                            XSSFPicture pic = (XSSFPicture) shape;
                            //形状获取对应的图片数据
                            XSSFPictureData picData = pic.getPictureData();
                            //保存图片到本地
                            byte[] data = picData.getData();
                            //TODO 这里上传文件至oss并生成链接,这里不做过多描述,有疑问请参照oss服务调用
                            String fileName = "https://oss.cn/" + DateUtil.today() + "/" + IdUtil.simpleUUID() + "/" + picData.suggestFileExtension();
                            //fileTemplate.putObject(properties.getBucketName(), fileName, new ByteArrayInputStream(data));
                            //TODO 放入excel集合,这里行数要减去1,获取图片是从表头开始(表头位置为0),获取excelVos是从数据开始(第一条数据位置为0)他们相差一个表头,所以要减去1才能对应
                            excelVos.get(r1 - 1).setPicture(fileName);
                        } catch (Exception e) {
                            log.error("asyncImportList XSSFClientAnchor key|{} error|{}", key, e.getMessage());
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("asyncImportList XSSFWorkbook error|{}", e.getMessage());
        }
    }

    /**
     * 数据处理
     */
    public void dataProcess(MultipartFile file, List<ExcelVo> excelVos) {
        // 这里默认读取第一个sheet
        try {
            EasyExcel.read(file.getInputStream(), ExcelVo.class, new ReadListener() {
                /**
                 * 单次缓存的数据量
                 */
                public static final int BATCH_COUNT = 100;
                /**
                 *临时存储
                 */
                private List<ExcelVo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                @Override
                public void invoke(Object object, AnalysisContext context) {
                    ExcelVo data = (ExcelVo) object;
                    cachedDataList.add(data);
                    if (cachedDataList.size() >= BATCH_COUNT) {
                        saveData();
                        // 存储完成清理 list
                        cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    saveData();
                }

                /**
                 * 加上存储数据库
                 */
                private void saveData() {
                    log.info("已获取数据|{}条", cachedDataList.size());
                    excelVos.addAll(cachedDataList);
                }
            }).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 * 导入VO
 *
 * @author wss
 */
@Data
public class ExcelVo {
    @ExcelProperty("序号")
    private Integer ordinal;
    @ExcelProperty("标题")
    private String title;
    @ExcelProperty("图片")
    private String picture;
}

Excel 表格准备

excel表头需和实体字段相对应

Postman 调用测试

打开图片链接发现与excel中图片一致,对应数据一致,读取图片成功!

结尾

到这里,EasyExcel 导入带图片已完成!读取图片速度较慢,可以通过异步或其它方式优化处理,根据自己需求修改即可,这里就不进行说明了。

补充

项目中本人是通过@RequestExcel注解直接获取的excel数据,file专用于图片读取,即方法中不用再进行数据处理,代码更加简化。

这篇文章主要是用来处理读取图片的,这里就不再详细说明该注解了,感兴趣的小伙伴可以查阅一下相关资料。

    /**
     * 数据导入并识别图片
     *
     * @param file file
     * @return R<Object>
     * @author wss
     */
    @PostMapping("/import")
    public R<Object> dataImport(@RequestParam("file") MultipartFile file, @RequestExcel List<ExcelVo> excelVos) {
        //图像处理
        this.imageProcess(file, excelVos);
        //返回结果,这里也可以处理excelVos数据,如往库里存储
        return R.success(excelVos);
    }

到此这篇关于Java EasyExcel导入带图片的文章就介绍到这了,更多相关Java EasyExcel导入带图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • kotlin和Java的相互调用示例详解

    kotlin和Java的相互调用示例详解

    Kotlin 的设计过程中就考虑到了与 Java 的互操作性。在 Kotlin 中可以直接调用既有的 Java 代码, 反过来在 Java 中也可以很流畅地使用 Kotlin 代码,下面这篇文章主要给大家介绍了关于kotlin和Java的相互调用的相关资料,需要的朋友可以参考下。
    2018-02-02
  • Mybatis-flex整合达梦数据库的实现示例

    Mybatis-flex整合达梦数据库的实现示例

    本文讨论了国产达梦数据库与Mybatis-flex框架的整合过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-10-10
  • Spring中的Sentinel熔断降级原理详解

    Spring中的Sentinel熔断降级原理详解

    这篇文章主要介绍了Spring中的Sentinel熔断降级原理详解,熔断是为了起到保护作用,如果某个目标服务调用比较慢或者大量的超时,这个时候如果触发熔断机制,则可以保证后续的请求不会继续发送到目标服务上,而是直接返回降级的逻辑并且快速释放资源,需要的朋友可以参考下
    2023-09-09
  • 浅析Mybatis 在CS程序中的应用

    浅析Mybatis 在CS程序中的应用

    如果是自己用的Mybatis,不需要考虑对配置文件加密,如果不是,那就需要考虑加密,这篇文章主要讲如何配置CS的Mybatis
    2013-07-07
  • java递归读取目录下所有文件的方法

    java递归读取目录下所有文件的方法

    这篇文章主要为大家详细介绍了java递归读取目录下所有文件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • SpringBoot集成WebServlet出现自定义servlet请求失败的问题解决方案

    SpringBoot集成WebServlet出现自定义servlet请求失败的问题解决方案

    SpringBoot中以Bean方式注册Servlet时遇到的问题,通过了解DispatcherServlet的原理,发现默认路径冲突是主要原因,本文介绍SpringBoot集成WebServlet出现自定义servlet请求失败的问题解决方案,感兴趣的朋友一起看看吧
    2025-03-03
  • 解读maven配置阿里云镜像问题

    解读maven配置阿里云镜像问题

    这篇文章主要介绍了解读maven配置阿里云镜像问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • java数据随机分页实现方案

    java数据随机分页实现方案

    本文主要介绍了java数据随机分页实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • 深入解析MybatisPlus多表连接查询

    深入解析MybatisPlus多表连接查询

    在一些复杂的业务场景中,我们经常会遇到多表连接查询的需求,本文主要介绍了深入解析MybatisPlus多表连接查询,具有一定的参考价值,感兴趣的可以了解一下
    2024-06-06
  • Java编程获取经纬度之间距离的方法

    Java编程获取经纬度之间距离的方法

    这篇文章主要介绍了Java编程获取经纬度之间距离的方法,涉及Java数学运算的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11

最新评论