java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java EasyExcel导入带图

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

作者:王疏蔬

这篇文章主要介绍了关于结合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导入带图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文