教您如何3分鐘快速搞定EasyExcel導(dǎo)入與導(dǎo)出功能
前言
該文章主要是介紹如何快速實現(xiàn)導(dǎo)入與導(dǎo)出功能
一、EasyExcel是什么?
引用官方的說明:EasyExcel是一個基于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)建對應(yīng)excel表格的實體類
@ExcelProperty該注解的value是對應(yīng)excle表格的列名稱,index對應(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后端接收請求入口
/**
* 導(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實現(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);
// 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關(guān)閉
//EasyExcel.read(文件流,對應(yīng)的Model實體類,監(jiān)聽器).sheet(那張sheet表,可以使用下標(biāo)或者使用sheet名字).head(表頭對應(yīng)的實體類).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ù)的方式參進來,方便數(shù)據(jù)入庫處理,這個參數(shù)自行界定 */
public ImportListener(ImportService importService, String tenantId) {
this.importService = importService;
this.tenantId = tenantId;
}
/** 讀取每一行數(shù)據(jù)都會進入該方法,數(shù)據(jù)處理與校驗可以在該方法進行處理 */
@Override
public void invoke(BigTreeImportModel data, AnalysisContext context) {
}
/** 所有數(shù)據(jù)讀取完畢后,最終會執(zhí)行這個方法,所以建議數(shù)據(jù)處理完后,批量在該方法進行入庫處理 */
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
}
3.導(dǎo)出
3.1創(chuàng)建導(dǎo)出格式生成對應(yīng)的excel表格的實體類,這個可以看2.1
3.2后端接收請求入口
/**
* 導(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 {
// 合并的列編號,從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á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;
}
//有上行這列的值了,拿來對比.
MergeRange mergeRange = lastRow.get(currentCellIndex);
if (!(mergeRange.lastValue != null && mergeRange.lastValue.equals(currentCellValue))) {
// 結(jié)束的位置觸發(fā)下合并.
// 同行同列不能合并,會拋異常
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);
// 同行同列不能合并,會拋異常
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的分頁功能進行分頁導(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)每個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進去
.lambdaQueryWrapper(new LambdaQueryWrapper<WorkRollPlan>() // 構(gòu)建查詢條件
.eq(true, WorkRollPlan::getIsDeleted, 0)
)
.pageNo(1) // 數(shù)據(jù)從第一行開始,如果表頭只有一行就是1,表頭有兩行的話就寫2
.respClazz(WorkRollPlan.class) // 這里寫實體類
.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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中EasyExcel實現(xiàn)Excel文件的導(dǎo)入導(dǎo)出
- 使用SpringBoot+EasyExcel+Vue實現(xiàn)excel表格的導(dǎo)入和導(dǎo)出詳解
- SpringBoot整合EasyExcel實現(xiàn)文件導(dǎo)入導(dǎo)出
- Java使用EasyExcel實現(xiàn)Excel的導(dǎo)入導(dǎo)出
- Java+EasyExcel實現(xiàn)文件的導(dǎo)入導(dǎo)出
- 基于EasyExcel實現(xiàn)百萬級數(shù)據(jù)導(dǎo)入導(dǎo)出詳解
- java使用EasyExcel導(dǎo)入導(dǎo)出excel
相關(guān)文章
解決2022.3.1版本中?IDEA中?XML文件提示屎黃色背景的方法
這篇文章主要介紹了解決2022.3.1版本中?IDEA中?XML文件屎黃色背景?的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-01-01
springboot自帶線程池ThreadPoolTaskExecutor使用
本文主要介紹了springboot自帶線程池ThreadPoolTaskExecutor使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Spring?Boot?如何通過ServletRequestHandledEvent事件實現(xiàn)接口請求的性能監(jiān)控
在Spring框架中,監(jiān)控接口請求的性能可以通過ServletRequestHandledEvent事件實現(xiàn),這篇文章給大家介紹Spring?Boot?如何通過ServletRequestHandledEvent事件實現(xiàn)接口請求的性能監(jiān)控,感興趣的朋友跟隨小編一起看看吧2024-08-08
springBoot使用openfeign來遠程調(diào)用的實現(xiàn)
這篇文章主要介紹了springBoot使用openfeign來遠程調(diào)用的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

