Java?EasyExcel導(dǎo)入帶圖片的完整過(guò)程記錄
前言
項(xiàng)目中,要求批量導(dǎo)入 Excel 數(shù)據(jù)并讀取其中圖片,目前 EasyExcel 不支持讀取圖片,因此需要使用 Apache POI 進(jìn)行導(dǎo)入。然而Apache POI 需要開發(fā)者手動(dòng)管理行、列、單元格等對(duì)象,相對(duì)較為底層且繁瑣。
作者隨即想到了一種方法,既能夠使用 EasyExcel 的簡(jiǎn)便導(dǎo)入方式,又能夠識(shí)別圖片并進(jìn)行處理。
相關(guān)依賴
<!-- Apache POI --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.2.1</version> </dependency>
Java 代碼展示
import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.util.ListUtils; import com.bi.my.vo.ExcelVo; import lombok.extern.slf4j.Slf4j; import net.dreamlu.mica.core.result.R; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.*; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * 數(shù)據(jù)+圖片導(dǎo)入 * * @author wss */ @Slf4j @RestController @RequestMapping("/easy") public class EasyExcelController { /** * 數(shù)據(jù)導(dǎo)入并識(shí)別圖片 * * @param file file * @return R<Object> * @author wss */ @PostMapping("/import") public R<Object> dataImport(@RequestParam("file") MultipartFile file) { List<ExcelVo> excelVos = new ArrayList<>(); //數(shù)據(jù)處理 this.dataProcess(file, excelVos); //圖像處理 this.imageProcess(file, excelVos); //返回結(jié)果,這里也可以處理excelVos數(shù)據(jù),如往mysql存儲(chǔ) return R.success(excelVos); } /** * 圖片處理 */ public void imageProcess(MultipartFile file, List<ExcelVo> excelVos) { try { XSSFWorkbook book = new XSSFWorkbook(file.getInputStream()); //方式1 獲取sheet數(shù)量,采用下標(biāo)方式遍歷讀取每個(gè)工作表數(shù)據(jù) int sheetsNos = book.getNumberOfSheets(); for (int sheetNo = 0; sheetNo < sheetsNos; sheetNo++) { Sheet sheet = book.getSheetAt(sheetNo); //...省略,內(nèi)容為方式2 } //方式2 獲取sheet數(shù)量,直接遍歷讀取每個(gè)工作表數(shù)據(jù) for (Sheet sheet : book) { XSSFSheet xssSheet = (XSSFSheet) sheet; //獲取工作表中繪圖包 XSSFDrawing drawing = xssSheet.getDrawingPatriarch(); if (drawing == null) { break; } //獲取所有圖像形狀 List<XSSFShape> shapes = drawing.getShapes(); //遍歷所有形狀 for (XSSFShape shape : shapes) { //獲取形狀在工作表中的頂點(diǎn)位置信息(anchor錨點(diǎn)) XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor(); //圖片形狀在工作表中的位置, 所在行列起點(diǎn)和終點(diǎn)位置 short c1 = anchor.getCol1(); int r1 = anchor.getRow1(); String key = r1 + "行," + c1 + "列"; if (shape instanceof XSSFPicture) { try { XSSFPicture pic = (XSSFPicture) shape; //形狀獲取對(duì)應(yīng)的圖片數(shù)據(jù) XSSFPictureData picData = pic.getPictureData(); //保存圖片到本地 byte[] data = picData.getData(); //TODO 這里上傳文件至oss并生成鏈接,這里不做過(guò)多描述,有疑問(wèn)請(qǐng)參照oss服務(wù)調(diào)用 String fileName = "https://oss.cn/" + DateUtil.today() + "/" + IdUtil.simpleUUID() + "/" + picData.suggestFileExtension(); //fileTemplate.putObject(properties.getBucketName(), fileName, new ByteArrayInputStream(data)); //TODO 放入excel集合,這里行數(shù)要減去1,獲取圖片是從表頭開始(表頭位置為0),獲取excelVos是從數(shù)據(jù)開始(第一條數(shù)據(jù)位置為0)他們相差一個(gè)表頭,所以要減去1才能對(duì)應(yīng) excelVos.get(r1 - 1).setPicture(fileName); } catch (Exception e) { log.error("asyncImportList XSSFClientAnchor key|{} error|{}", key, e.getMessage()); } } } } } catch (Exception e) { log.error("asyncImportList XSSFWorkbook error|{}", e.getMessage()); } } /** * 數(shù)據(jù)處理 */ public void dataProcess(MultipartFile file, List<ExcelVo> excelVos) { // 這里默認(rèn)讀取第一個(gè)sheet try { EasyExcel.read(file.getInputStream(), ExcelVo.class, new ReadListener() { /** * 單次緩存的數(shù)據(jù)量 */ public static final int BATCH_COUNT = 100; /** *臨時(shí)存儲(chǔ) */ private List<ExcelVo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); @Override public void invoke(Object object, AnalysisContext context) { ExcelVo data = (ExcelVo) object; cachedDataList.add(data); if (cachedDataList.size() >= BATCH_COUNT) { saveData(); // 存儲(chǔ)完成清理 list cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } } @Override public void doAfterAllAnalysed(AnalysisContext context) { saveData(); } /** * 加上存儲(chǔ)數(shù)據(jù)庫(kù) */ private void saveData() { log.info("已獲取數(shù)據(jù)|{}條", cachedDataList.size()); excelVos.addAll(cachedDataList); } }).sheet().doRead(); } catch (IOException e) { e.printStackTrace(); } } }
import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; /** * 導(dǎo)入VO * * @author wss */ @Data public class ExcelVo { @ExcelProperty("序號(hào)") private Integer ordinal; @ExcelProperty("標(biāo)題") private String title; @ExcelProperty("圖片") private String picture; }
Excel 表格準(zhǔn)備
excel表頭需和實(shí)體字段相對(duì)應(yīng)
Postman 調(diào)用測(cè)試
打開圖片鏈接發(fā)現(xiàn)與excel中圖片一致,對(duì)應(yīng)數(shù)據(jù)一致,讀取圖片成功!
結(jié)尾
到這里,EasyExcel 導(dǎo)入帶圖片已完成!讀取圖片速度較慢,可以通過(guò)異步或其它方式優(yōu)化處理,根據(jù)自己需求修改即可,這里就不進(jìn)行說(shuō)明了。
補(bǔ)充
項(xiàng)目中本人是通過(guò)@RequestExcel注解直接獲取的excel數(shù)據(jù),file專用于圖片讀取,即方法中不用再進(jìn)行數(shù)據(jù)處理,代碼更加簡(jiǎn)化。
這篇文章主要是用來(lái)處理讀取圖片的,這里就不再詳細(xì)說(shuō)明該注解了,感興趣的小伙伴可以查閱一下相關(guān)資料。
/** * 數(shù)據(jù)導(dǎo)入并識(shí)別圖片 * * @param file file * @return R<Object> * @author wss */ @PostMapping("/import") public R<Object> dataImport(@RequestParam("file") MultipartFile file, @RequestExcel List<ExcelVo> excelVos) { //圖像處理 this.imageProcess(file, excelVos); //返回結(jié)果,這里也可以處理excelVos數(shù)據(jù),如往庫(kù)里存儲(chǔ) return R.success(excelVos); }
到此這篇關(guān)于Java EasyExcel導(dǎo)入帶圖片的文章就介紹到這了,更多相關(guān)Java EasyExcel導(dǎo)入帶圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中EasyExcel實(shí)現(xiàn)Excel文件的導(dǎo)入導(dǎo)出
- SpringBoot集成EasyExcel實(shí)現(xiàn)Excel導(dǎo)入的方法
- SpringBoot整合EasyExcel實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出
- java使用EasyExcel導(dǎo)入導(dǎo)出excel
- Java+EasyExcel實(shí)現(xiàn)文件的導(dǎo)入導(dǎo)出
- EasyExcel實(shí)現(xiàn)導(dǎo)入+各種數(shù)據(jù)校驗(yàn)功能
- Java使用EasyExcel實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出
- Java使用easyExcel批量導(dǎo)入數(shù)據(jù)詳解
相關(guān)文章
Mybatis-flex整合達(dá)夢(mèng)數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例
本文討論了國(guó)產(chǎn)達(dá)夢(mèng)數(shù)據(jù)庫(kù)與Mybatis-flex框架的整合過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10SpringBoot集成WebServlet出現(xiàn)自定義servlet請(qǐng)求失敗的問(wèn)題解決方案
SpringBoot中以Bean方式注冊(cè)Servlet時(shí)遇到的問(wèn)題,通過(guò)了解DispatcherServlet的原理,發(fā)現(xiàn)默認(rèn)路徑?jīng)_突是主要原因,本文介紹SpringBoot集成WebServlet出現(xiàn)自定義servlet請(qǐng)求失敗的問(wèn)題解決方案,感興趣的朋友一起看看吧2025-03-03java數(shù)據(jù)隨機(jī)分頁(yè)實(shí)現(xiàn)方案
本文主要介紹了java數(shù)據(jù)隨機(jī)分頁(yè)實(shí)現(xiàn)方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06