文章目录
- 前言
- 依赖引入
- 导入实现
- 方式一
- 方式二
- 导出参考
前言
最近要实现一个导入导出的功能点,需要能将带图片的列表数据导出到excel中,且可以导入带图片的excel列表数据。
考虑到低代码平台的表头与数据的不确定性,技术框架上暂定使用Apache-POI。
依赖引入
由于POI的包很多种,为了避免引入不全导致的运行报错问题,这里使用Springboot
技术,引入主要依赖如下:
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.1.3</version>
</dependency>
导入实现
经过查阅相关的资料、案例等,目前导入解析有两种方式。
本次自测使用的excel模板如下样式
方式一
该方式可以解析所有的数据,多张图片仅能解析出一张,但不能定位出图片的下标位置信息。仅用于参考。
import org.apache.commons.compress.utils.Lists;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
@RestController
@RequestMapping("/poi")
public class TestController {
/**
* excel上传解析,能获取数据和图片
* 但图片多张只能拿到一张,且无法获取位置点
* @param file
* @return
* @throws IOException
*/
@PostMapping("/upload")
public String upload(MultipartFile file) throws IOException {
List<List<String>> data = Lists.newArrayList();
Workbook workbook = new XSSFWorkbook(file.getInputStream());
Sheet sheet = workbook.getSheetAt(0);
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
List<String> rowData = new ArrayList<>();
Iterator<Cell> cellIterator = row.iterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
rowData.add(getCellValueAsString(cell));
}
data.add(rowData);
}
// 处理图片
List<String> imageList = new ArrayList<>();
List<XSSFPictureData> allPictures = (List<XSSFPictureData>) workbook.getAllPictures();
for (XSSFPictureData pictureData : allPictures) {
byte[] bytes = pictureData.getData();
String mimeType = pictureData.getMimeType();
imageList.add(new String(bytes,"UTF-8"));
}
workbook.close();
return "";
}
private String getCellValueAsString(Cell cell) {
CellType cellType = cell.getCellType();
switch (cellType) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
return String.valueOf(cell.getNumericCellValue());
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
default:
return "";
}
}
}
断点查看导入解析的信息结果,如下所示:
方式二
相比方式一的逻辑,采取一种新的解析方式,迭代 sheet.getDrawingPatriarch()
的结果集进行判断。
但这样只能拿到图片,数据部分可以参考方式一去取。
/**
* excel 上传解析图片
* 多张都能获取,且能获取位置点
* 行 row 与 列 col 从下标 0 开始计算
* @param file
* @return
* @throws IOException
*/
@PostMapping("/upload2")
public String upload2(MultipartFile file) throws IOException {
// 多张图片,以一样的时间戳开头,行与列组成名称
long timeMillis = System.currentTimeMillis();
XSSFWorkbook tempWorkBook = new XSSFWorkbook(file.getInputStream());
// 获取模板sheet页
Sheet sheet = tempWorkBook.getSheetAt(0);
Drawing<?> drawing = sheet.getDrawingPatriarch();
for (Shape shape : drawing) {
if (shape instanceof Picture) {
System.out.println(" ");
Picture picture = (Picture) shape;
ClientAnchor anchor = picture.getClientAnchor();
int row1 = anchor.getRow1();
short col1 = anchor.getCol1();
System.out.println("row:"+row1+" col:"+col1);
PictureData pictureData = picture.getPictureData();
byte[] data = pictureData.getData();
System.out.println(Base64.getEncoder().encodeToString(data));
String imgType = pictureData.suggestFileExtension();
// 将图片保存到项目路径下
OutputStream outputStream = new FileOutputStream(timeMillis+"__"+row1+"_"+col1+"_img."+imgType);
outputStream.write(data);
outputStream.close();
}
}
tempWorkBook.close();
return "";
}
运行后的效果如下所示:
通过控制台中的打印位置信息,对比excel文件,能够定位图片所在单元格。
导出参考
Li-Zzz 的 导出Excel实现一单元格导出多图片