2016-07-27 107 views
3

文件不在瀏覽器下載。我正在準備文件並將其寫入輸出響應流。作爲excel文件下載響應

REST API有:

@RequestMapping(value = "/export-companies", 
     method = {RequestMethod.GET, RequestMethod.HEAD}) 
    @Timed 
    public void downloadCompanies(HttpServletResponse response) throws URISyntaxException { 
     HSSFWorkbook workbook = new HSSFWorkbook(); 
     HSSFSheet sheet = workbook.createSheet("Sample sheet"); 

     Map<String, Object[]> data = new HashMap<String, Object[]>(); 
     data.put("1", new Object[] {"Emp No.", "Name", "Salary"}); 
     data.put("2", new Object[] {1d, "John", 1500000d}); 
     data.put("3", new Object[] {2d, "Sam", 800000d}); 
     data.put("4", new Object[] {3d, "Dean", 700000d}); 

     Set<String> keyset = data.keySet(); 
     int rownum = 0; 
     for (String key : keyset) { 
      Row row = sheet.createRow(rownum++); 
      Object [] objArr = data.get(key); 
      int cellnum = 0; 
      for (Object obj : objArr) { 
       Cell cell = row.createCell(cellnum++); 
       if(obj instanceof Date) 
        cell.setCellValue((Date)obj); 
       else if(obj instanceof Boolean) 
        cell.setCellValue((Boolean)obj); 
       else if(obj instanceof String) 
        cell.setCellValue((String)obj); 
       else if(obj instanceof Double) 
        cell.setCellValue((Double)obj); 
      } 
     } 

     try { 
      ByteArrayOutputStream outByteStream = new ByteArrayOutputStream(); 
      workbook.write(outByteStream); 
      byte [] outArray = outByteStream.toByteArray(); 
      response.setContentType("application/ms-excel"); 
      response.setContentLength(outArray.length); 
      response.setHeader("Expires:", "0"); // eliminates browser caching 
      response.setHeader("Content-Disposition", "attachment; filename=template.xls"); 
      OutputStream outStream = response.getOutputStream(); 
      outStream.write(outArray); 
      outStream.flush(); 
      workbook.close(); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

從前端(使用角JS):

(function() { 
    'use strict'; 

    angular 
     .module('MyApp') 
     .factory('CompanyExportService', CompanyExportService); 

    CompanyExportService.$inject = ['$resource']; 

    function CompanyExportService ($resource) { 
     var service = $resource('api/export-companies', {}, { 
      'get': { 
       method: 'GET', 
       isArray: false 
      } 
     }); 

     return service; 
    } 
})(); 

文件內容是否有響應非可讀的格式。但文件不在瀏覽器下載。

+0

我也做了同樣的代碼,但一個小的改動response.setContentType( 「應用/武力下載」); 它在Chrome瀏覽器中工作,我沒有在其他瀏覽器中測試 – akhilsk

+0

如果它解決了您的問題,請將其標記爲已接受。 –

回答

4

Angular將收到文件內容僅爲字符序列。您需要從這些字符創建一個文件,並在前端啓動瀏覽器下載。

你可以做到這樣的 -

var blob = new Blob([data], 
        {type: 'application/vnd.openxmlformat-officedocument.spreadsheetml.sheet;'}); 
saveAs(blob, fileName); 

其中data是您收到形成你的API響應。 saveAs函數是FileSaver.js庫的一部分。雖然你可以看看如何手動做到這一點,但爲什麼重新發明輪子?

+2

我使用相同的代碼來保存從rest api的Response對象的response.build()方法返回的excel文件。雖然它保存文件,但是當我嘗試打開保存的Excel文件時,它顯示文件損壞的錯誤消息。 –

+0

你有沒有解決這個問題?我面臨同樣的問題。 – Chiya

3

使用XHR下載文件存在問題。只要你只做GET請求,就有更簡單的方法來觸發瀏覽器下載文件。使用JavaScript本機方法window.open(url)。 它在包括IE9在內的所有瀏覽器中都能正常工作。

在下面的代碼中,我使用了$window,這是Angular的本地窗口對象的代理。

示例代碼可能是這樣的:

(function() { 
'use strict'; 

angular 
    .module('MyApp') 
    .factory('CompanyExportService', CompanyExportService); 

CompanyExportService.$inject = ['$window']; 

function CompanyExportService ($window) { 
    var exportUrl = 'api/export-companies'; 

    return { 
     download: download 
    } 

    function download() { 
     $window.open(exportUrl); 
    } 
} 
})(); 

請注意,這個動作是在對角範圍,你不能做很多有關錯誤處理或等待,直到該文件將被下載。如果您想要生成大量的Excel文件或者您的API速度很慢,可能會出現問題。

欲瞭解更多詳情,請閱讀問題:Spring - download response as a file

更新:

我把它換成window.location.hrefwindow.open()這似乎是下載文件更好的選擇。

如果您的API將拋出一個錯誤頁面而不是文件,window.location.href將取代當前頁面(從而失去其狀態)。然而,$window.open()會在新標籤頁中打開此錯誤而不會丟失應用程序的當前狀態。

+0

嗨@Piotr Lewandowski親切地檢查我的小提琴https://jsfiddle.net/x30v0bym/3/文件下載是正確的,但excel在Microsoft Excel中沒有正常打開我沒有獲取單元格它顯示數據與白皮書幫助 – jose

+0

@ jose你的問題是你不會以適當的格式生成內容。您只將HTML保存到文件中,並用* xls *擴展名來命名。它不會自動奇蹟地轉換成excel文件格式。 *提出另一個問題*,因爲它需要更多的空間來描述正確的方式。 –

+0

@ jose我發現你已經問過問題。我在這裏回答了它:https://stackoverflow.com/a/44602960/2757140 –

3

您可以在新選項卡中下載文件。下載完成後,現代瀏覽器會自動關閉它們。

通過打開新窗口,您可以參考它,下載完成後window.closed設置爲true。

不幸的是,你需要不時地檢查這個參數在時間間隔內......

var newWindowRef = $window.open(url, name); 
if (newWindowRef) { 
    if (newWindowRef.document.body) { // not working on IE 
     newWindowRef.document.title = "Downloading ..."; 
     newWindowRef.document.body.innerHTML = '<h4>Your file is generating ... please wait</h4>'; 
    } 

    var interval = setInterval(function() { 
     if (!!newWindowRef.closed) { 
      // Downloading completed 
      clearInterval(interval); 
     } 
    }, 1000); 
} else { 
    $log.error("Opening new window is probably blocked"); 
} 

測試,適用於Chrome V52,V48 FF和IE 11