摘要:將查詢到的結果生成和文件,再以字節流的形式返回給前端。則是用于創建字節輸出流,在導出文件的代碼結尾,通過工具類中的復制文件函數將字節流寫入到輸出流中,從而將文件以字節流的形式返回給客戶端。
title: 想在Java中實現Excel和Csv的導出嗎?看這就對了
date: 2019-03-01 20:07:07
tags: Java
keywords: Java導出Excel和Csv
最近在項目中遇到一個需求,需要后端提供一個下載Csv和Excel表格的接口。這個接口接收前端的查詢參數,針對這些參數對數據庫做查詢操作。將查詢到的結果生成Excel和Csv文件,再以字節流的形式返回給前端。
前端拿到這個流文件之后,最開始用ajax來接收,但是前端發送的請求卻被瀏覽器cancel掉了。后來發現,發展了如此之久的Ajax居然不支持流文件下載。后來前端換成了最原始的XMLHttpRequest,才修復了這個問題。
首先給出項目源碼的地址。這是源碼,歡迎大家star或者提MR。
Csv 新建controller先來一個簡單的例子。首先在controller中新建這樣一個接口。
@GetMapping("csv") public void csv( HttpServletRequest request, HttpServletResponse response ) throws IOException { String fileName = this.getFileName(request, "測試數據.csv"); response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString()); response.setHeader("Content-Disposition", "attachment; filename="" + fileName + "";"); LinkedHashMapheader = new LinkedHashMap<>(); LinkedHashMap body = new LinkedHashMap<>(); header.put("1", "姓名"); header.put("2", "年齡"); List > data = new ArrayList<>(); body.put("1", "小明"); body.put("2", "小王"); data.add(header); data.add(body); data.add(body); data.add(body); FileCopyUtils.copy(ExportUtil.exportCSV(data), response.getOutputStream()); }
其中this.getFileName(request, "測試數據.csv")函數是用來獲取導出文件名的函數。多帶帶提出來是因為不同瀏覽器使用的默認的編碼不同。例如,如果使用默認的UTF-8編碼。在chrome瀏覽器中下載會出現中文亂碼。代碼如下。
private String getFileName(HttpServletRequest request, String name) throws UnsupportedEncodingException { String userAgent = request.getHeader("USER-AGENT"); return userAgent.contains("Mozilla") ? new String(name.getBytes(), "ISO8859-1") : name; }
response.getOutputStream()則是用于創建字節輸出流,在導出csv文件的controller代碼結尾,通過工具類中的復制文件函數將字節流寫入到輸出流中,從而將csv文件以字節流的形式返回給客戶端。
當前端通過http請求訪問服務器接口的時候,http中的所有的請求信息都會封裝在HttpServletRequest對象中。例如,你可以通過這個對象獲取到請求的URL地址,請求的方式,請求的客戶端IP和完整主機名,Web服務器的IP和完整主機名,請求行中的參數,獲取請求頭的參數等等。
針對每一次的HTTP請求,服務器會自動創建一個HttpServletResponse對象和請求對象相對應。響應對象可以對當前的請求進行重定向,自定義響應體的頭部,設置返回流等等。
新建導出工具類我們新建一個導出工具類,來專門負責導出各種格式的文件。代碼如下。
public class ExportUtil { public static byte[] exportCSV(List> exportData) { ByteArrayOutputStream out = new ByteArrayOutputStream(); BufferedWriter buffCvsWriter = null; try { buffCvsWriter = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)); // 將body數據寫入表格 for (Iterator > iterator = exportData.iterator(); iterator.hasNext(); ) { fillDataToCsv(buffCvsWriter, iterator.next()); if (iterator.hasNext()) { buffCvsWriter.newLine(); } } // 刷新緩沖 buffCvsWriter.flush(); } catch (IOException e) { e.printStackTrace(); } finally { // 釋放資源 if (buffCvsWriter != null) { try { buffCvsWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } return out.toByteArray(); } private static void fillDataToCsv(BufferedWriter buffCvsWriter, LinkedHashMap row) throws IOException { Map.Entry propertyEntry; for (Iterator propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) { propertyEntry = propertyIterator.next(); buffCvsWriter.write(""" + propertyEntry.getValue().toString() + """); if (propertyIterator.hasNext()) { buffCvsWriter.write(","); } } } }
fillDataToCsv主要是抽離出來為csv填充一行一行的數據的。
運行然后運行項目,調用http://localhost:8080/csv,就可以下載示例的csv文件。示例如下。
Excel 新建controller新建下載xlsx文件的接口。
@GetMapping("xlsx") public void xlsx( HttpServletRequest request, HttpServletResponse response ) throws IOException { String fileName = this.getFileName(request, "測試數據.xlsx"); response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString()); response.setHeader("Content-Disposition", "attachment; filename="" + fileName + "";"); List補充工具類> datas = new ArrayList<>(); LinkedHashMap data = new LinkedHashMap<>(); data.put("1", "姓名"); data.put("2", "年齡"); datas.add(data); for (int i = 0; i < 5; i++) { data = new LinkedHashMap<>(); data.put("1", "小青"); data.put("2", "小白"); datas.add(data); } Map >> tableData = new HashMap<>(); tableData.put("日報表", datas); tableData.put("周報表", datas); tableData.put("月報表", datas); FileCopyUtils.copy(ExportUtil.exportXlsx(tableData), response.getOutputStream()); }
上面新建的導出工具類中,只有導出csv的函數,接下來我們要添加導出xlsx的函數。
public static byte[] exportXlsx(Map>> tableData) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { HSSFWorkbook workbook = new HSSFWorkbook(); // 創建多個sheet for (Map.Entry >> entry : tableData.entrySet()) { fillDataToXlsx(workbook.createSheet(entry.getKey()), entry.getValue()); } workbook.write(out); } catch (IOException e) { e.printStackTrace(); } return out.toByteArray(); } /** * 將linkedHashMap中的數據,寫入xlsx表格中 * * @param sheet * @param data */ private static void fillDataToXlsx(HSSFSheet sheet, List > data) { HSSFRow currRow; HSSFCell cell; LinkedHashMap row; Map.Entry propertyEntry; int rowIndex = 0; int cellIndex = 0; for (Iterator > iterator = data.iterator(); iterator.hasNext(); ) { row = iterator.next(); currRow = sheet.createRow(rowIndex++); for (Iterator propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) { propertyEntry = propertyIterator.next(); if (propertyIterator.hasNext()) { String value = String.valueOf(propertyEntry.getValue()); cell = currRow.createCell(cellIndex++); cell.setCellValue(value); } else { String value = String.valueOf(propertyEntry.getValue()); cell = currRow.createCell(cellIndex++); cell.setCellValue(value); break; } } if (iterator.hasNext()) { cellIndex = 0; } } }
fillDataToXlsx的用途與csv一樣,為xlsx文件的每一行刷上數據。
運行然后運行項目,調用http://localhost:8080/xlsx,就可以下載示例的csv文件。示例如下。
項目地址最后再次給出項目地址,大家如果沒有理解到其中的一些地方,不妨把項目clone下來,自己親自操作一波。
參考這是在解決請求被瀏覽器cancel掉的過程中,很重要的一個參考,分享給大家。
https://www.cnblogs.com/cdemo...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73642.html
摘要:首發我的博客最近接到這么個需求,要把顯示的數據導出成表。之,發現又成了一座分水嶺。后來開放標準,可以導出格式的文件,就有了用武之地,導出數據并保存為有了更好的選擇。輸出內容套用模版之后,我們就有了完整的表格數據。至此,此項功能宣告圓滿。 首發我的博客 http://blog.meathill.com/tech/js/export-table-data-into-a-excel-f...
摘要:為了便于您更清晰的理解的體系架構,在這里我將為您展示年開發者知識圖譜,它包含了所有開發過程中的關鍵部分。在數據展示前端導入導出圖表面板數據綁定等場景無需大量代碼開發和測試,可極大節省企業研發成本并降低交付風險。 作為 Vue 的初學者,您或許已經聽過很多關于它的專業術語了,例如:單頁面應用程序、異步組件、服務器端呈現等,您可能還聽過和Vue經常一起被提到的工具和庫,如Vuex、Webp...
摘要:本文非原創,基于學院在中使用實現文件導入導出功能這篇文章在實際中測試調整。簡介在中集成套件中的,從而方便我們以優雅的富有表現力的代碼實現文件的導入和導出。 本文非原創,基于laravel 學院《在 Laravel 5 中使用 Laravel Excel 實現 Excel/CSV 文件導入導出功能》 這篇文章在實際中測試調整。 showImg(https://segmentfault.c...
摘要:單元測試會體現出以上錯誤處理程序的作用如果出現問題,錯誤處理程序就會返回。同時錯誤會展開堆棧,這對調試非常有幫助。展開堆棧處理異常的一種方式是在調用堆棧的頂部加入。確保你的錯誤處理處在相同域中,這樣會保留原始消息,堆棧和自定義錯誤對象。 JavaScript的事件驅動范式增添了豐富的語言,也是讓使用JavaScript編程變得更加多樣化。如果將瀏覽器設想為JavaScript的事件驅動...
摘要:,是逗號分隔值的英文縮寫,通常都是純文本文件。如果你導出的沒有什么高級用法的話,只是做導出數據用那么建議使用本方法要比要高效的多。二十萬數據導出大概需要到秒。 CSV,是Comma Separated Value(逗號分隔值)的英文縮寫,通常都是純文本文件。如果你導出的Excel沒有什么高級用法的話,只是做導出數據用那么建議使用本方法,要比PHPexcel要高效的多。二十萬數據導出大概...
閱讀 3428·2021-11-19 09:40
閱讀 1314·2021-10-11 11:07
閱讀 4844·2021-09-22 15:07
閱讀 2890·2021-09-02 15:15
閱讀 1964·2019-08-30 15:55
閱讀 539·2019-08-30 15:43
閱讀 883·2019-08-30 11:13
閱讀 1449·2019-08-29 15:36