话不多说,先上结果展示
我经常使用的excel的导出库只有EasyExcel 和ApachePoi,但是经过我的研究,发现ApachePoi实现不了在同一个单元格内插入多张图片的需求,及时使用了锚点相关的x1,x2,y1,y2去控制,但是所呈现出来的结果,仅仅是两张图片稍微错开了一小点,所以就放弃了对ApachePoi的研究,转而去研究了EasyExcel
涉及到的Maven坐标如下
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
以下是我所有涉及到的代码
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.util.MapUtils; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import org.apache.poi.ss.usermodel.Cell; import java.util.HashMap; import java.util.List; import java.util.Map; public class AutoColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy { private static final int MAX_COLUMN_WIDTH = 255; //自定义列的列宽 private Map<String, Integer> zdyColumnWidth = MapUtils.newHashMapWithExpectedSize(2); private final Map<Integer, Map<Integer, Integer>> cache = MapUtils.newHashMapWithExpectedSize(8); @Override protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList); if (!needSetWidth) { return; } if (zdyColumnWidth.containsKey(cell.toString())) { writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), zdyColumnWidth.get(cell.toString()) * 256); return; } Map<Integer, Integer> maxColumnWidthMap = cache.get(writeSheetHolder.getSheetNo()); if (maxColumnWidthMap == null) { maxColumnWidthMap = new HashMap<Integer, Integer>(16); cache.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap); } Integer columnWidth = dataLength(cellDataList, cell, isHead); if (columnWidth < 0) { return; } if (columnWidth > MAX_COLUMN_WIDTH) { columnWidth = MAX_COLUMN_WIDTH; } Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex()); if (maxColumnWidth == null || columnWidth > maxColumnWidth) { maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth); writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256); } } private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) { if (isHead) { return cell.getStringCellValue().getBytes().length; } WriteCellData<?> cellData = cellDataList.get(0); CellDataTypeEnum type = cellData.getType(); if (type == null) { return -1; } switch (type) { case STRING: return cellData.getStringValue().getBytes().length; case BOOLEAN: return cellData.getBooleanValue().toString().getBytes().length; case NUMBER: return cellData.getNumberValue().toString().getBytes().length; default: return -1; } } public void setZdyColumnWidth(Map<String, Integer> zdyColumnWidth) { this.zdyColumnWidth = zdyColumnWidth; } }
@Test
void 导出() {
try {
// 指定文件保存的路径
String targetFolderPath = "C:\\Users\\IEBE\\AEDI\\";
File targetFolder = new File(targetFolderPath);
if (!targetFolder.exists()) {
targetFolder.mkdirs(); // 如果文件夹不存在,创建文件夹
}
// 生成文件名
Random random = new Random();
int randomNumber = 10 + random.nextInt(90);
String name = "MultiImagesInSingleCell" + randomNumber + ".xlsx";
String fileName = URLEncoder.encode(name, "UTF-8").replaceAll("\\+", "%20");
AutoColumnWidthStyleStrategy longWidth = new AutoColumnWidthStyleStrategy();
// 创建文件对象
File outputFile = new File(targetFolder, fileName);
List<List<Object>> list = 填充数据(longWidth);
// 使用FileOutputStream写入数据
EasyExcel.write(new FileOutputStream(outputFile))
.head(填充标题())
.registerWriteHandler(longWidth)
.sheet("测试导出")
.doWrite(list);
log.info("+++++++++++++" + name);
} catch (Exception e) {
log.info("导出失败===》[{}]", e);
}
}
private List<List<String>> 填充标题() {
LinkedList<List<String>> list = new LinkedList<>();
List<String> head1 = List.of("个人信息", "姓名");
list.add(head1);
List<String> head2 = List.of("个人信息", "年龄");
list.add(head2);
List<String> head3 = List.of("个人信息", "性别");
list.add(head3);
List<String> head4 = List.of("图片", "图片");
list.add(head4);
return list;
}
private List<List<Object>> 填充数据(AutoColumnWidthStyleStrategy longWidth) {
List<List<Object>> list = new LinkedList<>();
for (int j = 0; j < 10; j++) {
int i = 0;
List<Object> row = new ArrayList<>();
row.add(i++, "张三");
row.add(i++, "男");
row.add(i++, "13");
i = 填充图片(row, i, longWidth, List.of(
"C:\\Users\\23606\\Desktop\\图片测试\\a.png",
"C:\\Users\\23606\\Desktop\\图片测试\\b.png",
"C:\\Users\\23606\\Desktop\\图片测试\\c.png",
"C:\\Users\\23606\\Desktop\\图片测试\\d.png"));
list.add(row);
}
return list;
}
private int 填充图片(List<Object> row, int index, AutoColumnWidthStyleStrategy longWidth, List<String> imagePaths) {
final Integer[] sumWidthArray = {120};
imagePaths.forEach(item -> {
//每张图片间距
Integer splitWidth = 2;
//每张图片的长度
Integer imageWidth = 60;
//图片列的最大长度
sumWidthArray[0] = imagePaths.size() * (imageWidth + splitWidth);
});
//每张图片间距
Integer splitWidth = 2;
//每张图片的长度
Integer imageWidth = 60;
//图片列的最大长度
Integer sumWidth = imagePaths.size() * (imageWidth + splitWidth);
WriteCellData<Void> writeCellData = new WriteCellData<>();
List<ImageData> imageDataList = new ArrayList<>();
for (int i = 1; i <= imagePaths.size(); i++) {
Integer left = imageWidth * (i - 1) + i * splitWidth;
Integer right = sumWidth - imageWidth - left;
ImageData imageData = new ImageData();
byte[] bytes = null;
InputStream inputStream = null;
ByteArrayOutputStream outputStream = null;
try {
inputStream = new FileInputStream(imagePaths.get(i - 1));
outputStream = new ByteArrayOutputStream();
// 对图片进行压缩
Thumbnails.of(inputStream).scale(0.9f).outputQuality(0.3f).toOutputStream(outputStream);
bytes = outputStream.toByteArray();
} catch (IOException e) {
log.error(e.getMessage(), e);
continue;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (bytes.length < 1) {
continue;
}
imageData.setImage(bytes);
imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_JPEG);
//距离单元格顶部距离
imageData.setTop(1);
//距离单元格底部距离
imageData.setBottom(1);
//距离单元格左边距离
imageData.setLeft(left);
//距离单元格右边距离
imageData.setRight(right);
imageData.setAnchorType(ClientAnchorData.AnchorType.DONT_MOVE_DO_RESIZE);
imageDataList.add(imageData);
}
writeCellData.setImageDataList(imageDataList);
writeCellData.getType();
Map<String, Integer> zdyColumnWidth = new HashMap<>();
//图片列名称,对应导出对象的列名称,图片列长度
zdyColumnWidth.put("图片", sumWidthArray[0] / 6);
longWidth.setZdyColumnWidth(zdyColumnWidth);
row.add(index++, writeCellData);
return index;
}