Apache组件POI,将图片下载到Excel文件中并导出。

文章介绍了如何利用ApachePOI库将数据库中图片字段的数据下载到Excel文件中,特别指出3.17版本的POI依赖是关键,而高版本可能存在不兼容问题。在处理大量图片时,由于逐个调用URL获取图片数据可能导致超时和网络IO问题,这是性能瓶颈所在。作者提供了Gitee上的Demo案例供参考。
摘要由CSDN通过智能技术生成

      在日常的工作中,有时我们会遇到需要将数据库表中图片字段下载到Excel中的需求,为方便各位小伙伴今后的开发工作,我将分享出自己写的代码,并指出图片下载到Excel文件中的性能瓶颈问题。 在文章末尾有我上传到 Gitee 上的 Demo案例,希望大家喜欢。

      将图片下载到Excel文件中并导出,先看一下效果。

1、使用的 POI 依赖

     需要说明的是: commons-io 依赖必须有,不然在编写代码的过程中会异常。由于 POI 组件版本升级的问题,本文分享的代码适合 3.17 版本的依赖,版本太高的jar包可能不适合。

     在我自己学习、测试过程中,5.2.0版本的POI组件Jar包就不适合本文的代码。 

<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.11.0</version>
</dependency>

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>3.17</version>
	<!--<version>5.2.0</version>-->
</dependency>

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.17</version>
	<!--<version>5.2.0</version>-->
</dependency>



2、关键部分代码展示

      在以下的函数中,大体分为以下几步:

      2-1、查询获取结果值:userVOList ,并将其转成导出 exportVOS ;

      2-2、创建工作簿对象workbook,并因此创建工作表对象 sheet ;

      2-3、对工作表 sheet工作表对象 设置头部标题数据、头部标题样式;

      2-4、对 sheet工作表对象 填充数据,这些数据分为普通文本数据、图片数据。

      2-5、将工作簿对象 workbook 输出。  


