使用poi导入图片并生成富文本
用poi做试题导入时,部分试题题干或者答案选项有图片的存在,所以需要获取题干或答案选项对应单元格的图片后存库,然后拼接成富文本用于前端展示。由于excel插入的图片是悬浮在上层的,这里我们获取图片左上角对应的角标作为单元格的角标,所以,导入时图片尽可能放在对应的单元格。
package soohoo;
import cn.hutool.core.io.FileUtil;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import static org.apache.poi.ss.usermodel.CellType.*;
/**
* @author yangyi
* @description
* @date 2020/8/21
*/
public class ImportPictureTest {
private final static String EXCEL_XLSX = "xlsx";
private final static String EXCEL_XLS = "xls";
public static void main(String[] args) throws Exception {
String filePath = "C:\\Users\\123\\Desktop\\图片导入测试.xlsx";
// String filePath = "C:\\Users\\123\\Desktop\\图片导入测试.xls";
Workbook wb = getWorkbook(filePath);
if (wb == null) {
throw new Exception("excel为空!");
}
// Sheet sheet = wb.getSheetAt(0);
Sheet sheet = wb.getSheetAt(1);
StringBuilder html = new StringBuilder();
FileOutputStream os = null;
Map<String, PictureData> pictureDataMap = listSheetPictureData(sheet);
int lastRowNum = sheet.getLastRowNum();
for (int i = 0; i <= lastRowNum; i++) {
Row row = sheet.getRow(i);
short lastCellNum = row.getLastCellNum();
for (int j = 0; j < lastCellNum; j++) {
Cell cell = row.getCell(j);
if (cell == null) {
continue;
}
cell.setCellType(STRING);
String text = cell.getStringCellValue();
html.append(text);
PictureData pictureData = pictureDataMap.get(i + "_" + j);
if (pictureData != null) {
StringBuilder pictureName = new StringBuilder("C:\\Users\\123\\Desktop\\");
pictureName.append(System.currentTimeMillis())
.append("_")
.append(i)
.append("_")
.append(j)
.append(".")
.append(pictureData.suggestFileExtension());
os = new FileOutputStream(pictureName.toString());
os.write(pictureData.getData());
os.flush();
os.close();
html.append("<img src=").append("'").append(pictureName.toString()).append("' />");
}
html.append("<br>");
}
}
String path = "C:\\Users\\123\\Desktop\\test.html";
os = new FileOutputStream(path);
byte[] bytes = html.toString().getBytes(StandardCharsets.UTF_8);
os.write(bytes);
os.flush();
os.close();
}
/**
* 获取sheet中图片的信息
*
* @param sheet sheet
* @return map;key:单元格横坐标纵坐标(图片左上角所在单元格的角标),value:图片信息
*/
private static Map<String, PictureData> listSheetPictureData(Sheet sheet) {
Map<String, PictureData> map = new HashMap<>(16);
Drawing<?> drawingPatriarch = sheet.getDrawingPatriarch();
for (Shape shape : drawingPatriarch) {
if (shape instanceof Picture) {
Picture pic = (Picture) shape;
PictureData pictureData = pic.getPictureData();
ClientAnchor anchor = pic.getClientAnchor();
if (pictureData != null && anchor != null) {
map.put(anchor.getRow1() + "_" + anchor.getCol1(), pictureData);
}
}
}
return map;
}
/**
* 获取excel的workbook
*
* @param filePath excel文件路径
* @return workbook
* @throws IOException IOException
*/
private static Workbook getWorkbook(String filePath) throws IOException {
Workbook wb = null;
String suffix = FileUtil.getSuffix(filePath);
if (EXCEL_XLS.equals(suffix)) {
wb = new HSSFWorkbook(new FileInputStream(filePath));
}
if (EXCEL_XLSX.equals(suffix)) {
wb = new XSSFWorkbook(new FileInputStream(filePath));
}
return wb;
}
}
在实际的试题中,可能存在图片在一段文本的中间,像这样:
想要的富文本应该是这样:
图片<img src="" />描述一个什么情况?
但是poi只能拿到图片所在单元格角标,没法知道图片在文本的哪个位置,得到的富文本将会是这样:
图片描述一个什么情况?<img src="" />
最后的前端展示的效果是: