Java?EasyExcel利用填充模版動態(tài)生成多個sheet頁
一、前言
今天收到一個導(dǎo)出Excel的需求,這種需求經(jīng)常做,看到模版還是是有點復(fù)雜的有頭有行,一般的導(dǎo)出是不好做,使用模板填充比較簡單! 另外還有一個需求小編是第一次見,所以來記錄一下,為后來人鋪路!
需求:導(dǎo)出有單子的頭信息和一些多個行信息,前端可以多選,多個放在一個excel里的sheet中
明白了需求我們技術(shù)選型,現(xiàn)在基本都是EasyExcel
用的比較多,今天使用的版本為:3.1.5
,低版本已經(jīng)不維護,建議使用高點的版本哈!
在這里先說一下,EasyExcel單獨是無法實現(xiàn)一個模版動態(tài)填充多個sheet頁,所以我們使用POI來幫忙復(fù)制sheet頁即可!
二、準(zhǔn)備工作
1. 閹割版效果圖
我簡化了一些功能,自己做了一個簡單的模板,但是功能都是有的,大致如下圖所示:
多個就使用合同號作為sheet名稱,每個里面也會有多個行垂直填充即可!
2. 填充模版
3. 導(dǎo)入依賴
中間使用了Hutool
來獲取流,很多公司不讓使用Hutool的,大家自己選擇,不使用可以用:
- Spring的ResourceUtils.getFile()
- JDK的new File()
本次使用Hutool的ClassPathResource
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.5</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.4</version> </dependency>
4. 導(dǎo)出實體
/** * @author wangzhenjun * @date 2023/7/4 17:09 */ @Data public class TestExcel { private String contractNo; private String address; private String dateTime; private List<Item> itemList; @Data public static class Item{ private String name; private BigDecimal price; } }
三、實戰(zhàn)代碼
為了方便直接寫在Controller里了,大家不要學(xué)習(xí)哈,業(yè)務(wù)的處理還是要在service里寫!
整體思路:
使用POI
的XSSFWorkbook
來根據(jù)要導(dǎo)出的個數(shù)來進行復(fù)制sheet頁,名稱為合同號
將復(fù)制好的sheet頁轉(zhuǎn)換成字節(jié)數(shù)組,然后再通過輸入流的方式讀取字節(jié)數(shù)組中的數(shù)據(jù)。
EasyExcel
將使用輸入流中的模板數(shù)據(jù)生成 Excel 數(shù)據(jù),并將生成的 Excel 文件寫入到 HttpServletResponse
的輸出流中,以便將其發(fā)送給客戶端進行下載或其他處理。
創(chuàng)建一個 WriteSheet
對象,并將其與上面復(fù)制的sheet頁名稱關(guān)聯(lián),就可以往里面填充數(shù)據(jù)了!
如果有這種list多個行填充的并且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true
不加的話會把你后面的內(nèi)容給覆蓋了!
但是這個就會把所有數(shù)據(jù)放到內(nèi)存 會很耗內(nèi)存!
用完記得把流關(guān)閉哈!
@SneakyThrows @GetMapping("/excel") public void excel (HttpServletResponse response){ int size = 2; List<TestExcel> testExcels = new ArrayList<>(); for (int i = 0; i < size; i++) { TestExcel testExcel = new TestExcel(); testExcel.setContractNo("HT07040" + (i + 1)); testExcel.setAddress("青島" + i + "號基地"); testExcel.setDateTime("2023-07-05"); testExcels.add(testExcel); List<TestExcel.Item> itemList = new ArrayList<>(); for (int j = 0; j < size; j++) { TestExcel.Item item = new TestExcel.Item(); item.setName("商品" + (j + 1)); item.setPrice(new BigDecimal("188").multiply(new BigDecimal(j + 1))); itemList.add(item); } testExcel.setItemList(itemList); } response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("測試", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); ClassPathResource classPathResource = new ClassPathResource("template" + File.separator + "測試.xlsx"); InputStream stream = classPathResource.getStream(); // 把excel流給這個對象,后續(xù)可以操作 XSSFWorkbook workbook = new XSSFWorkbook(stream); // 設(shè)置模板的第一個sheet的名稱,名稱我們使用合同號 workbook.setSheetName(0, testExcels.get(0).getContractNo()); for (int i = 1; i < size; i++) { // 剩余的全部復(fù)制模板sheet0即可 workbook.cloneSheet(0, testExcels.get(i).getContractNo()); } // 把workbook寫到流里 ByteArrayOutputStream baos = new ByteArrayOutputStream(); workbook.write(baos); byte[] bytes = baos.toByteArray(); stream = new ByteArrayInputStream(bytes); ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(stream).build(); for (TestExcel testExcel : testExcels) { WriteSheet writeSheet = EasyExcel.writerSheet(testExcel.getContractNo()).build(); // list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個就會把所有數(shù)據(jù)放到內(nèi)存 會很耗內(nèi)存 FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).direction(WriteDirectionEnum.VERTICAL).build(); excelWriter.fill(testExcel, writeSheet); excelWriter.fill(new FillWrapper("item", testExcel.getItemList()), fillConfig, writeSheet); } excelWriter.finish(); baos.close(); stream.close(); }
四、總結(jié)
這樣就完成了,主要的難點是復(fù)制sheet頁,多行填充在EasyExcel官網(wǎng)都是有的,還有一些我這邊沒有用到的東西,大家可以根據(jù)自己的需求去找找看!
到此這篇關(guān)于Java EasyExcel利用填充模版動態(tài)生成多個sheet頁的文章就介紹到這了,更多相關(guān)Java EasyExcel生成多個sheet內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot 各種回滾操作實戰(zhàn)教程(自動回滾、手動回滾、部分回滾)
這篇文章主要介紹了Spring Boot 各種回滾操作實戰(zhàn)教程(自動回滾、手動回滾、部分回滾),本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07springboot對接支付寶支付接口(詳細開發(fā)步驟總結(jié))
這篇文章主要介紹了springboot對接支付寶支付接口(詳細開發(fā)步驟總結(jié)),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Java實現(xiàn)RedisUtils操作五大集合(增刪改查)
本文主要介紹了Java實現(xiàn)RedisUtils操作五大集合,文中通過示例代碼介紹的非常詳細,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07Java使用System.currentTimeMillis()方法計算程序運行時間的示例代碼
System.currentTimeMillis() 方法的返回類型為 long ,表示毫秒為單位的當(dāng)前時間,文中通過示例代碼介紹了計算 String 類型與 StringBuilder 類型拼接字符串的耗時情況,對Java計算程序運行時間相關(guān)知識感興趣的朋友一起看看吧2022-03-03Maven腳手架如何基于jeecg實現(xiàn)快速開發(fā)
這篇文章主要介紹了Maven腳手架如何基于jeecg實現(xiàn)快速開發(fā),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10