<!-- easyexcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.0.5</version> </dependency> <dependency> <groupId>net.sf.jxls</groupId> <artifactId>jxls-core</artifactId> <version>1.0.6</version> </dependency>读取图片核心代码如下:
Workbook workbook = WorkbookFactory.create(inputStream); // 堆代码 duidaima.com // 默认读取第一页 XSSFSheet sheet = (XSSFSheet) workbook.getSheetAt(0); List<POIXMLDocumentPart> documentPartList = sheet.getRelations(); for (POIXMLDocumentPart part : documentPartList) { if (part instanceof XSSFDrawing) { XSSFDrawing drawing = (XSSFDrawing) part; List<XSSFShape> shapes = drawing.getShapes(); for (XSSFShape shape : shapes) { XSSFPicture picture = (XSSFPicture) shape; XSSFClientAnchor anchor = picture.getPreferredSize(); CTMarker marker = anchor.getFrom(); int row = marker.getRow(); int col = marker.getCol(); // 从第2行开始 if (row > 0 && row <= size) { PictureData pictureData = picture.getPictureData(); String extension = pictureData.suggestFileExtension(); byte[] bytes = pictureData.getData(); } } } }读取图片流程:
@ExcelProperty("姓名") private String name; @ExcelProperty(value = "图片") private String imageStr;首先配置一个 ExcelImageProperty 注解,确定「哪列的图片需要赋值给对应的图片字段」:
@Inherited @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelImageProperty { String[] value() default {""}; /** * 图片在第几列 1开始 * @return */ int index() default -1; }imageStr 对应第二列,字段上 ExcelImageProperty 注解的 index = 2,上面的实体修改如下:
@ExcelProperty("姓名") private String name; @ExcelProperty(value = "图片") @ExcelImageProperty(index = 2) private String imageStr;写好实体和注解后,再写一个工具类。
@Slf4j public class ExcelReadImageUtil { public static <T> void readImage(InputStream inputStream, List<T> list) { try { Workbook workbook = WorkbookFactory.create(inputStream); // 默认读取第一页 XSSFSheet sheet = (XSSFSheet) workbook.getSheetAt(0); List<POIXMLDocumentPart> documentPartList = sheet.getRelations(); Integer size = list.size(); for (POIXMLDocumentPart part : documentPartList) { if (part instanceof XSSFDrawing) { XSSFDrawing drawing = (XSSFDrawing) part; List<XSSFShape> shapes = drawing.getShapes(); for (XSSFShape shape : shapes) { XSSFPicture picture = (XSSFPicture) shape; XSSFClientAnchor anchor = picture.getPreferredSize(); CTMarker marker = anchor.getFrom(); int row = marker.getRow(); int col = marker.getCol(); // 从第2行开始 if (row > 0 && row <= size) { PictureData pictureData = picture.getPictureData(); String extension = pictureData.suggestFileExtension(); byte[] bytes = pictureData.getData(); InputStream imageInputStream = new ByteArrayInputStream(bytes); //String url = iTxCosService.uploadFile(new ByteArrayInputStream(bytes), UUID.randomUUID() + "." + extension); for (int i = 0; i < size; i++) { T item = list.get(i); Class clazz = item.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(ExcelImageProperty.class)) { ExcelImageProperty excelImageProperty = field.getAnnotation(ExcelImageProperty.class); int index = excelImageProperty.index(); if (index == col + 1 && row - 1 == i) { field.setAccessible(true); field.set(item,new String(bytes)); } } } } } } } } } catch (IOException | IllegalAccessException e) { e.printStackTrace(); log.error("read image error {}",e); } } }传参一个列表,通过获取读取输入流获取到图片,赋值给对应的字段。
2.使用 poi 读取图片,第二行读取数据,遍历每列数据,符合注解字段就赋值。一般获取到输入流后会上传图片,返回一个地址,这里仅仅就获取字节流,赋值给对应的字段。
InputStream inputStream = multipartFile.getInputStream(); List<DemoExcelInput> demoExcelInputs = EasyExcelFactory.read(multipartFile.getInputStream()).head(DemoExcelInput.class).sheet().doReadSync(); ExcelReadImageUtil.readImage(inputStream,demoExcelInputs);inputStream 不能重复使用,不然会报错 inputStream close 错误。
自定义转换器
@Data public class DemoExcelInput { @ExcelProperty("姓名") private String name; @ExcelProperty(value = "图片",converter = ExcelUrlImageConverter.class) private String imageStr; @ExcelProperty("url") private URL imageUrl; @ExcelProperty("inputstream") private InputStream inputStream; @ExcelProperty("bytes") private byte[] bytes; }读取图片
List<DemoExcelInput> demoExcelInputs = new ArrayList<>(); DemoExcelInput demoExcelInput = new DemoExcelInput(); demoExcelInput.setName("aa"); String url = "https://p26-passport.byteacctimg.com/img/user-avatar/82b069ce17bb5b0eccb7ee67d3f6f3bc~180x180.awebp"; demoExcelInput.setImageStr(url); demoExcelInput.setImageUrl(new URL(url)); demoExcelInputs.add(demoExcelInput); InputStream inputStream = new URL(url).openStream(); demoExcelInput.setInputStream(inputStream); byte[] bytes = IoUtils.toByteArray(new URL(url).openStream()); demoExcelInput.setBytes(bytes); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 String fileName= "导出excel模板"; String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20"); response.setHeader("Content-disposition","attachment;filename*=utf-8''"+encodedFileName+".xlsx"); EasyExcel.write(response.getOutputStream(),DemoExcelInput.class).sheet("模板").doWrite(demoExcelInputs);导出文件截图:
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.WriteConverterContext; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.util.IoUtils; import com.alibaba.excel.util.StringUtils; import java.io.InputStream; import java.net.URL; public class ExcelUrlImageConverter implements Converter<String> { @Override public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) throws Exception { String urlString = context.getValue(); if (StringUtils.isBlank(urlString)) { return new WriteCellData<>(""); } URL url = new URL(urlString); InputStream inputStream = url.openStream(); byte[] bytes = IoUtils.toByteArray(inputStream); return new WriteCellData<>(bytes); } }将读取到图片流转到对象 WriteCellData 中,就能写图片了。