spring + angular 实现导出excel
需求描述
要求批量導出數(shù)據(jù),以excel的格式。
選擇方式
前臺 + 后臺
之前在別的項目中也遇到過導出的問題,解決方式是直接在前臺導出將表格導出。
這次沒有選擇前臺導出的方式,是由于需要導出所有的數(shù)據(jù),所以考慮直接在后臺獲取所有的數(shù)據(jù),然后就直接導出,最后前臺觸發(fā)導出API。
后臺實現(xiàn)
導出使用的是POI,在上一篇文章中,我已做了基本的介紹,這里就不做介紹配置了,參照:POI實現(xiàn)將導入Excel文件
創(chuàng)建表格
首先先建立一張表,這里要建立.xlsx格式的表格,使用XSSFWorkbook:
Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("new sheet");接著創(chuàng)建表格的行和單元格:
Row row = sheet.createRow(0); row.createCell(0);然后設置表頭:
row.createCell(0).setCellValue("學號"); row.createCell(1).setCellValue("姓名"); row.createCell(2).setCellValue("手機號碼");最后獲取所有的數(shù)據(jù),對應的填寫到單元格中:
int i = 1; for (Student student : studentList) {row = sheet.createRow(i);row.createCell(0).setCellValue(student.getStudentNumber());row.createCell(1).setCellValue(student.getName());row.createCell(2).setCellValue(student.getPhoneNumber());i++; }輸出
這部分是糾結比較久的,反復試了很多次。
一開始是直接以文件輸出流的形式輸出的:
FileOutputStream output = new FileOutputStream("test.xlsx"); workbook.write(output);這樣可以正確生成文件,但是問題是,它會生成在項目的根目錄下。
而我們想要的效果是,下載在本地自己的文件夾中。
要解決這個問題,需要添加相應信息,返回給瀏覽器:
OutputStream fos = response.getOutputStream(); response.reset(); String fileName = "test"; fileName = URLEncoder.encode(fileName, "utf8"); response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); workbook.write(fos); fos.close();后臺完成代碼:
public void batchExport(HttpServletResponse response) {logger.debug("創(chuàng)建工作表");Workbook workbook = new XSSFWorkbook();Sheet sheet = workbook.createSheet("new sheet");logger.debug("獲取所有學生");List<Student> studentList = (List<Student>) studentRepository.findAll();logger.debug("建立表頭");Row row = sheet.createRow(0);row.createCell(0).setCellValue("學號");row.createCell(1).setCellValue("姓名");row.createCell(2).setCellValue("手機號碼");logger.debug("將學生信息寫入對應單元格");int i = 1;for (Student student : studentList) {row = sheet.createRow(i);row.createCell(0).setCellValue(student.getStudentNumber());row.createCell(1).setCellValue(student.getName());row.createCell(2).setCellValue(student.getPhoneNumber()); i++;}OutputStream fos;try {fos = response.getOutputStream();response.reset();String fileName = "test";fileName = URLEncoder.encode(fileName, "utf8");response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");response.setCharacterEncoding("UTF-8");response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// 設置contentType為excel格式workbook.write(fos);fos.close();} catch (Exception e) {e.printStackTrace();} }前臺實現(xiàn)
在前臺調用的時候,也經(jīng)歷了多次失敗,google了很多篇文章,各種各樣的寫法都有,自己也是試了試,前臺后臺都對照做了很多嘗試,但基本都是有問題的。這里我值給出我最后選擇配套后臺的方法。
// 后臺導出路由 const exportUrl = '/api/student/batchExport';// 創(chuàng)建a標簽,并點擊 let a = document.createElement('a'); document.body.appendChild(a); a.setAttribute('style', 'display:none'); a.setAttribute('href', exportUrl); a.click(); URL.revokeObjectURL(exportUrl);最后的實現(xiàn)還是一種比較簡單的方法,創(chuàng)建了一個a標簽,然后隱式點擊。
注意到這里我沒有使用http請求,主要是他并不能觸發(fā)瀏覽器的下載,在發(fā)起請求后,并沒有正確的生成文件,具體是什么還不清楚。后面弄明白后我會再更新這篇文章。
升級
上面的形式,在導出所有的數(shù)據(jù)的時候是沒有問題的,但是如果我想帶一些參數(shù)呢?
另外,我們的項目是建立在nginx同源的基礎上,一旦出現(xiàn)跨域問題,前臺向后臺請求,瀏覽器是不會默認攜帶Cookie的,每次請求都將會被看作是一個新的請求。
所以上面的解決辦法有所限制。
那么,還可以怎么寫呢?
file-saver
這里我將借助FileSaver來幫助我在前臺生成excel文件。
this.http.get('student/batchExport', { responseType: 'blob'}).subscribe(data => {let blob = new Blob([data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'});saveAs(blob, 'test.xlsx');});用httpClient發(fā)起get請求,聲明:響應類型為blob。
blob是一個用來存儲二進制文件的對象。然后創(chuàng)建一個blob對象,類型為excel格式。
最后,利用file-saver中的saveAs函數(shù),將blob對象生成文件名為'test.xlsx'的excel文件。
調整后臺
這里后臺大部分和前面的是一樣的,但是明眼人會發(fā)現(xiàn),前臺使用后面的方法后,下面的代碼就多余了:
String fileName = "test"; fileName = URLEncoder.encode(fileName, "utf8"); response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");是的,我們將這一部分交由前臺負責,所以后臺對應的這部分就可以刪除了,只使用response獲取輸出流就可以了:
OutputStream fos = response.getOutputStream(); workbook.write(fos); fos.close();好了,使用這種方法,我們就可以在發(fā)起http請求的時候,添加我們想要的參數(shù)了。
總結
我們在google的時候,很多時候,我們并不能一下子就找到我們想要的東西,但是并不是說這在做無用功,因為我們往往會在一些類似的文章中找到靈感。
所以,當我們沒有直接找到我們想要的結果的時候,不妨大膽的做一些嘗試,因為我們會在一次又一次失敗的嘗試中,慢慢的了解問題的原理到底是怎么回事。
相關參考:
https://my.oschina.net/u/3644...
https://blog.csdn.net/LUNG108...
總結
以上是生活随笔為你收集整理的spring + angular 实现导出excel的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea编辑springboot,如何打
- 下一篇: 剑指offer第二版-9.用两个栈实现队