首页 > 其他分享 >EasyExcel 读取单元格内图片

EasyExcel 读取单元格内图片

时间:2024-02-01 15:44:07浏览次数:33  
标签:return 读取 EasyExcel 单元格 new attachment sheet workbook sheetIndex

EasyExcel 读取单元格内图片

1.需求介绍

需要实现Excel数据批量导入,且Excel中某个单元格内存在图片,需要将图片解析上传,并与所在行数据进行绑定,具体数据如:

image-20240201144045786

2.具体实现

2.1 版本介绍

  1. easyexcel:3.3.2
  2. SpringBoot:2.7.1
  3. hutool:5.7.21

2.2 解决思路

参考hutool ExcelPicUtil工具类,通过调用getPicMap方法可以获得Map<String, PictureData>数据,其中key为:行_列,value为:此单元格图片对象

通过学习其源码发现存在一些问题:

  1. 当同一个单元格内存在多张照片,会出现覆盖情况,即先解析出来的图片会被后解析的覆盖,造成图片丢失的情况

  2. 采用双循环的方式解析数据,且获取的PictureData并不符合文件上传需求,若直接调用会存在两次双循环,解析速度变慢

2.3 具体实现

  1. 新增ExcelImageUtil工具类
public class ExcelImageUtil {

    /**
     * 获取工作簿指定sheet中图片列表
     *
     * @param workbook   工作簿{@link Workbook}
     * @param sheetIndex sheet的索引
     * @return 图片映射,键格式:行_列,值:{@link PictureData}
     */
    public static Map<Integer, List<Attachment>> getPicMap(Workbook workbook, int sheetIndex) {
        Assert.notNull(workbook, "Workbook must be not null !");
        if (sheetIndex < 0) {
            sheetIndex = 0;
        }
        // 由于实际业务提供的模板为XLSX,暂时不考虑XLS解析
        if (workbook instanceof HSSFWorkbook) {
            return null;
        } else if (workbook instanceof XSSFWorkbook) {
            try {
                return getRowPicMapXlsx((XSSFWorkbook) workbook, sheetIndex);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            throw new IllegalArgumentException(StrUtil.format("Workbook type [{}] is not supported!", workbook.getClass()));
        }
        return Collections.emptyMap();
    }

    // -------------------------------------------------------------------------------------------------------------- Private method start

    /**
     * 获取XLS工作簿指定sheet中图片列表
     *
     * @param workbook   工作簿{@link Workbook}
     * @param sheetIndex sheet的索引
     * @return 图片映射,键格式:行_列,值:{@link PictureData}
     */
    //private static Map<Integer, List<Attachment>> getPicMapXls(HSSFWorkbook workbook, int sheetIndex) {
    //    final Map<String, List<Attachment>> picMap = new HashMap<>();
    //    final List<HSSFPictureData> pictures = workbook.getAllPictures();
    //    if (CollectionUtil.isNotEmpty(pictures)) {
    //        final HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
    //        HSSFClientAnchor anchor;
    //        int pictureIndex;
    //        for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) {
    //            if (shape instanceof HSSFPicture) {
    //                pictureIndex = ((HSSFPicture) shape).getPictureIndex() - 1;
    //                anchor = (HSSFClientAnchor) shape.getAnchor();
    //                HSSFPictureData hssfPictureData = pictures.get(pictureIndex);
    //                Attachment attachment = new Attachment();
    //                ByteArrayInputStream inputStream = new ByteArrayInputStream(hssfPictureData.getData());
    //                hssfPictureData.get
    //                        name = name.substring(name.lastIndexOf("/") + 1);
    //                InputStream inputStreamPart = packagePart.getInputStream();
    //                attachment.setFileSize(Func.toLong(inputStreamPart.available()));
    //                BladeFile bladeFile = MinioUtil.getMinioTemplate().putFile(name, inputStream);
    //                attachment.setObjName(bladeFile.getName());
    //                attachment.setDisplayName(bladeFile.getOriginalName());
    //                //获取后缀名
    //                attachment.setFileType(FileUtil.extName(bladeFile.getOriginalName()));
    //                picMap.put(StrUtil.format("{}_{}", anchor.getRow1(), anchor.getCol1()), );
    //            }
    //        }
    //    }
    //    return picMap;
    //}

    /**
     * 获取XLSX工作簿指定sheet中图片列表
     *
     * @param workbook   工作簿{@link Workbook}
     * @param sheetIndex sheet的索引
     * @return 图片映射,键格式:行_列,值:{@link PictureData}
     */
    private static Map<Integer, List<Attachment>> getRowPicMapXlsx(XSSFWorkbook workbook, int sheetIndex) throws IOException {
        final Map<Integer, List<Attachment>> sheetIndexPicMap = new HashMap<>();
        final XSSFSheet sheet = workbook.getSheetAt(sheetIndex);
        XSSFDrawing drawing;
        for (POIXMLDocumentPart dr : sheet.getRelations()) {
            if (dr instanceof XSSFDrawing) {
                drawing = (XSSFDrawing) dr;
                final List<XSSFShape> shapes = drawing.getShapes();
                XSSFPicture pic;
                CTMarker ctMarker;
                for (XSSFShape shape : shapes) {
                    if (shape instanceof XSSFPicture) {
                        pic = (XSSFPicture) shape;
                        ctMarker = pic.getPreferredSize().getFrom();
                        int row = ctMarker.getRow();
                        XSSFPictureData data = pic.getPictureData();
                        Attachment attachment = new Attachment();
                        PackagePart packagePart = data.getPackagePart();
                        String name = packagePart.getPartName().getName();
                        name = name.substring(name.lastIndexOf("/") + 1);
                        InputStream inputStreamPart = packagePart.getInputStream();
                        attachment.setFileSize(Func.toLong(inputStreamPart.available()));
                        try {
                            BladeFile bladeFile = MinioUtil.getMinioTemplate().putFile(name, inputStreamPart);
                            attachment.setObjName(bladeFile.getName());
                            attachment.setDisplayName(bladeFile.getOriginalName());
                            //获取后缀名
                            attachment.setFileType(FileUtil.extName(bladeFile.getOriginalName()));
                        } catch (Exception e) {
                            log.error("MINIO 上传文件失败," + e.getMessage());
                            continue;
                        }
                        // 通过map.computeIfAbsent 方法,如果存在key 则返回已有的List,不存在则new ArrayList
                        // 再通过add()方法,添加当前对象
                        sheetIndexPicMap.computeIfAbsent(row, k -> new ArrayList<>()).add(attachment);
                    }
                    // 其他类似于图表等忽略,see: https://gitee.com/loolly/hutool/issues/I38857
                }
            }
        }
        return sheetIndexPicMap;
    }
}
  1. 解析数据

