日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

基于easypoi实现自定义模板导出excel

發(fā)布時(shí)間:2025/3/12 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于easypoi实现自定义模板导出excel 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

項(xiàng)目中需要做一個(gè)統(tǒng)計(jì)報(bào)表功能,實(shí)現(xiàn)各種Excel報(bào)表數(shù)據(jù)導(dǎo)出。要求表頭能夠動(dòng)態(tài)配置,表數(shù)據(jù)通過存儲(chǔ)過程實(shí)現(xiàn),也要求能夠動(dòng)態(tài)配置。

技術(shù)選型:
由于之前在項(xiàng)目中使用過easypoi,相對(duì)于原生apache poi,能夠用很少的代碼寫出Excel導(dǎo)入、導(dǎo)出功能,且API清晰好理解。因此優(yōu)先選擇了使用easypoi,驗(yàn)證功能需求能否實(shí)現(xiàn)。easypoi是基于apache poi開發(fā),在此基礎(chǔ)上進(jìn)行了封裝和擴(kuò)展,特別復(fù)雜的功能就需要使用基礎(chǔ)poi來開發(fā)了。

開發(fā)指南:https://opensource.afterturn.cn/doc/easypoi.html

實(shí)現(xiàn)思路:
由于配置的報(bào)表多是復(fù)雜多級(jí)表頭,而easypoi對(duì)于動(dòng)態(tài)表頭生成只支持兩級(jí),簡(jiǎn)單來說就是表頭最多兩行,所以這種方式就只能放棄。改選用配置動(dòng)態(tài)模板的方式,先做好模板,然后配置到數(shù)據(jù)表里。

實(shí)現(xiàn)步驟:
Maven pom中引入jar包

<dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>3.0.1</version> </dependency> <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-web</artifactId><version>3.0.1</version> </dependency> <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-annotation</artifactId><version>3.0.1</version> </dependency>

ReportController類: 如下代碼僅顯示主要步驟:

@RequestMapping("/exportExcel.html")@ResponseBodypublic void exportExcel(HttpServletResponse response, HttpSession session) {// 獲取報(bào)表配置 ReportResultVo主要存儲(chǔ)了 標(biāo)題行數(shù)、模板路徑位置、導(dǎo)出文件名稱等ReportResultVo config = reportService.getReportConfig(id);TemplateExportParams params = new TemplateExportParams();// 標(biāo)題開始行params.setHeadingStartRow(0);// 標(biāo)題行數(shù)params.setHeadingRows(config.getHeadRowNum());// 設(shè)置sheetName,若不設(shè)置該參數(shù),則使用得原本得sheet名稱params.setSheetName("數(shù)據(jù)統(tǒng)計(jì)");// 獲取報(bào)表內(nèi)容 // 因?yàn)楸頂?shù)據(jù)是根據(jù)存儲(chǔ)過程來實(shí)現(xiàn)的,不同的報(bào)表有不同的配置,// 所以使用Map<String,Object>格式來接收List<Map<String, Object>> reportBodyList = reportService.getReportBodyData(...);Map<String, Object> data = new HashMap<String, Object>();data.put("list", reportBodyList);// 獲取模板文件路徑// 這里有個(gè)很坑的地方,就是easypoi的API只能接收文件路徑,無法讀取文件流String filePath = 服務(wù)器上的某個(gè)路徑或者項(xiàng)目中的某個(gè)路徑// 設(shè)置模板路徑params.setTemplateUrl(filePath);// 獲取workbookWorkbook workbook = ExcelExportUtil.exportExcel(params, data);// exportFileName代表導(dǎo)出的文件名稱ReportUtils.export(response, workbook, exportFileName);

ReportUtils類:

// Excel 導(dǎo)出 通過瀏覽器下載的形式public static void export(HttpServletResponse response, Workbook workbook, String fileName) throws IOException {response.setHeader("Content-Disposition","attachment;filename=" + new String(fileName.getBytes("UTF-8"), "iso8859-1"));response.setContentType("application/vnd.ms-excel;charset=UTF-8");response.setHeader("Pragma", "no-cache");response.setHeader("Cache-Control", "no-cache");response.setDateHeader("Expires", 0);BufferedOutputStream bufferedOutPut = new BufferedOutputStream(response.getOutputStream());workbook.write(bufferedOutPut);bufferedOutPut.flush();bufferedOutPut.close();}

模板樣式:

模板以{{$fe:list 開頭,以}}結(jié)尾,代表變遍歷數(shù)據(jù)的意思,每個(gè)字段前面的t.前綴是easypoi指定的默認(rèn)值。

獲取的報(bào)表內(nèi)容字段名稱要與模板里的字段一一對(duì)應(yīng)

List<Map<String, Object>> reportBodyList = new ArrayList<>();Map<String,Object> values = new HashMap<StringObject>();values.put(c1,總計(jì));values.put(c2,10);values.put(c3,5);values.put(c4,8);values.put(c5,5);values.put(c6,8);values.put(c7,6);values.put(c8,3);reportBodyList.add(values);

導(dǎo)出的Excel結(jié)果如下:

到目前為止,已經(jīng)可以實(shí)現(xiàn)需求了,但是實(shí)現(xiàn)的不夠好,尤其是上面提到的easypoi無法讀取文件流,只能從本地路徑上獲取文件模板,極大的限制了程序的靈活性。而生產(chǎn)環(huán)境中的項(xiàng)目大多都會(huì)使用文件存儲(chǔ)服務(wù)器,比如fastdfs,而不是把模板上傳到web服務(wù)器上的某個(gè)路徑下。


還有別的解決辦法嗎?實(shí)在無法實(shí)現(xiàn)需求的話就只能使用apache poi了,但是這種方式改動(dòng)太大,雖然可以靈活定制excel樣式,但是實(shí)現(xiàn)要復(fù)雜的多。思考良久后,決定使用臨時(shí)文件的方式解決這個(gè)問題。

實(shí)現(xiàn)思路:
從fastdfs中獲取文件流后,寫到本地臨時(shí)目錄,然后讓easypoi從本地臨時(shí)目錄里讀取模板文件,最后再刪除臨時(shí)文件。

關(guān)鍵代碼如下:

@RequestMapping("/exportExcel.html")@ResponseBodypublic void exportExcel(HttpServletResponse response, HttpSession session) {......try{// 從fastDfs上獲取文件流 (fileStorage.readFile自己封裝的API)InputStream inputStream = fileStorage.readFile(filepath); // 模板臨時(shí)目錄String rootPath = session.getServletContext().getRealPath(“template_temp/);// 臨時(shí)文件路徑名String filePath = rootPath + "_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + filename;tempFile = new File(filePath);// 保存到臨時(shí)文件ReportUtils.saveTempFile(inputStream, tempFile);// 設(shè)置模板路徑params.setTemplateUrl(filePath);// 獲取workbookWorkbook workbook = ExcelExportUtil.exportExcel(params, data);// exportFileName代表導(dǎo)出的文件名稱ReportUtils.export(response, workbook, exportFileName);} catch (Exception e) {throw new GeneralException(ErrorCode.REPORT_EXPORT_EXCEPTION);} finally {// 刪除臨時(shí)文件if (tempFile.exists()) {tempFile.delete();}}}

ReportUtils類:

// 保存到臨時(shí)目錄 public static void saveTempFile(InputStream inputStream, File tempFile) throws IOException {if(!tempFile.getParentFile().exists()){ //如果文件的目錄不存在tempFile.getParentFile().mkdirs(); //創(chuàng)建目錄}OutputStream os = new FileOutputStream(tempFile);byte[] b = new byte[2048];int length;while ((length = inputStream.read(b)) > 0) {os.write(b, 0, length);}os.flush();os.close();inputStream.close(); }

至此,代碼實(shí)現(xiàn)較好的滿足了動(dòng)態(tài)配置的需要,如果大家有更好的方法,歡迎提出!


------------本文結(jié)束感謝您的閱讀------------

總結(jié)

以上是生活随笔為你收集整理的基于easypoi实现自定义模板导出excel的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。