導出導入Excel文件(詳解-基于EasyExcel)

前言:

? ? ? ? 近期由于工作的需要,根據需求需要導出導入Excel模板。于是自學了一下下,在此記錄并分享!!

EasyExcel:

? ? ? ? 首先我要在這里非常感謝阿里的大佬們!封裝這么好用的Excel相關的API,真的是拯救了許多猿猿們!!

? ? ? ? EasyExcel官網:關于Easyexcel | Easy Excel 官網

導出Excel(write):

? ? ? ? 接到項目之后,我負責的其中一個小需求是需要導出Excel,網上查了大量資料,發現EasyExcel包中已經包含了大量的對Excel的操作,當然對于一些特殊的需求可能需要自己寫一個對Excel操作的方法~

@ExcelProperty注解:

? ? ? ? 我將這個注解作為首要講解對象,足以看出其重要性。

? ? ? ? 示例代碼:

    @ExcelProperty(value = "序號",order = 1,converter = IdConverter.class)private Long id = 1L;@ExcelProperty(value = "出生日期", format = "yyyy-MM-dd",headStyle = CustomHeadStyleStrategy.class)private Date birthDate;

只要在對應字段上加上該注解以后,意味著該字段將作為表頭出現在Excel中,其中有一些參數如下:

1.?value

  • 類型String[]
  • 作用:指定 Excel 表頭的名稱。可以傳入一個字符串數組,當存在多級表頭時,數組中的元素按順序對應各級表頭。

2.?index

  • 類型int
  • 作用:指定該屬性對應 Excel 表格中的列索引,索引從 0 開始。當 Excel 列順序固定時,可以使用此參數進行精確映射。

3.?converter

  • 類型Class<? extends Converter<?>>
  • 作用:指定自定義的轉換器,用于將 Java 對象屬性與 Excel 單元格數據進行轉換。當默認的轉換器無法滿足需求時,可以自定義轉換器并通過此參數指定。

4.?format

  • 類型String
  • 作用:用于指定日期、數字等類型數據的格式化模式。當讀取或寫入 Excel 時,會按照指定的格式進行轉換。

5.?order

  • 類型int
  • 作用:指定該屬性在生成 Excel 表格時的列順序,數值越小越靠前。

6.?headStyle

  • 類型Class<? extends HeadStyleStrategy>
  • 作用:指定表頭樣式的策略類,用于自定義表頭的樣式,如字體、顏色、背景色等。

7.?contentStyle

  • 類型Class<? extends ContentStyleStrategy>
  • 作用:指定內容樣式的策略類,用于自定義表格內容的樣式,如字體、顏色、對齊方式等。

當然隨著EasyExcel引入的版本不一樣,有些參數可能被淘汰或者是換成了新的~

著重需要說明兩個參數:

1.converter參數,這個參數需要實現Converter接口

public class IdConverter implements Converter<Integer> {
//todo
}

這個接口需要重寫三個方法:

Class<?> supportJavaTypeKey();
  • 作用:指明此轉換器所支持的 Java 類型。返回值是一個?Class?對象,代表支持轉換的 Java 類型。

CellDataTypeEnum supportExcelTypeKey();
  • 作用:指定該轉換器支持的 Excel 單元格數據類型。CellDataTypeEnum?是一個枚舉類型,包含了各種 Excel 單元格數據類型,像字符串、數字、日期等。

T convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception;
  • 作用:把 Excel 單元格數據轉換為 Java 對象屬性。參數如下:
    • cellData:表示從 Excel 讀取到的單元格數據。
    • contentProperty:包含單元格的一些屬性信息。
    • globalConfiguration:全局配置信息。

綜上示例如下:

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;public class StringConverter implements Converter<String> {@Overridepublic Class<?> supportJavaTypeKey() {return String.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return cellData.getStringValue();}@Overridepublic WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return new WriteCellData<>(value);}
}

當然也可以根據自身的需求進行補充,例如:希望在數字后面+單位,在人名后面+稱呼,希望id是一個自增的等等行為~~

Excel中的id列自增:

? ? ? ? 這里我舉例id列希望是自增的:

實體類代碼:

    @ExcelProperty(value = "序號",order = 1,converter = IdConverter.class)private Long id = 1L;