     public boolean importInspectData(MultipartFile file) throws IOException, ParseException {
            InputStream inputStream = file.getInputStream();
            InputStream inputStream2 = file.getInputStream();
            ExcelReader excelReader = ExcelUtil.getReader(inputStream2);
            Map<Integer, List<Attachment>> attachMap = ExcelImageUtil.getPicMap(excelReader.getWorkbook(), 0);
            List<InspectionTemplateExcel> inspectionTemplateExcelList = EasyExcelUtil.read(inputStream, 0, 1, InspectionTemplateExcel.class);
            if (Func.isEmpty(inspectionTemplateExcelList)) {
                return true;
            }
            int i = 1;
            for (InspectionTemplateExcel excel : inspectionTemplateExcelList) {
                excel.setNo(i++);
            }
    
            Map<String, List<InspectionTemplateExcel>> collect = inspectionTemplateExcelList.stream().collect(Collectors.groupingBy(e -> e.getDiscoverDatetime() + "#" + e.getSegmentId()));
            for (Map.Entry<String, List<InspectionTemplateExcel>> stringListEntry : collect.entrySet()) {
                String key = stringListEntry.getKey();
                String[] split = key.split("#");
                Date date = ExcelDateUtil.parseDate(split[0]);
                List<InspectionTemplateExcel> value = stringListEntry.getValue();
                InspectionTemplateExcel templateExcel = inspectionTemplateExcelList.get(0);
                InspectionTask task = new InspectionTask();
                task.setType(Func.toInt(templateExcel.getInspectType()));
                task.setStartDatetime(date);
                task.setEndDatetime(date);
                task.setPersonId(AuthUtil.getUserName());
                task.setDeptId(SysCache.getDeptName(Func.firstLong(AuthUtil.getDeptId())));
                task.setSource(3);
                save(task);
                Long taskId = task.getId();
                Set<String> diseaseTypes = new HashSet<>();
                for (InspectionTemplateExcel excel : value) {
                    int no = excel.getNo();
                    InspectionBizRecord record = cn.hutool.core.bean.BeanUtil.copyProperties(excel, InspectionBizRecord.class, "discoverDatetime");
                    record.setSource(3);
                    record.setType(excel.getDiseaseType());
                    diseaseTypes.add(excel.getDiseaseType());
                    record.setInspectionTaskId(taskId);
                    if (attachMap.containsKey(no)) {
                        record.setImages(attachMap.get(no));
                    }
                    fillLocations(record);
                    recordService.save(record);
                }
     
            }
    
            return true;
        }
    

标签:return,读取,EasyExcel,单元格,new,attachment,sheet,workbook,sheetIndex
From: https://www.cnblogs.com/XiaoMingStudy1/p/18001412

相关文章

