教您如何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)建對應(yīng)excel表格的實(shí)體類
@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實(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(文件流,對應(yīng)的Model實(shí)體類,監(jiān)聽器).sheet(那張sheet表,可以使用下標(biāo)或者使用sheet名字).head(表頭對應(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)出格式生成對應(yīng)的excel表格的實(shí)體類,這個(gè)可以看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ì)進(jìn)入,絕對不要在這寫循環(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ā)下合并.
// 同行同列不能合并,會(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)容請搜索腳本之家以前的文章或繼續(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)百萬級數(shù)據(jù)導(dǎo)入導(dǎo)出詳解
- java使用EasyExcel導(dǎo)入導(dǎo)出excel
相關(guān)文章
Java設(shè)計(jì)模式之單例模式實(shí)例詳解【懶漢式與餓漢式】
這篇文章主要介紹了Java設(shè)計(jì)模式之單例模式,簡單說明了單例模式的原理并結(jié)合具體實(shí)例形式分析了單例模式中懶漢式與餓漢式的具體實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下2017-09-09
SpringBoot集成WebSocket實(shí)現(xiàn)雙屏實(shí)時(shí)消息互推功能
在項(xiàng)目開發(fā)中,實(shí)時(shí)消息推送是高頻需求,比如雙屏聯(lián)動(dòng)、大屏監(jiān)控、在線聊天、訂單狀態(tài)推送等場景,本文以SpringBoot 2.7.x(最穩(wěn)定版本,零基礎(chǔ)友好)為基礎(chǔ),手把手教大家從 0 到 1 集成 WebSocket,實(shí)現(xiàn)左屏 / 右屏雙端實(shí)時(shí)消息互推功能,需要的朋友可以參考下2026-02-02
Java實(shí)現(xiàn)發(fā)送手機(jī)短信語音驗(yàn)證功能代碼實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)發(fā)送手機(jī)短信語音驗(yàn)證功能代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
SpringBoot中MyBatis使用自定義TypeHandler的實(shí)現(xiàn)
本文主要介紹了SpringBoot中MyBatis使用自定義TypeHandler,當(dāng)默認(rèn)的類型映射不能滿足需求時(shí),自定義?TypeHandler?就非常有用,具有一定的參考價(jià)值,感興趣的可以了解一下2024-08-08
SpringBoot如何切換成其它的嵌入式Servlet容器(Jetty和Undertow)
這篇文章主要介紹了SpringBoot如何切換成其它的嵌入式Servlet容器(Jetty和Undertow),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
在SpringBoot中如何使用HttpClient實(shí)現(xiàn)HTTP請求
本文介紹了如何使用Apache?HttpClient來訪問HTTP協(xié)議的資源,并提供了詳細(xì)的使用示例,包括GET和POST請求的無參和有參調(diào)用2025-02-02

