java导出excel使用poi实现同一单元格既有图片又有文本

本文介绍如何使用Java的POI库在Excel中插入图片,包括获取HSSFPatriarch对象、创建HSSFClientAnchor及调用createPicture方法的具体步骤。同时,分享了在大量数据导出时,如何解决单个sheet行数限制的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现效果类似这样 

       在POI中有HSSFPatriarch对象,该对象为画图的顶级管理器,它的createPicture(anchor, pictureIndex)方法就能够在Excel插入一张图片。所以要在Excel中插入图片,三步就可以搞定。一、获取HSSFPatriarch对象,二、new HSSFClientAnchor对象,三、调用createPicture方法即可。实现倒是非常容易实现,如果想把它做好还是有点儿难度的。这里我们先插入一张图片:

 

这里我是要将题库中的试题导出 其中有些题目中包含图片,有些答案中包含图片,图片和文本是以“四种烷基自由基的稳定性大小顺序是:<img src="/项目名/ExcelImg/184DECC9F108774332BD0D7D6F086B70C5.png" alt="184DECC9F108774332BD0D7D6F086B70C5.png" height="100px" width="100px">” 这种形式保存在数据库字段中,所以要获取单元格的值再将html代码分离出来,使用addImgdata()分离html代码,使用getImgs()取出html代码中的图片路径

将要导的包也写进来 方法即拿即用,类自己建

1.导出excel主方法

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.Region;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Font;

/**
 * @Desc 题库导出excel含有图片和数据
 * @Date 2019-11-29 14:02
 * @param request
 * @param response 
 * @param headers String[] headers = new String[] { "试题类型", "试题一级分类","试题二级分类","试题三级分类", "难度等级", "试题描述", "选择题A描述",
                "选择题B描述", "选择题C描述","选择题D描述","答案","选择题E描述", "选择题F描述","选择题G描述","选择题H描述","选择题I描述","选择题J描述","题目解析"};
 * @param excelData  数据
 * @param title  导出的excel文件名
	 
 */  
public static void createSimpleExcelQ(HttpServletRequest request,HttpServletResponse response,String[] headers, List<String[]> excelData, String title){
		    OutputStream outputStream = null;
		
		try {
		//清空response
		response.reset();//需要此步骤
		//设置文件内容下载方式
		response.setHeader("Content-Disposition","attachment;filename="+toUtf8String(title+".xls"));//new String((title+".xls").getBytes("utf-8"), "iso-8859-1"));
		//设置以excel方式
		response.setContentType("application/vnd.ms-excel; charset=UTF-8");
		// 创建一个 workbook,对应一个Excel文件
		HSSFWorkbook workbook = new HSSFWorkbook();
		int sheetSize = 0;
		if (excelData.size()%60000>0){
			sheetSize = excelData.size()/60000+1;
		}else {
			sheetSize = excelData.size()/60000;
		}
		for (int z = 0;z<sheetSize;z++){
			// 在 workbook 中添加一个 sheet,对应 Excel 文件中的 sheet
			String sheetName = z*60000 + "-" + (z+1)*60000;
			if ((z+1)*60000 > excelData.size()){
				sheetName = z*60000 + "-" + excelData.size();
			}
			HSSFSheet sheet = workbook.createSheet(sheetName);
			
			//画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
			HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
			
			//创建字体-设置
			Font titleFont = workbook.createFont();
			titleFont.setFontHeightInPoints((short)20);
			titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
			//创建样式-设置
			HSSFCellStyle style = workbook.createCellStyle();
			style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
			style.setFont(titleFont);
			//设置默认列的宽度
			sheet.setDefaultColumnWidth(35);
			//合并单元格
			sheet.addMergedRegion(new Region((short)0 , (short) 0, (short)0, (short)(excelData.get(0).length-1)));
			//第一行作为标题
			HSSFRow row0 = sheet.createRow((int) 0);
			//设置行高
			row0.setHeight((short)800);
			// 创建第 i 个单元格
			HSSFCell createCell = row0.createCell(0);
			// 给单元格赋值
			createCell.setCellValue(title);
			// 设置单元格格式
			createCell.setCellStyle(style);

			

			// 在 sheet 中添加第 2行(表头)
			HSSFRow row = sheet.createRow((int) 1);
			//创建字体-设置
			Font tFont = workbook.createFont();
			tFont.setFontHeightInPoints((short)15);
			tFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
			//创建样式-设置
			HSSFCellStyle tStyle = workbook.createCellStyle();
			tStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
			tStyle.setFont(tFont);
			HSSFCell cell = null;
			// 创建单元格
			for (int i = 0; i < headers.length; i++) {
				// 创建第 i 个单元格
				cell = row.createCell(i);
				row.setHeight((short)500); //设置行高
				// 给单元格赋值
				cell.setCellValue(headers[i]);
				// 设置单元格格式
				cell.setCellStyle(tStyle);
			}
			//创建字体-设置
			Font cFont = workbook.createFont();
			cFont.setFontHeightInPoints((short)15);
			cFont.setBoldweight(Font.BOLDWEIGHT_NORMAL);
			//创建样式-设置
			HSSFCellStyle cStyle = workbook.createCellStyle();
			cStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
			cStyle.setFont(cFont);
			cStyle.setWrapText(true);  //自动换行设置
			// 将数据写入 Excel 中
			int maxData = (z+1)*60000;
			if ((z+1)*60000>excelData.size()){
				maxData = excelData.size();
			}
			for (int i = z*60000; i < maxData; i++) {
				// 创建数据行
				row = sheet.createRow(i - z*60000 + 2);
				row.setHeight((short)1000); //设置行高
				// 获取当前行数据
				String[] rowData = excelData.get(i);
				for (int j = 1; j <= rowData.length; j++) {
					if (rowData[j - 1] != null) {
						// 创建单元格,并设置值
						HSSFCell createCell2 = row.createCell(j - 1);
						BufferedImage bufferImg = null;
						ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
						String rowDataAndPath = addImgdata(rowData[j - 1]);
						String rowdata = "";
						if(rowDataAndPath.indexOf("---") > -1) {
							String path = rowDataAndPath.split("---")[1];
							rowdata = rowDataAndPath.split("---")[0];
							//获得图片的绝对路径
							String absoluteUrl = request.getSession().getServletContext().getRealPath("/")+path.replace((request.getSession().getServletContext().getContextPath()+"/").replaceAll("/", "\\\\"), "");
							File file = new File(absoluteUrl);
							if(file.exists()) {
								
								bufferImg = ImageIO.read(file);
								ImageIO.write(bufferImg, "jpg", byteArrayOut);
								//anchor主要用于设置图片的属性
								HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 600, 200,(short) (j-1), (i+2), (short) (j-1), (i+2));
								patriarch.createPicture(anchor, workbook.addPicture(byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));
							}
						}else {
							rowdata = rowData[j-1];
						}
						
						createCell2.setCellValue(rowdata);
						createCell2.setCellStyle(cStyle);
					}

				}
			}
		}

			// 创建输出流,并将 Excel 保存到本地
			outputStream = response.getOutputStream();
			// 将 workbook 写入输出流中
			workbook.write(outputStream);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭 outputStream
				outputStream.flush();
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

这里由于导出的题库数量较多,poi导出excel时单个sheet最多只能支持60000行数据,所以分了多个sheet导出数据。 

还有一个new HSSFClientAnchor(0, 0, 600, 200,(short) (j-1), (i+2), (short) (j-1), (i+2));这里的参数设置根据自己的喜好设置图片位置和大小

HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2)

