最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用EasyExcel模版導(dǎo)出詳細(xì)操作教程

 更新時(shí)間:2023年10月27日 11:23:30   作者:從前有只貓頭鷹  
業(yè)務(wù)中經(jīng)常需要按照一個(gè)特定的模板導(dǎo)出特定內(nèi)容,有些單元格還要求特殊的格式,所以下面這篇文章主要給大家介紹了關(guān)于Java使用EasyExcel模版導(dǎo)出的相關(guān)資料,需要的朋友可以參考下

一、官方提供方法

easyexcel官方文檔 填充Excel | Easy Excel

官方demo是利用本地模版文件填充并下載到本地

    /**
     * 復(fù)雜的填充
     *
     * @since 2.1.1
     */
    @Test
    public void complexFill() {
        // 模板注意 用{} 來表示你要用的變量 如果本來就有"{","}" 特殊字符 用"\{","\}"代替
        // {} 代表普通變量 {.} 代表是list的變量
        String templateFileName =
            TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "complex.xlsx";
 
        String fileName = TestFileUtil.getPath() + "complexFill" + System.currentTimeMillis() + ".xlsx";
        // 方案1
        try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            // 這里注意 入?yún)⒂昧薴orceNewRow 代表在寫入list的時(shí)候不管list下面有沒有空行 都會(huì)創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動(dòng)。默認(rèn) 是false,會(huì)直接使用下一行,如果沒有則創(chuàng)建。
            // forceNewRow 如果設(shè)置了true,有個(gè)缺點(diǎn) 就是他會(huì)把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
            // 簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個(gè)就會(huì)把所有數(shù)據(jù)放到內(nèi)存 會(huì)很耗內(nèi)存
            // 如果數(shù)據(jù)量大 list不是最后一行 參照下一個(gè)
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(data(), fillConfig, writeSheet);
            excelWriter.fill(data(), fillConfig, writeSheet);
            Map<String, Object> map = MapUtils.newHashMap();
            map.put("date", "2019年10月9日13:28:28");
            map.put("total", 1000);
            excelWriter.fill(map, writeSheet);
        }
    }

二、根據(jù)業(yè)務(wù)場景的方法

我用的是web項(xiàng)目,將輸出改為了輸出流 OutputStream

	/**
	 * 導(dǎo)出質(zhì)檢任務(wù)詳情
	 *
	 * @param id 任務(wù)主鍵,用于獲取數(shù)據(jù)
	 */
	@Override
	public void exportTask(Long id, HttpServletResponse response) {
		ExcelWriter excelWriter = null;
		try {
			// outputStream:要導(dǎo)出的文件的輸出流
			OutputStream outputStream = response.getOutputStream();
			// 模版文件
			ClassPathResource classPathResource = new ClassPathResource("template/taskTemplate.xlsx");
			// 使用模版文件的兩種方式:
			// 	1、文件路徑:.withTemplate(templateFileName)
			// 	2、輸入流:.withTemplate(inputStream)
			String templateFileName = classPathResource.getFile().getPath();
			InputStream inputStream = classPathResource.getInputStream();
 
			excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).excelType(ExcelTypeEnum.XLSX).autoCloseStream(Boolean.FALSE).build();
			WriteSheet writeSheet = EasyExcel.writerSheet().build();
 
			// 獲取數(shù)據(jù) dataList columnList formData
			Map<String, Object> mapDetail = qmsQcTaskDetailService.getDataListByTaskId(id);
 
			// 調(diào)用微服務(wù)獲取字典 determine 用來翻譯判定結(jié)果
			List<SysDictItem> determineItem = remoteDictService.getDictByType("determine").getData();
			// 調(diào)用微服務(wù)獲取字典 product_unit 用來翻譯零件單位
			List<SysDictItem> unitItem = remoteDictService.getDictByType("product_unit").getData();
 
			/* 1、List以外的數(shù)據(jù) */
			QmsQcTask formData = (QmsQcTask) mapDetail.get("formData");
			determineItem.stream().filter(item -> StrUtil.equals(formData.getResult(), item.getItemValue())).findFirst().ifPresent(sysDictItem -> formData.setResult(sysDictItem.getLabel()));
			unitItem.stream().filter(item -> StrUtil.equals(formData.getMaterialUnit(), item.getItemValue())).findFirst().ifPresent(sysDictItem -> formData.setMaterialUnit(sysDictItem.getLabel()));
			excelWriter.fill(formData, writeSheet);
			/* 2、List cols數(shù)據(jù) */
			List<Map<String, Object>> cols = new ArrayList<>();
			// 查找抽檢數(shù)是多少,即有幾列
			int num = formData.getSampleNum();
			for (int i = 1; i <= num; i++) {
				Map<String, Object> map = new HashMap<>();
				// 列名
				map.put("label", "" + i);
				cols.add(map);
			}
			// 橫向填充
			FillConfig fillConfigCols = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
			excelWriter.fill(new FillWrapper("cols", cols), fillConfigCols, writeSheet);
 
			/* 3、List details數(shù)據(jù) */
			// 這里注意 入?yún)⒂昧薴orceNewRow 代表在寫入list的時(shí)候不管list下面有沒有空行 都會(huì)創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動(dòng)。默認(rèn) 是false,會(huì)直接使用下一行,如果沒有則創(chuàng)建。
			// forceNewRow 如果設(shè)置了true,有個(gè)缺點(diǎn) 就是他會(huì)把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
			// 簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個(gè)就會(huì)把所有數(shù)據(jù)放到內(nèi)存 會(huì)很耗內(nèi)存
			FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
			List<Map<String, Object>> dataList = (List<Map<String, Object>>) mapDetail.get("dataList");
			for (int i = 0; i < dataList.size(); i++) {
				Map<String, Object> data = dataList.get(i);
				// 翻譯判定合不合格(因?yàn)闃I(yè)務(wù)和字典不在一個(gè)數(shù)據(jù)庫,所以放在代碼里處理)
				String determine = (String) data.get("determine");
				determineItem.stream().filter(item -> StrUtil.equals(determine, item.getItemValue())).findFirst().ifPresent(sysDictItem -> data.put("determine", sysDictItem.getLabel()));
				// 如果沒有質(zhì)檢標(biāo)準(zhǔn),每一個(gè)質(zhì)檢值都要轉(zhuǎn)為合不合格
				if (StrUtil.isBlank((String) data.get("inspection_standard"))){
					int samplingNum = Optional.ofNullable((Integer) data.get("sampling_num")).orElse(0);
					for (int j = 1; j <= samplingNum; j++) {
						String val = (String) data.get(""+j);
						int finalJ = j;
						determineItem.stream().filter(item -> StrUtil.equals(val, item.getItemValue())).findFirst().ifPresent(sysDictItem -> data.put(""+ finalJ, sysDictItem.getLabel()));
					}
				}
				// 給數(shù)據(jù)加上序號(hào)
				data.put("index", i + 1);
			}
			excelWriter.fill(new FillWrapper("details", dataList), fillConfig, writeSheet);
 
			// 設(shè)置輸出流格式以及文件名:
			response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
			response.setCharacterEncoding("utf-8");
			String fileName = URLEncoder.encode("質(zhì)檢任務(wù)", "UTF-8").replaceAll("\\+", "%20");
			response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
 
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			// 千萬別忘記close關(guān)閉流
			if (excelWriter != null) {
				excelWriter.close();
			}
		}
 
	}

 模版:

效果:

三、說明

1、獲取輸出流

// outputStream:要導(dǎo)出的文件的輸出流
OutputStream outputStream = response.getOutputStream();

2、獲取模版文件

// 模版文件
ClassPathResource classPathResource = new ClassPathResource("template/taskTemplate.xlsx");
// 方式一:路徑
String templateFileName = classPathResource.getFile().getPath();
// 方式二:輸入流
InputStream inputStream = classPathResource.getInputStream();

3、創(chuàng)建 ExcelWriter 和 WriteSheet

excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).excelType(ExcelTypeEnum.XLSX).autoCloseStream(Boolean.FALSE).build();
WriteSheet writeSheet = EasyExcel.writerSheet().build();

使用模版文件有兩種方式,使用其中一種就可以:

    1.文件路徑:.withTemplate(templateFileName)

    2.輸入流:.withTemplate(inputStream)

4、獲取數(shù)據(jù)

Map<String, Object> mapDetail = qmsQcTaskDetailService.getDataListByTaskId(id);

我這里直接調(diào)用了方法,map包含

dataList主要列表數(shù)據(jù) formData 列表外的數(shù)據(jù)

5、填充數(shù)據(jù)

1.獲取字典數(shù)據(jù)

// 調(diào)用微服務(wù)獲取字典 determine 用來翻譯判定結(jié)果
List<SysDictItem> determineItem = remoteDictService.getDictByType("determine").getData();
// 調(diào)用微服務(wù)獲取字典 product_unit 用來翻譯零件單位
List<SysDictItem> unitItem = remoteDictService.getDictByType("product_unit").getData();

我的業(yè)務(wù)數(shù)據(jù)和字典不在同一個(gè)數(shù)據(jù)庫內(nèi),sql無法翻譯,所以需要在代碼里翻譯

2.填充列表外的數(shù)據(jù)

/* 1、List以外的數(shù)據(jù) */
			QmsQcTask formData = (QmsQcTask) mapDetail.get("formData");
			determineItem.stream().filter(item -> StrUtil.equals(formData.getResult(), item.getItemValue())).findFirst().ifPresent(sysDictItem -> formData.setResult(sysDictItem.getLabel()));
			unitItem.stream().filter(item -> StrUtil.equals(formData.getMaterialUnit(), item.getItemValue())).findFirst().ifPresent(sysDictItem -> formData.setMaterialUnit(sysDictItem.getLabel()));
			excelWriter.fill(formData, writeSheet);

只要對(duì)象屬性名和模版里寫的標(biāo)記已知就可以了

3.填充缺少的列名

模版:

 效果:

 因?yàn)槲液蟀氩糠至忻婕暗叫修D(zhuǎn)列,且不固定列數(shù),所以需要橫著填充上列名。注意列表的名字“cols”要對(duì)應(yīng)起來。

使用.direction(WriteDirectionEnum.HORIZONTAL) 設(shè)置為橫向填充。

/* 2、List cols數(shù)據(jù) */
List<Map<String, Object>> cols = new ArrayList<>();
// 查找抽檢數(shù)是多少,即有幾列
int num = formData.getSampleNum();
for (int i = 1; i <= num; i++) {
	Map<String, Object> map = new HashMap<>();
	// 列名
	map.put("label", "" + i);
	cols.add(map);
}
// 橫向填充
FillConfig fillConfigCols = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
excelWriter.fill(new FillWrapper("cols", cols), fillConfigCols, writeSheet);

4.填充主列表數(shù)據(jù)

/* 3、List details數(shù)據(jù) */
// 這里注意 入?yún)⒂昧薴orceNewRow 代表在寫入list的時(shí)候不管list下面有沒有空行 都會(huì)創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動(dòng)。默認(rèn) 是false,會(huì)直接使用下一行,如果沒有則創(chuàng)建。
// forceNewRow 如果設(shè)置了true,有個(gè)缺點(diǎn) 就是他會(huì)把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
// 簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個(gè)就會(huì)把所有數(shù)據(jù)放到內(nèi)存 會(huì)很耗內(nèi)存
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
List<Map<String, Object>> dataList = (List<Map<String, Object>>) mapDetail.get("dataList");
 
/*以下為個(gè)人業(yè)務(wù)處理*/
for (int i = 0; i < dataList.size(); i++) {
	Map<String, Object> data = dataList.get(i);
	// 翻譯判定合不合格(因?yàn)闃I(yè)務(wù)和字典不在一個(gè)數(shù)據(jù)庫,所以放在代碼里處理)
	String determine = (String) data.get("determine");
	determineItem.stream().filter(item -> StrUtil.equals(determine, item.getItemValue())).findFirst().ifPresent(sysDictItem -> data.put("determine", sysDictItem.getLabel()));
	// 如果沒有質(zhì)檢標(biāo)準(zhǔn),每一個(gè)質(zhì)檢值都要轉(zhuǎn)為合不合格
	if (StrUtil.isBlank((String) data.get("inspection_standard"))){
		int samplingNum = Optional.ofNullable((Integer) data.get("sampling_num")).orElse(0);
		for (int j = 1; j <= samplingNum; j++) {
			String val = (String) data.get(""+j);
			int finalJ = j;
			determineItem.stream().filter(item -> StrUtil.equals(val, item.getItemValue())).findFirst().ifPresent(sysDictItem -> data.put(""+ finalJ, sysDictItem.getLabel()));
		}
	}
	// 給數(shù)據(jù)加上序號(hào)
	data.put("index", i + 1);
}
/*以上為個(gè)人業(yè)務(wù)處理*/
 
excelWriter.fill(new FillWrapper("details", dataList), fillConfig, writeSheet);

最重要的三句話:

FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
List<Map<String, Object>> dataList = (List<Map<String, Object>>) mapDetail.get("dataList");
 
 
excelWriter.fill(new FillWrapper("details", dataList), fillConfig, writeSheet);

這里注意 入?yún)⒂昧薴orceNewRow 代表在寫入list的時(shí)候不管list下面有沒有空行 都會(huì)創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動(dòng)。默認(rèn) 是false,會(huì)直接使用下一行,如果沒有則創(chuàng)建。forceNewRow 如果設(shè)置了true,有個(gè)缺點(diǎn) 就是他會(huì)把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個(gè)就會(huì)把所有數(shù)據(jù)放到內(nèi)存 會(huì)很耗內(nèi)存

5.設(shè)置輸出流格式以及文件名

