欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2023年10月27日 11:23:30   作者:從前有只貓頭鷹  
業(yè)務(wù)中經(jīng)常需要按照一個特定的模板導(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的時候不管list下面有沒有空行 都會創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動。默認(rèn) 是false,會直接使用下一行,如果沒有則創(chuàng)建。
            // forceNewRow 如果設(shè)置了true,有個缺點 就是他會把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
            // 簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個就會把所有數(shù)據(jù)放到內(nèi)存 會很耗內(nèi)存
            // 如果數(shù)據(jù)量大 list不是最后一行 參照下一個
            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項目,將輸出改為了輸出流 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的時候不管list下面有沒有空行 都會創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動。默認(rèn) 是false,會直接使用下一行,如果沒有則創(chuàng)建。
			// forceNewRow 如果設(shè)置了true,有個缺點 就是他會把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
			// 簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個就會把所有數(shù)據(jù)放到內(nèi)存 會很耗內(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è)務(wù)和字典不在一個數(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),每一個質(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ù)加上序號
				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ù)和字典不在同一個數(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);

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

3.填充缺少的列名

模版:

 效果:

 因為我后半部分列名涉及到行轉(zhuǎn)列,且不固定列數(shù),所以需要橫著填充上列名。注意列表的名字“cols”要對應(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的時候不管list下面有沒有空行 都會創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動。默認(rèn) 是false,會直接使用下一行,如果沒有則創(chuàng)建。
// forceNewRow 如果設(shè)置了true,有個缺點 就是他會把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
// 簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個就會把所有數(shù)據(jù)放到內(nèi)存 會很耗內(nèi)存
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
List<Map<String, Object>> dataList = (List<Map<String, Object>>) mapDetail.get("dataList");
 
/*以下為個人業(yè)務(wù)處理*/
for (int i = 0; i < dataList.size(); i++) {
	Map<String, Object> data = dataList.get(i);
	// 翻譯判定合不合格(因為業(yè)務(wù)和字典不在一個數(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),每一個質(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ù)加上序號
	data.put("index", i + 1);
}
/*以上為個人業(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的時候不管list下面有沒有空行 都會創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動。默認(rèn) 是false,會直接使用下一行,如果沒有則創(chuàng)建。forceNewRow 如果設(shè)置了true,有個缺點 就是他會把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個就會把所有數(shù)據(jù)放到內(nèi)存 會很耗內(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");

四、思想

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

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

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

理論上可行,但我沒試。

總結(jié)

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

相關(guān)文章

最新評論