实现效果类似这样
在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;
}
将这三个方法写在工具类中,在导出的时候直接调用就行了