当前位置:   article > 正文

通过Java批量导出带有图片的Excel文件数据_java导出单个单元格多张图片

java导出单个单元格多张图片

批量导出带有图片的Excel文件

Java通过POI或者一些常见的Excel工具类能够轻易导出后台的结构化数据,但是最近面临一个新需求,需要将对应记录数据和图片网络地址在同一行中导出。

一、思路解析

Excel

一般我们看到的Excel表格是这样的。
首先,我们考虑需要使用List存放每一行的值,并且规定第一行即为表头,从第二行开始是数据。
伪代码是这样的:

List<List<Object>> rowList = new ArrayList<List<Object>>();
// Excel表头
rowList.add(Arrays.asList("序号","标题", "图片"));
for(int i=0;i<3;i++){
	// 每一行的数据
   rowList.add(Arrays.asList(i+1,"test"+(i+1),"imageUrl"+(i+1)));
}
// 调用生成Excel的方法
ExcelUtils.toImportExcel(rowList);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

唯一需要注意的是,跟一般的导出Excel方法不同的是,我们第三列的图片是一个网络URL地址,我们需要将其转成png或者img格式并嵌入到对应的Excel单元格里,这就是比较特别的地方,下文中会着重介绍。

二、关键源码

这里使用POI来解决问题,首先我们需要ExcelUtils工具类

public class ExcelUtils {
	/**
	 * Excel导出设置Workbook
	 * @param title 导出Excel文件名称
	 * @param rowList 第一个List为表头,其余行为表数据
	 * @param downLoadPic 是否下载图片
	 * @throws IOException
	 */
	public static HSSFWorkbook warpSingleWorkbook(String title,List<List<Object>> rowList, Boolean downLoadPic) throws IOException {
		if (rowList == null || rowList.isEmpty()) {
			throw new NullPointerException("the row list is null");
		}
		HSSFWorkbook book = new HSSFWorkbook();
		// 创建表
		HSSFSheet sheet = book.createSheet(title);
		// 设置单元格默认宽度为20个字符
		sheet.setDefaultColumnWidth(20);
		HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
		// 设置表头样式
		HSSFCellStyle style = book.createCellStyle();
		// 设置居左
		style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
		// 检测表头数据(表头不允许数据为空)
		List<Object> head = rowList.get(0);
		// 写数据
		int size = rowList.get(0).size();
		// 第几行
		for (int i = 0; i < rowList.size(); i++) {
			List<Object> row = rowList.get(i);
			if (row == null || row.isEmpty()) {
				book.close();
				throw new NullPointerException("the "+(i+1)+"th row is null");
			}
			if (size != row.size()) {
				book.close();
				throw new IllegalArgumentException("the cell number of "+(i+1)+"th row is different form the first");
			}
			HSSFRow sr = sheet.createRow(i);
			// 第几列
			for (int j = 0; j < row.size(); j++) {
				// 如果是否下载照片选择了true,由于我们的照片放在第三列,即当循环到序列为2的时候获取到网络图片地址,这里还考虑到了有多张照片的情况,且用逗号拼接成多张照片。
				if (downLoadPic && i > 0 && j == 2) {
					if(StringUtils.isNotBlank(row.get(2).toString())){
						sr.setHeight((short) (1800));
						List<String> images = Arrays.asList(row.get(14).toString().split(","));
						int temp = j;
						for(String image : images){
							// 调用封装好的下载图片方法
							drawPictureInfoExcel(book, patriarch, i, j, image);
							j++;
						}
					}
				} else {
					setExcelValue(sr.createCell(j), row.get(j), style);
				}
			}
		}
		return book;
	}

	/**
	 * 设置Excel浮点数可做金额等数据统计
	 * @param cell 单元格类
	 * @param value 传入的值
	 */
	public static void setExcelValue(HSSFCell cell, Object value, HSSFCellStyle style){
		// 写数据
		if (value == null) {
			cell.setCellValue("");
		}else {
			if (value instanceof Integer || value instanceof Long) {
				cell.setCellType(Cell.CELL_TYPE_NUMERIC);
				cell.setCellValue(Long.valueOf(value.toString()));
			} else if (value instanceof BigDecimal) {
				cell.setCellType(Cell.CELL_TYPE_NUMERIC);
				cell.setCellValue(((BigDecimal)value).setScale(3, RoundingMode.HALF_UP).doubleValue());
			} else {
				cell.setCellValue(value.toString());
			}
			cell.setCellStyle(style);
		}
	}

