spring + angular 實現導出excel

需求描述

要求批量導出數據,以excel的格式。

選擇方式

前臺 + 後臺

之前在別的項目中也遇到過導出的問題,解決方式是直接在前臺導出將表格導出。

這次沒有選擇前臺導出的方式,是由於需要導出所有的數據,所以考慮直接在後臺獲取所有的數據,然後就直接導出,最後前臺觸發導出API。

後臺實現

導出使用的是POI,在上一篇文章中,我已做了基本的介紹,這裏就不做介紹配置了,參照:POI實現將導入Excel文件

創建表格

首先先建立一張表,這裏要建立.xlsx格式的表格,使用XSSFWorkbook

Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("new sheet");

接着創建表格的單元格

Row row = sheet.createRow(0);
row.createCell(0);

然後設置表頭

row.createCell(0).setCellValue("學號");
row.createCell(1).setCellValue("姓名");
row.createCell(2).setCellValue("手機號碼");

最後獲取所有的數據,對應的填寫到單元格中:

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("創建工作表");
    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();
    }
}

前臺實現

在前臺調用的時候,也經歷了多次失敗,google了很多篇文章,各種各樣的寫法都有,自己也是試了試,前臺後臺都對照做了很多嘗試,但基本都是有問題的。這裏我值給出我最後選擇配套後臺的方法。

// 後臺導出路由
const exportUrl = '/api/student/batchExport';

// 創建a標籤,並點擊
let a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('style', 'display:none');
a.setAttribute('href', exportUrl);
a.click();
URL.revokeObjectURL(exportUrl);

最後的實現還是一種比較簡單的方法,創建了一個a標籤,然後隱式點擊。

注意到這裏我沒有使用http請求,主要是他並不能觸發瀏覽器的下載,在發起請求後,並沒有正確的生成文件,具體是什麼還不清楚。後面弄明白後我會再更新這篇文章。

總結

我們在google的時候,很多時候,我們並不能一下子就找到我們想要的東西,但是並不是說這在做無用功,因爲我們往往會在一些類似的文章中找到靈感。

所以,當我們沒有直接找到我們想要的結果的時候,不妨大膽的做一些嘗試,因爲我們會在一次又一次失敗的嘗試中,慢慢的瞭解問題的原理到底是怎麼回事。


相關參考:
https://my.oschina.net/u/3644...
https://blog.csdn.net/LUNG108...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章