dx1 dy1 起始单元格中的x,y坐标.

dx2 dy2 结束单元格中的x,y坐标

col1,row1 指定起始的单元格,下标从0开始

col2,row2 指定结束的单元格 ,下标从0开始

 来张图更容易说明:

2.分离html代码方法 

/**
	 * 将单元格数据中的文字和图片html代码分离
	 * @param rowData
	 * @param request
	 * @return
	 */
	public static String addImgdata(String rowData) {
		String regEx_html="<[^>]+>"; //定义HTML 标签的正则表达式
		Pattern p_html= Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
		Matcher m_html=p_html.matcher(rowData);
		String picturePath = "";
		if(m_html.find()) {
			String html = m_html.group()!=null?m_html.group().trim() : "";//获得html代码
			if(!html.equals("")) {
				picturePath = getImgs(html);
			}
		}
		rowData = m_html.replaceAll("---")+picturePath;  //将文本与图片路径拼接
		return rowData;
	}

3.分离html代码中的图片路径 

/**
	 * 获取html代码中的图片地址
	 * @param html
	 * @param request
	 */
	public static String getImgs(String html) {
		String img = "";  
		Pattern p_image;  
		Matcher m_image;  
		String str = "";  
		String[] images = null;  
		String regEx_img = "(<img.*src\\s*=\\s*(.*?)[^>]*?>)";  
		p_image = Pattern.compile(regEx_img, Pattern.CASE_INSENSITIVE);  
		m_image = p_image.matcher(html);  
		while (m_image.find()) {  
			img = m_image.group();  
			Matcher m = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)").matcher(img);  
			while (m.find()) {  
				String tempSelected = m.group(1);  

				if ("".equals(str)) {  
					str = tempSelected;  
				} else {  
					String temp = tempSelected;  
					str = str + "," + temp;  
				}  
			}  
		}  
		if (!"".equals(str)) {  
			images = str.split(",");  
		}  
	    String picUrl = images[0].replaceAll("/", "\\\\");
//      获取第一张图片地址 :\项目名\ExcelImg\1352D2BCE3655F431A9660E77560BECD39.png
		return picUrl;
	}

将这三个方法写在工具类中,在导出的时候直接调用就行了 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值