2016-07-27 106 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