EasyExcel 读取单元格内图片

📅 2024-02-01 15:41 👁️ 5710 💬 0

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;
        }
    
登录后才能查看或发表评论, 立即 登录
点击右上角即可分享
微信分享提示