<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Excel 匯入與匯出是專案中經常用到的功能,在 Java 中常用 poi 實現 Excel 的匯入與匯出。由於 poi 佔用記憶體較大,在高並行下很容易發生 OOM 或者頻繁 fullgc,阿里基於 poi 開源了 EasyExcel 專案。
除了節約記憶體,EasyExcel 還簡化了 API,通過註解對映 Excel 單元格與物件欄位之間的關係,簡單的幾行程式碼就能搞定複雜的匯入匯出功能了。
看似一切美好,不過經常做 Excel 匯入與匯出就會發現,EasyExcel 還是沒那麼完美的。
首先,匯入與匯出 Excel 本質是上將 Excel 檔案內容與 Java 物件之間做一個對映,EasyExcel 做的只是在這兩者之間轉換。如果專案中的 Excel 匯入與匯出功能比較多,會產生大量的樣板式程式碼,使用體驗類似於 JDBC。
另外,匯入往往還伴隨著校驗,這是 EasyExcel 沒有支援的功能。如果需要校驗,要麼寫程式碼手動判斷,要麼呼叫 Java Validation 規範 定義的 API 判斷,這又會產生大量樣板式程式碼。
而且,當前 spring boot 已經成了必備的 Java 開發框架,easyexcel 也沒有進行整合。
匯入與匯出通常發生在 Web 環境,對於 Spring MVC 來說,可以將請求資訊轉換為任意型別的 contoller 方法引數,將 controller 方法返回值轉換為使用者端支援的內容。
如果能夠使用自定義的 controller 方法引數接收 Excel 檔案內容,將 controller 方法返回值轉換為 Excel 檔案響應,可以直接消除 Excel 匯入與匯出時的樣板式程式碼。
另外在將請求內容轉換為 controller 方法引數時還可以加入自定義的校驗邏輯。
由於 Excel 匯入與匯出樣板式程式碼、校驗問題與具體的業務邏輯無關,可以單獨抽象出來,我這裡在 EasyExcel 的基礎上封裝了一個 easyexcel-spring-boot-starter 的專案,大大降低了 EasyExcel 上手的門檻,對使用者來說只需要使用 EasyExcel 定義的註解提供對映關係就可以了,適用於簡單場景的匯入匯出。
專案程式碼已上傳 github easyexcel-spring-boot-starter 倉庫,點選連結即可查閱。下面就來看看怎樣使用吧。
首先需要引入依賴,座標如下。
<dependency> <groupId>com.zzuhkp</groupId> <artifactId>easyexcel-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
不過很不幸的是目前還沒傳至中央倉庫,需要的小夥伴可自行上傳到私有倉庫或直接把程式碼嵌入自己的專案。
首先看下要匯入的 Excel 內容吧。
為了接收 Excel 檔案內容,我們需要定義一個對應的 Model 類。
@Data public class DemoData { @ExcelProperty(index = 0) private Integer integer; @ExcelProperty(index = 1) private String string; @ExcelProperty(index = 2) private Date date; }
然後使用 List<T>
引數接收即可。
@PostMapping("/list/obj") public List<DemoData> listObj(@ExcelParam List<DemoData> list) { return list; }
注意引數前新增了 @ExcelParam
註解,用來標識 Excel 檔案引數。這樣,一個匯入功能實現了,是不是很簡單呢?
預設情況下接收名稱為 file
的表單欄位作為 Excel 檔案,如果不滿足還可以修改。
@ExcelParam(value = "file", required = true)
有時候,我們可能比較關心物件對應 Excel 的後設資料,例如這個物件是第幾行記錄產生的,這個物件的欄位對應 Excel 第幾列,這個時候我們可以使用 ReadRows<T>
引數接收 Excel。
@PostMapping("/list/rows") public ReadRows<DemoData> readRows(@ExcelParam ReadRows<DemoData> readRows) { return readRows; }
ReadRows
使用兩個欄位記錄行對映關係與列對映關係。
public class ReadRows<T> { private ExcelReadHeadProperty excelReadHeadProperty; private List<ReadRow<T>> rows; }
ExcelReadHeadProperty
是 EasyExcel 自帶的類,表示列對映關係的後設資料。ReadRow
是框架自定義的類,表示行對映關係的後設資料。
看下 ReadRow 定義吧。
public class ReadRow<T> { // 行索引,從 0 開始 private final Integer rowIndex; // 行記錄對應物件 private final T data; }
使用 ExcelReadHeadProperty 獲取欄位對應列索引的範例程式碼如下。
// 物件欄位名稱 -> 從 0 開始的列索引 Map<String, Integer> fieldColumnIndexMap = readRows.getExcelReadHeadProperty().getHeadMap().values() .stream().collect(Collectors.toMap(Head::getFieldName, Head::getColumnIndex));
這裡對 Excel 的匯出進行了簡單的支援。將 List<T>
定義為 controller 方法返回值即可。
@ExcelResponse @GetMapping("/list/download") public List<DemoData> downloadList() { return Arrays.asList(new DemoData(1, "hello", new Date()), new DemoData(2, "excel", new Date())); }
需要注意的是使用 @ExcelResponse
註解表示響應內容為 Excel 檔案。預設情況,下載的檔名稱為 default.xlxs
,寫入到名稱為 Sheet1
的工作表中。如果不滿足需求可以修改。
@ExcelResponse(fileName = "測試檔案", sheetName = "工作表1")
引數校驗是 Excel 匯入常用的功能,這裡進行了強有力的支援,使用體驗如原生 spring boot 校驗般順滑。
與 spring boot 原生使用方式一樣,將 @Validated
或 @Valid
註解新增到 @ExcelParam
引數上即可。
@PostMapping("/list/obj") public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list) { return list; }
預設情況下框架使用 JSR-303 Bean Validation 規範定義的校驗註解校驗,需要手動引入 spring-boot-starter-validation
,可通過設定環境變數 easyexcel.validator.default.enable=false
關閉。
@Data public class DemoData { @NotNull(message = "引數不能為空") private Integer integer; private String string; private Date date; }
另外還可以自定義註解對物件校驗。
... 省略其他元註解 @Constraint(validatedBy = {DemoDataValid.DemoDataValidator.class}) public @interface DemoDataValid { ... 省略註解屬性 class DemoDataValidator implements ConstraintValidator<DemoDataValid, DemoData> { @Override public boolean isValid(DemoData value, ConstraintValidatorContext context) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("測試物件校驗").addConstraintViolation(); return false; } } }
@DemoDataValid public class DemoData { ... 省略屬性 }
Bean Validation 註解只能校驗單個欄位或物件,如果需要對所有的物件進行校驗,可以實現框架定義的 ExcelValidator
介面,然後將實現定義為 Spring Bean。
這個介面定義如下。
public interface ExcelValidator<T> { ExcelValidErrors validate(ReadRows<T> readRows); }
ExcelValidErrors
用於接收校驗的錯誤資訊,分別使用介面 ExcelValidObjectError
和 ExcelValidFieldError
介面定義行錯誤資訊和單元格錯誤資訊。
public class ExcelValidErrors { // 行錯誤資訊或單元格錯誤資訊列表 private final List<ExcelValidObjectError> errors; } public interface ExcelValidObjectError { // 獲取行號,從 1 開始 Integer getRow(); // 獲取錯誤訊息 String getMessage(); } public interface ExcelValidFieldError extends ExcelValidObjectError { // 獲取列,從 1 開始 Integer getColumn(); }
例如,如果需要對所有的 DemoData
校驗 integer
欄位的值不能重複,可以使用如下的程式碼。
@Component public class CustomExcelValidator implements ExcelValidator<DemoData> { @Override public ExcelValidErrors validate(ReadRows<DemoData> readRows) { ExcelValidErrors errors = new ExcelValidErrors(); Map<Integer, List<ReadRow<DemoData>>> group = readRows.getRows().stream() .collect(Collectors.groupingBy(item -> item.getData().getInteger())); for (Map.Entry<Integer, List<ReadRow<DemoData>>> entry : group.entrySet()) { if (entry.getValue().size() > 1) { for (ReadRow<DemoData> readRow : entry.getValue()) { errors.addError(new DefaultExcelObjectError(readRow.getRowIndex() + 1, "引數重複")); } } } return errors; } }
與 Spring MVC 設計類似,這裡也提供了兩種接收校驗結果的方式。
開啟校驗後,如果校驗結果中包含錯誤,會將錯誤資訊封裝到 ExcelValidException
,並丟擲異常,可以通過全域性異常捕獲的方式收集錯誤資訊。
@RestControllerAdvice public class GlobalExceptionControllerAdvice { @ExceptionHandler(ExcelValidException.class) public String handleException(ExcelValidException e) { ExcelValidErrors errors = e.getErrors(); return JSON.toJSONString(errors); } }
如果不想通過異常捕獲的方式接收校驗的錯誤資訊,還可以將錯誤資訊新增到 @ExcelParam
引數的後面,範例程式碼如下。
@PostMapping("/list/obj") public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list, ExcelValidErrors errors) { if (errors.hasErrors()) { String messages = errors.getAllErrors().stream().map(ExcelValidObjectError::getMessage).collect(Collectors.joining(" | ")); throw new RuntimeException("發現異常:" + messages); } return list; }
easyexcel-spring-boot-starter 綜合應用了前面文章介紹的各種 Spring 知識,程式碼量並不大,對實現感興趣的小夥伴可自行查閱程式碼。由於這個框架是把 Excel 中所有的行資料收集到記憶體,因此只適合一些比較簡單的場景。
到此這篇關於Spring Boot專案如何優雅實現Excel匯入與匯出功能的文章就介紹到這了,更多相關SpringBoot實現Excel匯入匯出內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45