// 設(shè)置輸出流格式以及文件名:
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("質(zhì)檢任務(wù)", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

四、思想

我的模版使用了動(dòng)態(tài)的列,不確定有幾列,所以我就寫了一百多個(gè)。

還有另外一種設(shè)想:

如果先把列表外的數(shù)據(jù)填充,然后將主列表的列填充完畢,再把主列表的標(biāo)記寫上,這些操作完畢之后把文件輸出到另外的輸出流上,再將此輸出流轉(zhuǎn)為輸入流,再把主列表的數(shù)據(jù)填充,輸出到response。

理論上可行,但我沒試。

總結(jié)

到此這篇關(guān)于Java使用EasyExcel模版導(dǎo)出的文章就介紹到這了,更多相關(guān)使用EasyExcel模版導(dǎo)出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中的接口知識(shí)匯總

    Java中的接口知識(shí)匯總

    本文給大家匯總介紹了在java中的接口知識(shí),包括為什么要使用接口、什么是接口、抽象類和接口的區(qū)別、如何定義接口以及定義接口注意點(diǎn),希望大家能夠喜歡
    2016-04-04
  • 詳解Java類加載機(jī)制中的雙親委派模型

    詳解Java類加載機(jī)制中的雙親委派模型

    Java的雙親委派模型是一種類加載機(jī)制,它用于保證Java類的安全性和穩(wěn)定性,在這個(gè)模型中,當(dāng)一個(gè)類需要被加載時(shí),Java虛擬機(jī)會(huì)先檢查自己是否已經(jīng)加載了該類,本文就給大家講解一下Java類加載機(jī)制中的雙親委派模型,需要的朋友可以參考下
    2023-09-09
  • SpringBoot整合Redis實(shí)現(xiàn)常用功能超詳細(xì)過程

    SpringBoot整合Redis實(shí)現(xiàn)常用功能超詳細(xì)過程

    這篇文章主要介紹了SpringBoot整合Redis實(shí)現(xiàn)常用功能,登陸功能是每個(gè)項(xiàng)目必備的功能吧,但是想設(shè)計(jì)好,卻是很難,下面介紹兩種登陸功能的解決方式,需要的朋友可以參考下
    2022-08-08
  • IntellIJ?IDEA顯示內(nèi)存不足的完美解決方法

    IntellIJ?IDEA顯示內(nèi)存不足的完美解決方法

    IntelliJ?IDEA是一款廣泛使用的Java集成開發(fā)環(huán)境,以其強(qiáng)大的功能和高效的編碼體驗(yàn)深受開發(fā)者喜愛,然而?在我們導(dǎo)入大項(xiàng)目時(shí),?IntellIJ?Idea?向我們拋出了一個(gè)?OutOfMemoryError?內(nèi)存不足,?所以本文給大家介紹了IntellIJ?Idea顯示內(nèi)存不足的完美解決方法
    2025-03-03
  • Java中日期時(shí)間比較的多種方法及實(shí)用代碼

    Java中日期時(shí)間比較的多種方法及實(shí)用代碼

    本文介紹了Java中不同日期時(shí)間類的比較方法,包括java.util.Date、java.util.Calendar、java.time?API和java.sql.Timestamp,提供了使用before、after和compareTo等方法進(jìn)行日期比較的示例代碼,展示了各自的特點(diǎn)和使用場景,需要的朋友可以參考下
    2024-09-09
  • 解決使用@ManyToMany查詢數(shù)據(jù)時(shí)的死循環(huán)問題

    解決使用@ManyToMany查詢數(shù)據(jù)時(shí)的死循環(huán)問題

    這篇文章主要介紹了解決使用@ManyToMany查詢數(shù)據(jù)時(shí)的死循環(huán)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • spring security環(huán)境搭建

    spring security環(huán)境搭建

    本文通過代碼給大家介紹了spring security環(huán)境搭建的詳細(xì)教程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2017-09-09
  • Java實(shí)現(xiàn)大數(shù)運(yùn)算的實(shí)例代碼

    Java實(shí)現(xiàn)大數(shù)運(yùn)算的實(shí)例代碼

    這篇文章主要介紹了Java實(shí)現(xiàn)大數(shù)運(yùn)算的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • java實(shí)現(xiàn)識(shí)別二維碼圖片功能

    java實(shí)現(xiàn)識(shí)別二維碼圖片功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)識(shí)別二維碼圖片功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Spring容器擴(kuò)展機(jī)制的實(shí)現(xiàn)原理

    Spring容器擴(kuò)展機(jī)制的實(shí)現(xiàn)原理

    這篇文章主要介紹了Spring容器擴(kuò)展機(jī)制的實(shí)現(xiàn)原理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11

最新評(píng)論

贺州市| 洪洞县| 义乌市| 阿拉善右旗| 江西省| 西安市| 大宁县| 卫辉市| 昌乐县| 自治县| 南陵县| 陆河县| 搜索| 磐安县| 玛曲县| 时尚| 井冈山市| 沙坪坝区| 论坛| 陇西县| 赤峰市| 陕西省| 黔西| 佳木斯市| 顺义区| 依兰县| 香港| 襄汾县| 阿坝县| 手游| 大竹县| 三门县| 扎兰屯市| 本溪市| 信宜市| 武功县| 石景山区| 大足县| 贵德县| 蕲春县| 中宁县|