converter代碼:?

public class IdConverter implements Converter<Integer> {private int currentId = 1;@Overridepublic Class<?> supportJavaTypeKey() {return Integer.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.NUMBER;}@Overridepublic WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) {return new WriteCellData<>(String.valueOf(currentId++));}
}

效果如下:

????????

復雜表頭:

? ? ? ? 如果想要一個多級表頭,使用上述的注解一樣可以做到:

只不過value的值要變成層級關系:

    @ExcelProperty(value = {"項目交付信息","牽頭部門名稱"},order = 14)private String leadingDepartment;@ExcelProperty(value = {"項目交付信息","交付部門名稱"},order = 15)private String deliveryDepartment;@ExcelProperty(value = {"項目交付信息","項目PO"},order = 16)private String projectPo;@ExcelProperty(value = {"項目交付信息","項目經理"},order = 17)private String projectManager;

@DateTimeFormat注解:

? ? ? ? 該注解也是一個確定時間格式的注解,由于版本的迭代,上述的@ExcelProperty的format

屬性已經被廢除,建議使用該注解進行時間格式的限制。

????????@DateTimeFormat?注解是 Spring 框架提供的一個用于日期和時間格式化的注解,它主要用于將字符串類型的日期時間數據綁定到 Java 對象的日期時間類型字段上,或者將 Java 對象中的日期時間類型字段按照指定格式輸出為字符串。

pattern

  • 類型String
  • 作用:指定日期時間的格式化模式。模式遵循 Java 的?SimpleDateFormat?或?DateTimeFormatter?的規則。例如,"yyyy-MM-dd"?表示年 - 月 - 日的格式,"yyyy-MM-dd HH:mm:ss"?表示年 - 月 - 日 時:分: 秒的格式。

iso

  • 類型ISO?枚舉類型
  • 作用:使用預定義的 ISO 日期時間格式。ISO?枚舉包含了幾個常用的 ISO 日期時間格式,如?ISO.DATE?表示?yyyy-MM-dd?格式,ISO.TIME?表示?HH:mm:ss.SSSXXX?格式,ISO.DATE_TIME?表示?yyyy-MM-dd'T'HH:mm:ss.SSSXXX?格式。

示例如下:

 @DateTimeFormat(pattern = "yyyy-MM-dd")private Date birthDate;

@ContentRowHeight,@HeadRowHeight,@ColumnWidth

? ? ? ? 設置行高與列寬,上述的三個注解可以實現設置操作,注意,上述注解@ColumnWidth可以使用在類上面,也可以單獨注解在屬性上面。

? ? ? ? 示例如下:

@ContentRowHeight(20)//內容行高
@HeadRowHeight(20)//表頭行高
@ColumnWidth(25)//列寬
public class DeriveExcelDTO {@ColumnWidth(40)@ExcelProperty(value = "項目名稱",order = 2)private String projectName;
}

這里就不展示效果圖了,大家有興趣可以自己進行嘗試!!!

示例完整導出代碼:

// 實體類,用于映射Excel列
public class DemoData {@ExcelProperty("字符串標題")private String string;@ExcelProperty("日期標題")private Date date;@ExcelProperty("數字標題")private Double doubleData;// 構造函數、getter和setterpublic DemoData() {}public DemoData(String string, Date date, Double doubleData) {this.string = string;this.date = date;this.doubleData = doubleData;}// getters and setterspublic String getString() { return string; }public void setString(String string) { this.string = string; }public Date getDate() { return date; }public void setDate(Date date) { this.date = date; }public Double getDoubleData() { return doubleData; }public void setDoubleData(Double doubleData) { this.doubleData = doubleData; }
}// 控制器示例(Spring MVC)
@RestController
public class ExcelExportController {@GetMapping("/export")public void export(HttpServletResponse response) throws IOException {// 準備數據List<DemoData> data = new ArrayList<>();for (int i = 0; i < 10; i++) {DemoData demoData = new DemoData();demoData.setString("字符串" + i);demoData.setDate(new Date());demoData.setDoubleData(0.56 + i);data.add(demoData);}// 設置響應頭response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("測試", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");// 導出ExcelEasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(data);}
}

導入Excel(read):

? ? ? ? 導出Excel其實和導入是差不多的,但是在使用EasyExcel時,需要注意表頭的書寫是否和讀取時一致(例如讀取時讀二級表頭,Excel中對應的數據的表頭必須也是二級的)!后面會詳細介紹到。

設置監聽器:

? ? ? ? 讀取Excel表格時,必須設置一個監聽器,但是需要注意的是該監聽器不能被Spring管理,每次使用時必須手動new。

@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {/*** 每隔5條存儲數據庫,實際使用中可以100條,然后清理list ,方便內存回收*/private static final int BATCH_COUNT = 100;/*** 緩存的數據*/private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 假設這個是一個DAO,當然有業務邏輯這個也可以是一個service。當然如果不用存儲這個對象沒用。*/private DemoDAO demoDAO;public DemoDataListener() {// 這里是demo,所以隨便new一個。實際使用如果到了spring,請使用下面的有參構造函數demoDAO = new DemoDAO();}/*** 如果使用了spring,請使用這個構造方法。每次創建Listener的時候需要把spring管理的類傳進來** @param demoDAO*/public DemoDataListener(DemoDAO demoDAO) {this.demoDAO = demoDAO;}/*** 這個每一條數據解析都會來調用** @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublic void invoke(DemoData data, AnalysisContext context) {log.info("解析到一條數據:{}", JSON.toJSONString(data));cachedDataList.add(data);// 達到BATCH_COUNT了,需要去存儲一次數據庫,防止數據幾萬條數據在內存,容易OOMif (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存儲完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}/*** 所有數據解析完成了 都會來調用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 這里也要保存數據,確保最后遺留的數據也存儲到數據庫saveData();log.info("所有數據解析完成!");}/*** 加上存儲數據庫*/private void saveData() {log.info("{}條數據,開始存儲數據庫!", cachedDataList.size());demoDAO.save(cachedDataList);log.info("存儲數據庫成功!");}
}

當然阿里為了更加方便猿猿們,也就行了二次封裝,封裝后的ReadListener可以交給Spring進行管理,也是非常方便了~

? ? ? ? 沒錯就是這個AnalysisEventListener類,里面繼承了ReadListener,也是更加簡便清晰了~

可以重寫一下的方法:

每個方法的作用以及參數如下:

????????

onException(Exception exception, AnalysisContext context)

  • 作用:讀取過程中發生異常時觸發
  • 參數
    • exception:異常對象
    • context:讀取上下文

doAfterAllAnalysed(AnalysisContext context)

  • 作用:整個 Excel 文件讀取完成后觸發
  • 參數:讀取上下文

invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context)

  • 作用:解析表頭時觸發(默認表頭占 1 行)
  • 參數
    • headMap:表頭數據(key 為列索引,value 為單元格數據)
    • context:讀取上下文

hasNext(AnalysisContext context)

  • 作用:控制是否繼續讀取下一行(返回 false 時終止讀取)
  • 參數:讀取上下文

?完整示例如下:

public class DemoDataListener extends AnalysisEventListener<DemoData> {private List<DemoData> dataList = new ArrayList<>();@Overridepublic void invoke(DemoData data, AnalysisContext context) {// 每行數據解析后調用dataList.add(data);System.out.println("解析第" + context.readRowHolder().getRowIndex() + "行:" + data.getName());}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 所有數據解析完成后調用System.out.println("共解析" + dataList.size() + "行數據");}@Overridepublic void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {// 表頭解析后調用System.out.println("解析表頭:" + headMap.get(0).getStringValue());}@Overridepublic void onException(Exception exception, AnalysisContext context) {// 異常處理System.err.println("解析失敗,行號:" + context.readRowHolder().getRowIndex());exception.printStackTrace();}public List<DemoData> getDataList() {return dataList;}
}

?完整代碼:

????????

public String importUser(@RequestParam("file") MultipartFile file) {try {EasyExcel.read(file.getInputStream(), User.class, new UserExcelListener(userService)).sheet().doRead();return "導入并更新成功";} catch (Exception e) {return "導入并更新失敗:" + e.getMessage();}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80176.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80176.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80176.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python版本管理工具-pyenv輕松切換多個Python版本

在使用python環境開發時&#xff0c;相信肯定被使用版本所煩惱&#xff0c;在用第三方庫時依賴兼容的python版本不一樣&#xff0c;有沒有一個能同時安裝多個python并能自由切換的工具呢&#xff0c;那就是pyenv&#xff0c;讓你可以輕松切換多個Python 版本。 pyenv是什么 p…

Elasticsearch 索引副本數

作者&#xff1a;來自 Elastic Kofi Bartlett 解釋如何配置 number_of_replicas、它的影響以及最佳實踐。 更多閱讀&#xff1a;Elasticsearch 中的一些重要概念: cluster, node, index, document, shards 及 replica 想獲得 Elastic 認證&#xff1f;查看下一期 Elasticsearc…

AXI4總線協議 ------ AXI_LITE協議

一、AXI 相關知識介紹 https://download.csdn.net/download/mvpkuku/90841873 AXI_LITE 選出部分重點&#xff0c;詳細文檔見上面鏈接。 1.AXI4 協議類型 2.握手機制 二、AXI_LITE 協議的實現 1. AXI_LITE 通道及各通道端口功能介紹 2.實現思路及框架 2.1 總體框架 2.2 …

idea運行

各種小kips Linuxidea上傳 Linux 部署流程 1、先在idea打好jar包&#xff0c;clean之后install 2、在Linux目錄下&#xff0c;找到對應項目目錄&#xff0c;把原來的jar包放在bak文件夾里面 3、殺死上一次jar包的pid ps -ef|grep cliaidata.jar kill pid 4、再進行上傳新的jar…

FPGA: XILINX Kintex 7系列器件的架構

本文將詳細介紹Kintex-7系列FPGA器件的架構。以下內容將涵蓋Kintex-7的核心架構特性、主要組成部分以及關鍵技術&#xff0c;盡量全面且結構化&#xff0c;同時用簡潔的語言確保清晰易懂。 Kintex-7系列FPGA架構概述 Kintex-7是Xilinx 7系列FPGA中的中高端產品線&#xff0c;基…

【LLM】大模型落地應用的技術 ——— 推理訓練 MOE,AI搜索 RAG,AI Agent MCP

【LLM】大模型落地應用的技術 ——— 推理訓練MOE&#xff0c;AI搜索RAG&#xff0c;AI Agent MCP 文章目錄 1、推理訓練 MOE2、AI搜索 RAG3、AI Agent MCP 1、推理訓練 MOE MoE 是模型架構革新&#xff0c;解決了算力瓶頸。原理是多個專家模型聯合計算。 推理訓練MoE&#xff…

10 web 自動化之 yaml 數據/日志/截圖

文章目錄 一、yaml 數據獲取二、日志獲取三、截圖 一、yaml 數據獲取 需要安裝 PyYAML 庫 import yaml import os from TestPOM.common import dir_config as Dir import jsonpathclass Data:def __init__(self,keyNone,file_name"test_datas.yaml"):file_path os…

中exec()函數因$imagePath參數導致的命令注入漏洞

exec(zbarimg -q . $imagePath, $barcodeList, $returnVar); 針對PHP中exec()函數因$imagePath參數導致的命令注入漏洞&#xff0c;以下是安全解決方案和最佳實踐&#xff1a; 一、漏洞原理分析 直接拼接用戶輸入$imagePath到系統命令中&#xff0c;攻擊者可通過注入特殊字…

this.$set的用法-響應式數據更新

目錄 一、核心作用 三、使用場景與示例 1. 給對象添加新屬性 四、與 Vue.set 的關系 五、底層原理 六、Vue 3 的替代方案 七、最佳實踐 八、常見問題 Q&#xff1a;為什么修改嵌套對象屬性不需要 $set&#xff1f; Q&#xff1a;$set 和 $forceUpdate 的區別&#xf…

【生成式AI文本生成實戰】DeepSeek系列應用深度解析

目錄 &#x1f31f; 前言&#x1f3d7;? 技術背景與價值&#x1fa79; 當前技術痛點&#x1f6e0;? 解決方案概述&#x1f465; 目標讀者說明 &#x1f9e0; 一、技術原理剖析&#x1f4ca; 核心概念圖解&#x1f4a1; 核心作用講解&#x1f527; 關鍵技術模塊說明?? 技術選…

c/c++的opencv的圖像預處理講解

OpenCV 圖像預處理核心技術詳解 (C/C) 圖像預處理是計算機視覺任務中至關重要的一步。原始圖像往往受到噪聲、光照不均、尺寸不一等多種因素的影響&#xff0c;直接用于后續分析&#xff08;如特征提取、目標檢測、機器學習模型訓練等&#xff09;可能會導致性能下降或結果不準…

使用 Docker 部署 React + Nginx 應用教程

目錄 1. 創建react項目結構2. 創建 .dockerignore3. 創建 Dockerfile4. 創建 nginx.conf5. 構建和運行6. 常用命令 1. 創建react項目結構 2. 創建 .dockerignore # 依賴目錄 node_modules npm-debug.log# 構建輸出 dist build# 開發環境文件 .git .gitignore .env .env.local …

Java 流(Stream)API

一、理論說明 1. 流的定義 Java 流&#xff08;Stream&#xff09;是 Java 8 引入的新特性&#xff0c;用于對集合&#xff08;如 List、Set&#xff09;或數組進行高效的聚合操作&#xff08;如過濾、映射、排序&#xff09;和并行處理。流不存儲數據&#xff0c;而是按需計…

網絡協議分析 實驗七 FTP、HTTP、DHCP

文章目錄 實驗7.1 FTP協議練習二 使用瀏覽器登入FTP練習三 在窗口模式下&#xff0c;上傳/下傳數據文件實驗7.2 HTTP(Hyper Text Transfer Protocol)練習二 頁面提交練習三 訪問比較復雜的主頁實驗7.3 DHCP(Dynamic Host Configuration Protocol) 實驗7.1 FTP協議 dir LIST&…

go語言學習進階

目錄 第一章 go語言中包的使用 一.main包 二.package 三.import 四.goPath環境變量 五.init包初始化 六.管理外部包 第二章 time包 第三章 File文件操作 一.FileInfo接口 二.權限 三.打開模式 四.File操作 五.讀文件 參考1&#xff1a;Golang 中的 bufio 包詳解…

Hue面試內容整理-后端框架

Cloudera 的 Hue 項目在后端采用了成熟的 Python Web 框架 Django,結合其他組件構建了一個可擴展、模塊化的系統,便于與 Hadoop 生態系統中的各個組件集成。以下是 Hue 后端架構的詳細介紹: 后端架構概覽 1. Django Web 框架 Hue 的核心是基于 Django 構建的 Web 應用,負責…

Web-CSS入門

WEB前端&#xff0c;三部分&#xff1a;HTML部分、CSS部分、Javascript部分。 1.HTML部分&#xff1a;主要負責網頁的結構層 2.CSS部分&#xff1a;主要負責網頁的樣式層 3.JS部分&#xff1a;主要負責網頁的行為層 **基本概念** 層疊樣式表&#xff0c;Cascading Style Sh…

2025年PMP 學習十六 第11章 項目風險管理 (總章)

2025年PMP 學習十六 第11章 項目風險管理 &#xff08;總章&#xff09; 第11章 項目風險管理 序號過程過程組1規劃風險管理規劃2識別風險規劃3實施定性風險分析規劃4實施定量風險分析規劃5規劃風險應對執行6實施風險應對執行7監控風險監控 目標: 提高項目中積極事件的概率和…

基于SpringBoot的小區停車位管理系統

作者&#xff1a;計算機學姐 開發技術&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源碼”。 專欄推薦&#xff1a;前后端分離項目源碼、SpringBoot項目源碼、Vue項目源碼、SSM項目源碼、微信小程序源碼 精品專欄&#xff1a;…

HTML常用標簽用法全解析:構建語義化網頁的核心指南

HTML作為網頁開發的基石&#xff0c;其標簽的合理使用直接影響頁面的可讀性、SEO效果及維護性。本文系統梳理HTML核心標簽的用法&#xff0c;結合語義化設計原則與實戰示例&#xff0c;助你構建規范、高效的網頁結構。 一、基礎結構與排版標簽 1.1 文檔結構 <!DOCTYPE htm…