教您如何3分鐘快速搞定EasyExcel導(dǎo)入與導(dǎo)出功能
前言
該文章主要是介紹如何快速實(shí)現(xiàn)導(dǎo)入與導(dǎo)出功能
一、EasyExcel是什么?
引用官方的說明:EasyExcel是一個(gè)基于Java的、快速、簡潔、解決大文件內(nèi)存溢出的Excel處理工具。
他能讓你在不用考慮性能、內(nèi)存的等因素的情況下,快速完成Excel的讀、寫等功能。
二、使用步驟
1.引入庫
pom.xml引入jar依賴包:
<!-- EasyExcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency>
2.導(dǎo)入
2.1創(chuàng)建對(duì)應(yīng)excel表格的實(shí)體類
@ExcelProperty該注解的value是對(duì)應(yīng)excle表格的列名稱,index對(duì)應(yīng)的是excel列的下標(biāo)
@Data public class ImportModel { /** * 樹根 */ @ExcelProperty(value = "名稱", index = 0) private String ; /** * 樹根標(biāo)題 */ @ExcelProperty(value = "編碼", index = 1) private String code; }
2.2后端接收請(qǐng)求入口
/** * 導(dǎo)入 */ @ApiOperation("導(dǎo)入") @PostMapping("/importTree") public R importTree(@RequestParam("file") MultipartFile file) { /** 根據(jù)自己的業(yè)務(wù)自行選擇在哪處理 */ /** 直接在controllerr處理 */ // EasyExcel.read(file.getInputStream(), BigTreeImportCommand.class, new ExcelListener(urbanFacilityManageService)).sheet().doRead(); /** 在service實(shí)現(xiàn)類處理 */ Boolean flag = treeService.importTree(file, tenantId); return R.ok("導(dǎo)入成功"); }
2.3業(yè)務(wù)處理
@Override public Boolean importTree(MultipartFile file) { try { /** 處理數(shù)據(jù)的監(jiān)聽器,有參構(gòu)造,根據(jù)自己的業(yè)務(wù)決定 */ TreeExcelListener excelListener = new TreeExcelListener(importService,tenantId); // 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheet 文件流會(huì)自動(dòng)關(guān)閉 //EasyExcel.read(文件流,對(duì)應(yīng)的Model實(shí)體類,監(jiān)聽器).sheet(那張sheet表,可以使用下標(biāo)或者使用sheet名字).head(表頭對(duì)應(yīng)的實(shí)體類).headRowNumber(表頭占幾行).registerReadListener(處理數(shù)據(jù)的監(jiān)聽器類).doRead() EasyExcel.read(file.getInputStream(), ImportModel.class, excelListener).sheet(0).head(ImportModel.class).headRowNumber(1).doRead(); return true; } catch (Exception e) { throw new RuntimeException(e); } }
2.4監(jiān)聽器處理數(shù)據(jù)
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.ieds.back.interfaces.sys.web.command.BigTreeImportModel; /** * @Author: ChenFB * @CreateTime: 2023-04-23 17:18 * @Description: 導(dǎo)入監(jiān)聽器 */ public class ImportListener extends AnalysisEventListener<BigTreeImportModel> { private ImportService importService; private String tenantId; /** 有參構(gòu)造,建議將serverjie接口以參數(shù)的方式參進(jìn)來,方便數(shù)據(jù)入庫處理,這個(gè)參數(shù)自行界定 */ public ImportListener(ImportService importService, String tenantId) { this.importService = importService; this.tenantId = tenantId; } /** 讀取每一行數(shù)據(jù)都會(huì)進(jìn)入該方法,數(shù)據(jù)處理與校驗(yàn)可以在該方法進(jìn)行處理 */ @Override public void invoke(BigTreeImportModel data, AnalysisContext context) { } /** 所有數(shù)據(jù)讀取完畢后,最終會(huì)執(zhí)行這個(gè)方法,所以建議數(shù)據(jù)處理完后,批量在該方法進(jìn)行入庫處理 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { } }
3.導(dǎo)出
3.1創(chuàng)建導(dǎo)出格式生成對(duì)應(yīng)的excel表格的實(shí)體類,這個(gè)可以看2.1
3.2后端接收請(qǐng)求入口
/** * 導(dǎo)出 */ @ApiOperation("導(dǎo)出") @GetMapping("/exportTree") public void exportTree(HttpServletResponse response, @RequestParam("tenantId") String tenantId) { treeService.exportTree(response,tenantId); }
3.3業(yè)務(wù)處理
@Override public void exportTree(HttpServletResponse response, String tenantId) { ExcelWriter writer = null; try { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //設(shè)置響應(yīng)內(nèi)容類型 response.setCharacterEncoding("utf-8");//編碼 // 設(shè)置文件名, ps:把字符串中所有的'+'替換成'%20',在URL中%20代表空格 String fileName = URLEncoder.encode("文件名,根據(jù)業(yè)務(wù)決定", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");//設(shè)置響應(yīng)頭 response.setHeader("fileName", fileName + ".xlsx");//設(shè)置響應(yīng)頭 /** 導(dǎo)出的數(shù)據(jù)集合 */ List<ExportModel> modelList = new ArrayList<>(); /** registerWriteHandler(合并行數(shù),那些列需要合并) */ writer = EasyExcel.write(response.getOutputStream(), BigTreeImportModel.class).registerWriteHandler(new MergeStrategy(modelList.size(), 0, 1, 2, 7, 8, 10, 11)).build();//獲取寫出流 WriteSheet sheet = EasyExcel.writerSheet("sheet名稱,自行決定").build();//創(chuàng)建表格,設(shè)置表格頁名稱 writer.write(modelList, sheet);//讀出 } catch (Exception e) { throw new RuntimeException(e); } finally { if (null != writer) { writer.finish();//關(guān)閉流 } } }
4.合并工具類
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.merge.AbstractMergeStrategy; import org.apache.commons.collections.map.HashedMap; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import java.util.*; /** * @Author: ChenFB * @CreateTime: 2023-04-20 10:56 * @Description: Excel單元格合并工具類 */ public class MergeStrategy extends AbstractMergeStrategy { // 合并的列編號(hào),從0開始,指定的index或自己按字段順序數(shù) private Set<Integer> mergeCellIndex = new HashSet<>(); // 數(shù)據(jù)集大小,用于區(qū)別結(jié)束行位置 private Integer maxRow = 0; // 禁止無參聲明 private MergeStrategy() { } public MergeStrategy(Integer maxRow, int... mergeCellIndex) { Arrays.stream(mergeCellIndex).forEach(item -> { this.mergeCellIndex.add(item); }); this.maxRow = maxRow; } // 記錄上一次合并的信息 private Map<Integer, MergeRange> lastRow = new HashedMap(); // 每行每列都會(huì)進(jìn)入,絕對(duì)不要在這寫循環(huán) @Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { int currentCellIndex = cell.getColumnIndex(); // 判斷該行是否需要合并 if (mergeCellIndex.contains(currentCellIndex)) { String currentCellValue = cell.getStringCellValue(); int currentRowIndex = cell.getRowIndex(); if (!lastRow.containsKey(currentCellIndex)) { // 記錄首行起始位置 lastRow.put(currentCellIndex, new MergeRange(currentCellValue, currentRowIndex, currentRowIndex, currentCellIndex, currentCellIndex)); return; } //有上行這列的值了,拿來對(duì)比. MergeRange mergeRange = lastRow.get(currentCellIndex); if (!(mergeRange.lastValue != null && mergeRange.lastValue.equals(currentCellValue))) { // 結(jié)束的位置觸發(fā)下合并. // 同行同列不能合并,會(huì)拋異常 if (mergeRange.startRow != mergeRange.endRow || mergeRange.startCell != mergeRange.endCell) { sheet.addMergedRegionUnsafe(new CellRangeAddress(mergeRange.startRow, mergeRange.endRow, mergeRange.startCell, mergeRange.endCell)); } // 更新當(dāng)前列起始位置 lastRow.put(currentCellIndex, new MergeRange(currentCellValue, currentRowIndex, currentRowIndex, currentCellIndex, currentCellIndex)); } // 合并行 + 1 mergeRange.endRow += 1; // 結(jié)束的位置觸發(fā)下最后一次沒完成的合并 if (relativeRowIndex.equals(maxRow - 1)) { MergeRange lastMergeRange = lastRow.get(currentCellIndex); // 同行同列不能合并,會(huì)拋異常 if (lastMergeRange.startRow != lastMergeRange.endRow || lastMergeRange.startCell != lastMergeRange.endCell) { sheet.addMergedRegionUnsafe(new CellRangeAddress(lastMergeRange.startRow-1, lastMergeRange.endRow, lastMergeRange.startCell, lastMergeRange.endCell)); } } } } } class MergeRange { public int startRow; public int endRow; public int startCell; public int endCell; public String lastValue; public MergeRange(String lastValue, int startRow, int endRow, int startCell, int endCell) { this.startRow = startRow; this.endRow = endRow; this.startCell = startCell; this.endCell = endCell; this.lastValue = lastValue; } }
附:EasyExcel結(jié)合Mybatis plus的分頁功能進(jìn)行分頁導(dǎo)出
工具類
import cn.hutool.core.collection.CollUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.Builder; import lombok.Data; import org.springframework.http.HttpHeaders; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; public class EasyExcelUtil { @Data @Builder public static class ExcelParam { /** * 查詢 Mapper */ private BaseMapper baseMapper; /** * Lambda查詢方式 */ private LambdaQueryWrapper lambdaQueryWrapper; /** * 頁碼,默認(rèn)從1開始 */ private Integer pageNo = 1; /** * 分頁條數(shù),,默認(rèn)每個(gè)sheet 1000 條數(shù)據(jù) */ private Integer pageSize = 1000; /** * 用于存放查詢到的結(jié)果,讓Excel生成 */ private Class<?> respClazz; /** * 生成的Excel 名稱,不加后綴 */ private String fileName; /** * Excel sheet名稱 */ private String sheetName; } public static void exportExcel(ExcelParam excelParam, HttpServletResponse response) { response.setContentType("application/vnd.ms-excel;charset=utf-8"); response.setCharacterEncoding("utf-8"); response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + excelParam.getFileName() + ".xlsx"); try ( ServletOutputStream outputStream = response.getOutputStream(); ExcelWriter excelWriter = EasyExcel.write(outputStream, excelParam.getRespClazz()).build(); ) { Page page = new Page(excelParam.getPageNo(), excelParam.getPageSize()); page = (Page) excelParam.getBaseMapper().selectPage(page, excelParam.getLambdaQueryWrapper()); /** 構(gòu)建 */ WriteSheet writeSheet1 = EasyExcel.writerSheet(1, excelParam.getSheetName() + "第" + excelParam.getPageNo() + "頁").build(); /** 獲取總數(shù) */ Long totalPage = page.getPages(); List records = page.getRecords(); /** 寫入內(nèi)容 */ excelWriter.write(records, writeSheet1); writeSheet1 = null; // GC // 若為空表 if (CollUtil.isEmpty(page.getRecords())) { /** 生成完畢 */ excelWriter.finish(); /** 立即刷回 */ outputStream.flush(); return; } for (int i = excelParam.pageNo + 1, index = 2; i <= totalPage; i++, index++) { /** 清空*/ records.clear(); WriteSheet writeSheet = EasyExcel.writerSheet(index, excelParam.getSheetName() + "第" + i + "頁").build(); page.setCurrent(i); /** 新的查詢 */ page = (Page) excelParam.getBaseMapper().selectPage(page, excelParam.getLambdaQueryWrapper()); records = page.getRecords(); /** 輸入內(nèi)容內(nèi)容 */ excelWriter.write(records, writeSheet); } /** 生成完畢 */ excelWriter.finish(); /** 立即刷回 */ outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } } }
使用
EasyExcelUtil.ExcelParam p = EasyExcelUtil.ExcelParam.builder() .baseMapper(workRollPlanService.getBaseMapper()) // 傳Service類的BaseMapper進(jìn)去 .lambdaQueryWrapper(new LambdaQueryWrapper<WorkRollPlan>() // 構(gòu)建查詢條件 .eq(true, WorkRollPlan::getIsDeleted, 0) ) .pageNo(1) // 數(shù)據(jù)從第一行開始,如果表頭只有一行就是1,表頭有兩行的話就寫2 .respClazz(WorkRollPlan.class) // 這里寫實(shí)體類 .pageSize(1000) // Excel每頁數(shù)據(jù)大小 .fileName("test") // 文件名 .sheetName("測試sheet") // 頁名 .build(); EasyExcelUtil.exportExcel(p, response);
總結(jié)
到此這篇關(guān)于如何3分鐘快速搞定EasyExcel導(dǎo)入與導(dǎo)出功能的文章就介紹到這了,更多相關(guān)EasyExcel導(dǎo)入與導(dǎo)出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中EasyExcel實(shí)現(xiàn)Excel文件的導(dǎo)入導(dǎo)出
- 使用SpringBoot+EasyExcel+Vue實(shí)現(xiàn)excel表格的導(dǎo)入和導(dǎo)出詳解
- SpringBoot整合EasyExcel實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出
- Java使用EasyExcel實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出
- Java+EasyExcel實(shí)現(xiàn)文件的導(dǎo)入導(dǎo)出
- 基于EasyExcel實(shí)現(xiàn)百萬級(jí)數(shù)據(jù)導(dǎo)入導(dǎo)出詳解
- java使用EasyExcel導(dǎo)入導(dǎo)出excel
相關(guān)文章
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(49)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-08-08解決2022.3.1版本中?IDEA中?XML文件提示屎黃色背景的方法
這篇文章主要介紹了解決2022.3.1版本中?IDEA中?XML文件屎黃色背景?的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01springboot自帶線程池ThreadPoolTaskExecutor使用
本文主要介紹了springboot自帶線程池ThreadPoolTaskExecutor使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Java整合Jackson實(shí)現(xiàn)反序列化器流程
Jackson是一個(gè)開源的Java序列化和反序列化工具,可以將Java對(duì)象序列化為XML或JSON格式的字符串,以及將XML或JSON格式的字符串反序列化為Java對(duì)象。由于其使用簡單,速度較快,且不依靠除JDK外的其他庫,被眾多用戶所使用2023-01-01通過Java實(shí)現(xiàn)帶干擾線的驗(yàn)證碼
帶干擾線的驗(yàn)證碼是一種常見的安全驗(yàn)證方式,目的是通過圖像中的干擾線增加機(jī)器識(shí)別的難度,確保只有人類用戶能夠順利識(shí)別并輸入驗(yàn)證碼,本項(xiàng)目的目的是通過Java實(shí)現(xiàn)一個(gè)帶有干擾線的驗(yàn)證碼生成器,需要的朋友可以參考下2025-02-02Spring?Boot?如何通過ServletRequestHandledEvent事件實(shí)現(xiàn)接口請(qǐng)求的性能監(jiān)控
在Spring框架中,監(jiān)控接口請(qǐng)求的性能可以通過ServletRequestHandledEvent事件實(shí)現(xiàn),這篇文章給大家介紹Spring?Boot?如何通過ServletRequestHandledEvent事件實(shí)現(xiàn)接口請(qǐng)求的性能監(jiān)控,感興趣的朋友跟隨小編一起看看吧2024-08-08springBoot使用openfeign來遠(yuǎn)程調(diào)用的實(shí)現(xiàn)
這篇文章主要介紹了springBoot使用openfeign來遠(yuǎn)程調(diào)用的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03