记easypoi使用模板导出带图片的excel

2021-03-10 18:07:14  卢浮宫  版权声明:本文为站长原创文章,转载请写明出处


一、背景


    1.1、需求接收

        在2021年3月10日上午接收到一个需求:系统导出的excel文件能不能有图片。


    1.2、需求评估

        ① 早在之前就分享了一篇文章:Excel工具类,支持文件读取及前后端导出

            能让我们更为便利的进行excel文件的导出工作处理,而且easypoi官方也是有支持到图片的导出功能的。

            所以就整体实现来说是没有太大问题的。


二、easypoi进行图片导出分析


    2.1、官方相关说明

        这里简单贴一下:

        


    2.2、简要分析

        ① 官方已经构建了一个ImageEntity的Bean,负责图片资源的处理

        ② ImageEntity的主要内容(com.afterturn.easypoi.entity.ImageEntity)如下:

            

        ③ 如果你使用的是网络或本地资源文件,它会使用ImageIO来转换成字节数组。

           当然如果你使用的已经是byte[]那就更好不过了

        ④ 读取模板数据并绘制workbook,同时携带图片资源数据。简单如下:

            


三、踩坑记录及简要分析


    3.1、说明

        ① 使用easypoi版本为 4.1.0

        ② 这次的踩坑整体来说是因为操作方式和官方处理冲突导致的,那这个冲突是什么,且听我细细道来。


    3.2、关于图片

        我这边使用的是一个网络地址(OSS路径),大致如下:

        https://XXX.oss.com/XXX/images/BHBHBH.png?Expirse=12313&access=XXX.3KhFKDLJAFOOJ...


    3.3、遇到问题

        在创建workbook时数组下标越界异常,简单如下:

            

    

    3.4、问题分析

        ① 我们通过报错信息可以直接定位到PoiPublicUtil的128行,有如下代码:


        public static String getFileExtendName(byte[] photoByte) {
String strFileExtendName = "JPG";
if (photoByte[0] == 71 && photoByte[1] == 73 && photoByte[2] == 70 && photoByte[3] == 56 && (photoByte[4] == 55 || photoByte[4] == 57) && photoByte[5] == 97) {
strFileExtendName = "GIF";
} else if (photoByte[6] == 74 && photoByte[7] == 70 && photoByte[8] == 73 && photoByte[9] == 70) {
strFileExtendName = "JPG";
} else if (photoByte[0] == 66 && photoByte[1] == 77) {
strFileExtendName = "BMP";
} else if (photoByte[1] == 80 && photoByte[2] == 78 && photoByte[3] == 71) {
strFileExtendName = "PNG";
}

return strFileExtendName;
}

        ② 问题很明朗了,是easyPoi在解析图片文件类型上除了问题。断点可以发现入参为空值!

        ③ 顺藤摸瓜我们有找到如下easyPoi在处理图片资源时的一段代码:


        public static byte[] getImage(String imagePath) {
InputStream is = POICacheManager.getFile(imagePath);
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();

Object var4;
try {
BufferedImage bufferImg = ImageIO.read(is);
ImageIO.write(bufferImg, imagePath.substring(imagePath.lastIndexOf(".") + 1, imagePath.length()), byteArrayOut);
byte[] var10 = byteArrayOut.toByteArray();
return var10;
} catch (Exception var8) {
LOGGER.error(var8.getMessage(), var8);
var4 = null;
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(byteArrayOut);
}

return (byte[])var4;
}

        我们可以看到在使用 ImageIO 处理图片资源时,第二个参数使用的字符串截取来确定的。

        如果是XXX.png这些是完全没有问题的,关键是我的图片资源是一个私有读的资源,是有Expirse等参数的。

        而更巧的是其中还包含有点号的,所以这个formateName肯定就不属于jpg、png这些了。


四、解决方案(附部分代码)


    4.1、更换OSS读写权限,优化图片网络地址。

        ① 我们很明确的指导是因为图片路径问题导致ImageIO不能对图片资源做一个有效的转换。那只需要规范我们的图片地址就是可以的了。

        ② 顺带说下:通过设置OSS的读写权限为公共读可以使得图片资源路径没有过期时间这个附加参数。

    

    4.2、相关代码如下

        ① excel参数中增加图片相关属性


Map<String, Object> temp = new HashMap<String, Object>();
ImageEntity image = new ImageEntity();
image.setHeight(200);
image.setWidth(200);
image.setRowspan(4);
image.setColspan(2);
image.setUrl("https://XXX.aliyuncs.com/image/BHCWYZ.png");
temp.put("image", image);
data.put("imageInfo", temp);
Workbook workbook = ExcelExportUtil.exportExcel(params, data);

        ② 在excel模板中定义图片信息

            


        ③ 效果展示

            


六、后记


    ① 这个只能算作是遇到了一个问题,然后查明原因解决一下,涉及到的技术层面的东西比较少。

    ② 就当是做一个记录吧,当然如果你也遇到了类似问题,并且此文对你产生了帮助那也是再好不过的了...

    更多精彩,请持续关注:guangmuhua.com

    


最新评论: