这个只写了思路具体代码在文章最后,不想了解得直接去拿代码
- 了解Excel数据结构
Excel 文件格式后缀xls,xlsx 其实是一个压缩文件,是由多个文件夹以及xml 文件组程,xml文件记录了Excel得内容以及样式等信息。现在在桌面新建一个xlsx文件,插入一个嵌入式图片,文件后缀为.zip ,然后解压我们得到以下一个文件夹
可以看到又几个文件夹以及xml,,poi 不能读取wps嵌入式图片,是因为这个cellimages是wps自己独有得并不属于office标准,新增一个悬浮图片然后解压得到以下一个文件列表
会有一个drawings得文件夹,这个是office支持得格式正常获取图片是可以的 ,直接使用poi 的api 就可以获取到,自己去百度吧
<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<xdr:twoCellAnchor editAs="oneCell">
<xdr:from>
<xdr:col>6</xdr:col>
<xdr:colOff>0</xdr:colOff>
<xdr:row>4</xdr:row>
<xdr:rowOff>0</xdr:rowOff>
</xdr:from>
<xdr:to>
<xdr:col>21</xdr:col>
<xdr:colOff>548640</xdr:colOff>
<xdr:row>46</xdr:row>
<xdr:rowOff>7620</xdr:rowOff>
</xdr:to>
<xdr:pic>
<xdr:nvPicPr>
<xdr:cNvPr id="2" name="图片 1"/>
<xdr:cNvPicPr>
<a:picLocks noChangeAspect="1"/>
</xdr:cNvPicPr>
</xdr:nvPicPr>
<xdr:blipFill>
<a:blip r:embed="rId1"/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</xdr:blipFill>
<xdr:spPr>
<a:xfrm>
<a:off x="3703320" y="731520"/>
<a:ext cx="9806940" cy="7688580"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
<a:noFill/>
<a:ln w="9525">
<a:noFill/>
</a:ln>
</xdr:spPr>
</xdr:pic>
<xdr:clientData/>
</xdr:twoCellAnchor>
</xdr:wsDr>
打开drawing1.xml 可以看到from 标签记录了图片得位置但是使用wps 生成得cellImages如图一所示
生成得是wps 得自定义标签这个没有from 不存储位置信息但是可以看到ID ID_6702DEA2ADBA44AE8C65065BD13FF23D 这个东西
wps 嵌入单元格信息是这样得,只要找出id和图片对应得信息就可以获取到图片
2.wps xml 中找对应关系
//这个是relations
图片存储在以下得位置:
可以看出 ID 关联了rid ,rid 又和图片关联 比如你上传多个图片一样的,引用得其实是一张图片
3.poi 代码解析找出对应关系
首先就要读取一下这个xml
我是使用xmlBean来解析cellimages.xml pio底层也是用这个
主要过程就是-》基于xml 生成xsd 文件->xsd 文件生成java 代码 -》java 代码解析xml 内容获取关系,rid1和图片路径得关系poi 已经支持不用做,获取图片信息得方法poi 也不用做利用poi的方法就可以获取(不会或者不了解xmlBean得可以自己去学习)
1.根据xml 文件成成xsd 文件 下载 Download trang-20091111.jar : trang << t << Jar File Download
java -jar trang.jar cellimages.xml cellimages.xsd
2.下载xmlBean
下载完成后解压
利用scomp 指令生成对用得jar 包
XMLBeans Tools 这个是官方文档
运行指令
scomp -out c:\xmltypes.jar c:\cellimages.xsd -compiler C:\java\jdk1.6.0_10\bin\javac customer.xsdconfig
意思是根据xsd 生成java 解析xml 对应得jar customer.xsdconfig内容如下
<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config"> <xb:namespace> <xb:package>com.chenkang.demo.util.excel</xb:package> </xb:namespace></xb:config>
然后后得到一个jar 包项目值引入依赖
4.开始代码解析
/**
* {ID_581F75328A584939A51CC44E17945975:rid1,ID_6702DEA2ADBA44AE8C65065BD13FF23D:rid1}
* 行rid 以及图片id关系
*
* @param cellImagePart cellImagePart
* @return Map
* @throws Exception 异常
*/
public static Map<String, String> getRidAndPidMap(PackagePart cellImagePart) throws Exception {
CellImagesDocument cellImagesDocument = CellImagesDocument.Factory.parse(cellImagePart.getInputStream());
CellImagesDocument.CellImages cellImages = cellImagesDocument.getCellImages();
Map<String, String> result = new HashMap<>(4);
cellImages.getCellImageList().forEach(cellImage -> {
result.put(cellImage.getPic().getNvPicPr().getCNvPr().getName().getStringValue(), cellImage.getPic().getBlipFill().getBlip().getEmbed());
});
return result;
}
这个就是解析cellImages.xml 来获取rid 和id 得关系
/**
* //relationships 绑定了rid 和 图片 路径得地址
* 获取rid和path的关系
* @param packagePart cellImagePart
* @return Map
* @throws Exception 异常
*/
public static Map<String, String> getRidAndPathMap(PackagePart packagePart) throws Exception {
Map<String, String> ridAndPathMap = new HashMap<>(4);
PackageRelationshipCollection relationships = packagePart.getRelationships();
relationships.forEach(relationship -> ridAndPathMap.put(relationship.getId(), relationship.getTargetURI().getPath()));
return ridAndPathMap;
}
这个是获取rid 和图片路径得关系
/**
*图片ID和 XSSFPictureData
*
* @param workbook workbook
* @return List<Map < String, String>>
* @throws Exception 异常
*/
public static Map<String, XSSFPictureData> getPictureMap(XSSFWorkbook workbook) throws Exception {
OPCPackage opcPackage = workbook.getPackage();
List<PackagePart> partsByContentType = opcPackage.getPartsByContentType("application/vnd.wps-officedocument.cellimage+xml");
PackagePart packagePart = partsByContentType.get(0);
List<XSSFPictureData> allPictures = workbook.getAllPictures();
Map<String,XSSFPictureData> result = new HashMap<>(4);
Map<String, String> ridAndPidMap = getRidAndPidMap(packagePart);
Map<String, String> ridAndPathMap = getRidAndPathMap(packagePart);
ridAndPidMap.forEach((key, value) -> {
String path = ridAndPathMap.get(value);
Optional<XSSFPictureData> first = allPictures.stream().filter(pictureData -> pictureData.getPackagePart().getPartName().getName().equals(path)).findFirst();
result.put(key,first.orElse(null));
});
return result;
}
这一步是来最终映射id 和图片得关系 为什么
List<XSSFPictureData> allPictures = workbook.getAllPictures();
这个能获取图片呢是因为无论是悬浮图片还是嵌入图片他最终都是读取到得是
这个路径
只是说找不到映射关系 再详细得可以去看下源码
最后测试:
public static void main(String[] args) throws Exception {
File file = new File("C:\\Users\\18151\\Desktop\\test.xlsx");
XSSFWorkbook sheets = new XSSFWorkbook(file);
XSSFSheet sheetAt = sheets.getSheetAt(0);
String id=sheetAt.getRow(1).getCell(1).getStringCellValue();
Map<String, XSSFPictureData> pictureMap = WpsImageUtil.getPictureMap(sheets);
System.out.println(pictureMap);
System.out.println(pictureMap.get(StringExtractor.extractID(id)));
}
读取文件,获取到cellValue得到得是
=DISPIMG("ID_C13878DEBED44D23AED14F38392FD788",1) 根据工具类拿到id ,然后再根据映射关系获取到得pictureData 这个直接getData()就是文件流该上传完成业务还是干嘛得都可以
完整得代码详见