/***
     * 用户信息 导出
     *
     * @param paramDTO  用户入参DTO
     * @param response  response请求
     *
     * @return
     * @author moon  2023/6/27 10:31
     */
    @Override
    public void exportUser(UserParamDTO paramDTO, HttpServletResponse response) throws Exception {

        // 1-1、获取列表查询数据
        List<UserVO> userVOList = userMapperExt.selectUserByParamDTO(paramDTO);

        // 1-2、将 UserVO 转成 UserExportVO
        List<UserExportVO> exportVOS = userVOList.stream().map(infoVO -> BeanUtils.convert(infoVO, UserExportVO.class)).collect(Collectors.toList());

        //空数据导出不了标题 需要放一个空对象
        if (CollectionUtils.isEmpty(exportVOS)) {
            exportVOS = new ArrayList<>();
        }

        // Map<'英文名', '中文名'> 组合形式.
        Map<String, String> aliasMap = ExcelUtils.getDTOAliasTitle(UserExportVO.class, Constant.BooleanFlag.FALSE);

        List<String> headerList = new ArrayList<>(aliasMap.keySet());
        // 2-1、创建 工作簿 对象.
        Workbook workbook = new XSSFWorkbook();
        // 2-2、创建工作表对象
        Sheet sheet = workbook.createSheet();
        // 设置标题行,第0行.
        Row headerRow = sheet.createRow(Constant.Digital.ZERO);

        // 获取头部单元格样式
        CellStyle headerCellStyle = ExcelUtils.getCellStyle(workbook, HorizontalAlignment.CENTER, VerticalAlignment.CENTER, Constant.Digital.ONE);
        // 2-3、设置头部单元格样式
        for (int i = 0; i < headerList.size(); i++) {
            // 获取中文值
            String value = aliasMap.get(headerList.get(i));
            Cell cell = headerRow.createCell(i);
            // 设置 样式
            cell.setCellStyle(headerCellStyle);
            // 设置 值
            cell.setCellValue(value);
        }

        
        // 2-4、填充单元格数据
        for (int i = 0; i < exportVOS.size(); i++) {

            // 创建行对象,从第1行开始。
            int rowNum = i + 1;
            Row row = sheet.createRow(rowNum);
            UserExportVO tempVO = exportVOS.get(i);

            // 创建单元格对象(列)并设置值
            for (int j = 0; j < headerList.size(); j++) {
                Cell cell = row.createCell(j);
                Field field = UserExportVO.class.getDeclaredField(headerList.get(j));
                // 若属性为私有,需要设置可访问。
                field.setAccessible(Constant.BooleanFlag.TRUE);
                String fieldName = field.getName();
                String fieldValue;
                if (Objects.isNull(field.get(tempVO))) {
                    fieldValue = Constant.CommonlySymbols.EMPTY;
                } else {
                    fieldValue = field.get(tempVO).toString();
                }

                if (StringUtils.equalsAny(fieldName, UserVO.FIELD_HEAD_PHOTO, UserVO.FIELD_SCHOOL_PHOTO)
                        && StringUtils.isNotBlank(fieldValue)) {  // 2个图片字段,需要特殊处理.

                    // 构造 URL
                    String path = field.get(tempVO).toString();
                    URL url = new URL(path);
                    // 打开连接
                    URLConnection con = url.openConnection();
                    //设置请求超时为5s
                    con.setConnectTimeout(8 * 1000);
                    // 输入流
                    InputStream is = con.getInputStream();
                    byte[] bytes = IOUtils.toByteArray(is);
                    @SuppressWarnings("static-access")
                    int pictureIdx = workbook.addPicture(bytes, workbook.PICTURE_TYPE_PNG);  // 添加图片到工作簿中

                    CreationHelper helper = workbook.getCreationHelper();  // 获取创建帮助类
                    Drawing drawing = sheet.createDrawingPatriarch();   // 获取绘图父对象
                    ClientAnchor anchor = helper.createClientAnchor();  // 创建客户端锚点
                    // 图片插入坐标
                    anchor.setCol1(j);  // 设置图片左上角的列数
                    anchor.setRow1(rowNum);  // 设置图片左上角的行数
                    // 插入图片
                    Picture pict = drawing.createPicture(anchor, pictureIdx);  // 在指定位置插入图片

                    // 设置 单元格高度
                    cell.getRow().setHeight((short) 1000);  // 将单元格所在行的高度设置为1000
                    // 设置 单元格宽度
                    sheet.setColumnWidth(cell.getColumnIndex(), 2600);  // 将单元格所在列的宽度设置为2600
                    // 设置图片宽、高放缩比例
                    pict.resize(1, 1);  // 这行代码,可以将值设置成 pict.resize(0.5, 0.5)、pict.resize(2, 2),看看效果如何。

                } else {
                    cell.setCellValue(fieldValue);
                }
            }
        }

        
        // 将工作簿写入文件中
        try {

            response = ExcelUtils.getHttpServletResponse(response, Constant.ExcelProperty.USER_EXPORT_NAME);
            ServletOutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
        } finally {
            workbook.close();
        }

    }




       由于数据库表中存在的是图片的URL地址,在获取图片信息时,需要逐个调用URL获取数据,当图片数据量较大时,会出现超时问题、网络IO问题,这也是图片下载的瓶颈所在。   

3、使用Postman进行测试

3-1、测试的URL:http://localhost:8080/user/exportUser

3-2、入参参数:

{
  "age": "",
  "createDate": "",
  "distinct": true,
  "id": "",
  "isDeleted": "",
  "name": ""
}


3-3、返回结果:

    在之后的时间里,我将还会分享 Excel勾选导出 代码案例,希望能够帮到大家。

Gitee上的Demo案例:  apache-poi-demo   ,项目名称:apache-poi-demo .             

入口函数:com.moon.poi.service.impl.UserServiceImpl#exportUser(...)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值