需求是这样的,给你固定一个excel,里面有id和插入的图片,大概200M-1G左右。
读取后将图片写入文件存储服务器内,获取静态地址,再将静态地址更新到对应id上。
难点:这个你很难定位到图片的横纵坐标,因为图片并不是真的在单元格内(业务那边给定的模板就是如此)。
excel结构大概为:
?找了网上的代码,简单修修改改。
package com.main.util;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* created by rock-ayl on 2022-2-23
* 解析excel内的图片所在单元格
*/
public class ExcelImageUtils {
private final static Logger LOG = LoggerFactory.getLogger(ExcelImageUtils.class);
/**
* 根据文件解析excel内图片
*
* @param file 文件对象
* @param sheetIndex 第几个sheet
* @return
*/
public static Map<String, Map<Integer, PictureData>> parseSheetPic(File file, int sheetIndex) {
try {
//文件流
InputStream input = new FileInputStream(file);
//文件后缀
String fileExt = FilenameUtils.getExtension(file.getName());
//实现并返回
return parseSheetPic(input, fileExt, sheetIndex);
} catch (Exception e) {
LOG.error("parseSheetPic fail , file error={}", e);
}
//默认
return new HashMap<>();
}
/**
* 根据文件流及文件类型解析excel内图片
*
* @param inputStream 文件流
* @param fileExt 文件后缀 xls,xlsx
* @param sheetIndex 第几个sheet
* @return
*/
public static Map<String, Map<Integer, PictureData>> parseSheetPic(InputStream inputStream, String fileExt, int sheetIndex) {
try {
//初始化
Workbook workbook = WorkbookFactory.create(inputStream);
//获取sheet
Sheet sheet = workbook.getSheetAt(sheetIndex);
//第一行作为key
Map<Integer, String> keyMap = new HashMap<>();
//第一行的迭代器
Iterator<Cell> iterator = sheet.getRow(0).cellIterator();
//指针
int p = 0;
//如果存在
while (iterator.hasNext()) {
//获取值
String value = iterator.next().getStringCellValue();
//如果存在
if (StringUtils.isNotBlank(value)) {
//记录该key
keyMap.put(p, value);
}
//无论如何+1o
p++;
}
//根据类型解析
switch (fileExt) {
case "xls":
return parseSheetPicForXLS((HSSFWorkbook) workbook, sheetIndex, keyMap);
case "xlsx":
return parseSheetPicForXLSX((XSSFWorkbook) workbook, sheetIndex, keyMap);
}
} catch (Exception e) {
LOG.error("parseSheetPic fail , inputStream error={}", e);
}
//默认
return new HashMap<>();
}
/**
* 解析XLS的图片
*
* @param workbook workbook
* @param sheetIndex 第几页sheet的图片
* @return
*/
private static Map<String, Map<Integer, PictureData>> parseSheetPicForXLS(HSSFWorkbook workbook, int sheetIndex, Map<Integer, String> keyMap) {
//初始化结果
Map<String, Map<Integer, PictureData>> result = new HashMap<>();
//获取workbook所有图片列表
List<HSSFPictureData> pictures = workbook.getAllPictures();
//获取对应sheet
HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
//如果存在图片
if (pictures.size() > 0) {
//获取列表
List<HSSFShape> children = sheet.getDrawingPatriarch().getChildren();
//循环
for (HSSFShape shape : children) {
//获取并强转
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
//如果是
if (shape instanceof HSSFPicture) {
//强转
HSSFPicture pic = (HSSFPicture) shape;
//从workbook所有图片中找到该图片
HSSFPictureData picData = pictures.get(pic.getPictureIndex() - 1);
//如果存在改key
if (keyMap.containsKey(anchor.getCol1())) {
//获取key
String key = keyMap.get(anchor.getCol1());
//尝试获取mep
Map<Integer, PictureData> map = result.getOrDefault(key, new HashMap<>());
//组装
map.put(anchor.getRow1() - 1, picData);
result.put(key, map);
}
}
}
}
//返回
return result;
}
/**
* 解析XLSX图片
*
* @return
*/
private static Map<String, Map<Integer, PictureData>> parseSheetPicForXLSX(XSSFWorkbook workbook, int sheetIndex, Map<Integer, String> keyMap) {
//初始化结果
Map<String, Map<Integer, PictureData>> result = new HashMap<>();
//获取列表
List<POIXMLDocumentPart> relationList = workbook.getSheetAt(sheetIndex).getRelations();
//循环1
for (POIXMLDocumentPart dr : relationList) {
//如果是类型
if (dr instanceof XSSFDrawing) {
//强转
XSSFDrawing drawing = (XSSFDrawing) dr;
//获取列表
List<XSSFShape> shapeList = drawing.getShapes();
//循环2
for (XSSFShape shape : shapeList) {
//强转
XSSFPicture pic = (XSSFPicture) shape;
//获取其可能的表格
CTMarker ctMarker = pic.getPreferredSize().getFrom();
//如果存在改key
if (keyMap.containsKey(ctMarker.getCol())) {
//获取key
String key = keyMap.get(ctMarker.getCol());
//尝试获取结果map
Map<Integer, PictureData> map = result.getOrDefault(key, new HashMap<>());
//组装
map.put(ctMarker.getRow() - 1, pic.getPictureData());
result.put(key, map);
}
}
}
}
//返回
return result;
}
}
代码测试结果:
准确定位的概率大概是90%左右,小部分会定位到其他key上,精度不高,无法采用。
至此,该需求经过讨论,废弃。
由于需求废弃并改为了其他方式,未提交这部分代码,简单记录下,防止以后用到。
|