在日常的工作中,有时我们会遇到需要将数据库表中图片字段下载到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*/@Overridepublic void exportUser(UserParamDTO paramDTO, HttpServletResponse response) throws Exception {// 1-1、获取列表查询数据List<UserVO> userVOList = userMapperExt.selectUserByParamDTO(paramDTO);// 1-2、将 UserVO 转成 UserExportVOList<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个图片字段,需要特殊处理.// 构造 URLString path = field.get(tempVO).toString();URL url = new URL(path);// 打开连接URLConnection con = url.openConnection();//设置请求超时为5scon.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(...)