  • AWR1243+DCA100——数据读取
    一、DCA1000读取AWR1243的ADC数据的格式DCA1000通过4个LVDS线读取对应AWR1243的4个接收天线Rx的回波数据;使能LVDS的数量要和使能接收天线Rx的数量相等,且由大到小依次对应。例如使能了RX1,RX2和Lane2,Lane3,则Lane2读取RX1数据,Lane3读取RX2数据,其他数据线(Lane1和Lane4填充零);每......
  • 解决前端JSZip读取压缩包内文件中文名称乱码问题
    1importJSZipfrom"jszip";23functionjszipFile(file){4if(!/\.zip$/i.test(file.name)){5reject(`文件"${file.name}"不是zip文件`);6return;7}89constfileReader=newFileReader();1011//转换文件为Arra......
  • python中不同类型文件的读取方法
    在进行卷积神经网络的学习过程中,碰到了不同类型的数据集加载,下面总结一下:1、文本文件:CSV、TSV、Json、Txt1.1、简介CSV文件是逗号分隔值(Comma-SeparatedValues,CSV),其文件以纯文本形式存储表格数据(数字和文本);TSV是Tab-separatedvalues的缩写,即制表符分隔值,与csv和txt都同属......
  • [office] excel表格锁定单元格不滚动的设置方法
    excel表格锁定单元格不滚动的设置方法1.打开需要修改的表格,在表格主页面中找到上方视图选项,点击该选项进入视图页面。2.在视图页面中找到冻结窗格选项,点击该选项进入至冻结窗格页面中。3.在冻结窗格页面中找到冻结首行选项即可固定该表格中的首行单元格。4.在冻结窗格页面中找到冻......
  • WPS JS 宏根据单元格内容填充颜色
    WPSJS宏根据单元格内容填充颜色直接上代码/***Macro1Macro*宏由Steven录制,时间:2024/01/30*/functionSetCellColorsBYMacro(){ //获取表格的行数和列数varrowCount=48;varcolAll=['A','B','C','D','E',&......
  • java读取并解析XML文件的方法有哪些?
    XMLStreamReader:1. DOM(DocumentObjectModel)方式:DOM将整个XML文档加载到内存中,形成一颗树状结构,然后通过操作这个树状结构来获取所需要的数据。示例代码如下:importjavax.xml.parsers.*;importorg.w3c.dom.*;publicclassXMLParser{publicstaticvoidmain(Stri......
  • pandas高效读取大文件的探索之路
    使用pandas进行数据分析时,第一步就是读取文件。在平时学习和练习的过程中,用到的数据量不会太大,所以读取文件的步骤往往会被我们忽视。然而,在实际场景中,面对十万,百万级别的数据量是家常便饭,即使千万,上亿级别的数据,单机处理也问题不大。不过,当数据量和数据属性多了之后,读取文件的......
  • 字符缓冲流读取复制文件、排序文件内容
    1publicstaticvoidmain(String[]args){2try(3//定义字符输入流与文件相通4BufferedReaderbr=newBufferedReader(newFileReader("src/test.txt"));5//定义字符输出流与文件相通6......
  • ffmpeg-读取媒体文件信息-avformat_open_input
    实例代码Codeintvideo_audio_info(intargc,char*argv[]){ if(argc<2){ printf("Usage:%smediaFile\n",argv[0]); return-1; } AVFormatContext*ic=NULL; charpath[20]={0}; strcpy(path,argv[1]); //1.打开媒体文件 intret=avfo......
  • perf_event_open 学习 —— 通过read的方式读取硬件技术器
    目录示例程序1单计数器多计数器示例程序2ConfigureasinglecounterConfiguremultiplecounters(nomultiplexing)示例程序1Linuxperf子系统的使用(一)——计数刚刚入职的时候我就研究了perf_event_open()这个巨无霸级别的系统调用,还用Python封装了一层,非常便于获取计数器......