	/**
	 *
	 * @param wb
	 * @param patriarch
	 * @param rowIndex
	 * @param columnIndex
	 * @param pictureUrl
	 */
	private static void drawPictureInfoExcel(HSSFWorkbook wb,HSSFPatriarch patriarch,int rowIndex, int columnIndex,String pictureUrl){
		//rowIndex代表当前行
		try {
			URL url = new URL(pictureUrl);
			//打开链接
			HttpURLConnection conn = (HttpURLConnection)url.openConnection();
			//设置请求方式为"GET"
			conn.setRequestMethod("GET");
			//超时响应时间为5秒
			conn.setConnectTimeout(5 * 1000);
			//通过输入流获取图片数据
			InputStream inStream = conn.getInputStream();
			//得到图片的二进制数据,以二进制封装得到数据,具有通用性
			byte[] data = readInputStream(inStream);
			//anchor主要用于设置图片的属性
			// dx1:起始单元格的x偏移量,
			// dy1:起始单元格的y偏移量,
			// dx2:终止单元格的x偏移量,
			// dy2:终止单元格的y偏移量,
			// col1:起始单元格列序号,从0开始计算;
			// row1:起始单元格行序号,从0开始计算,
			// col2:终止单元格列序号,从0开始计算;
			// row2:终止单元格行序号,从0开始计算,
			HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 250,(short) columnIndex, rowIndex, (short) columnIndex, rowIndex);
			//Sets the anchor type (图片在单元格的位置)
			//0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
			anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE);
			patriarch.createPicture(anchor, wb.addPicture(data, HSSFWorkbook.PICTURE_TYPE_PNG));
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static byte[] readInputStream(InputStream inStream) throws Exception{
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		//创建一个Buffer字符串
		byte[] buffer = new byte[1024];
		//每次读取的字符串长度,如果为-1,代表全部读取完毕
		int len = 0;
		//使用一个输入流从buffer里把数据读取出来
		while( (len=inStream.read(buffer)) != -1 ){
			//用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
			outStream.write(buffer, 0, len);
		}
		//关闭输入流
		inStream.close();
		//把outStream里的数据写入内存
		return outStream.toByteArray();
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

调用规则,从主入口进入方法,这里我们用下载蜡笔小新图片到Excel里为例,找到一张网络URL图片地址为:https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595325136781&di=2f03af92dfac5476b81ad22f426e76ad&imgtype=0&src=http%3A%2F%2Fcdn.duitang.com%2Fuploads%2Fitem%2F201406%2F15%2F20140615002128_eWXnf.jpeg

@ApiOperation(value = "带图片报表导出", notes = "带图片报表导出", httpMethod = "GET")
    @RequestMapping(value = "/importReport", method = RequestMethod.GET)
    public void importReport(HttpServletRequest req, HttpServletResponse res) {
        List<List<Object>> rowList = new ArrayList<List<Object>>();
        // Excel表头
        rowList.add(Arrays.asList("序号","标题", "图片"));
        for(int i=0;i<3;i++){
        	// 下载三张蜡笔小新图片到Excel中
            rowList.add(Arrays.asList(i+1,"test"+(i+1),"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595325136781&di=2f03af92dfac5476b81ad22f426e76ad&imgtype=0&src=http%3A%2F%2Fcdn.duitang.com%2Fuploads%2Fitem%2F201406%2F15%2F20140615002128_eWXnf.jpeg"));
        }
        // 接下来需要调用生成Excel的方法,唯一需要注意的是第三列的图片是一个网络URL地址,我们需要将其转成png或者img格式并嵌入到对应的Excel单元格里
        try {
            HSSFWorkbook wb = ExcelUtils.warpSingleWorkbook("带图片报表", rowList, true);
            res.reset();
            res.setHeader("Content-type","application/octet-stream");
            res.setContentType("application/octet-stream");
            res.setContentType("application/vnd.ms-excel");
            res.setHeader("Accept-Ranges", "bytes");
            String fileName = "带图片报表" + "_" + CalendarUtils.doFormatString(new Date(), CalendarUtils.YYYYMMDDHHmmss) + ".xls";
            fileName = new String(fileName.getBytes(), CommConstants.CHAESET_ZH);
            res.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            // 文件流输出到rs里
            wb.write(res.getOutputStream());
            res.getOutputStream().flush();
            res.getOutputStream().close();
            wb.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

在网页端调用该方法后,导出的报表结果如下所示:
result

三、总结

唯一需要注意的是导出网络图片到Excel需要解析网络图片,且需要设置导出图片的单元格位置,在理清楚需求之后网上有许多已经造好的轮子可以复用。而时间充裕的话,建议大家可以去研究一下文中ExcelUtils工具类中的源码。

参考资料:

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号