作为excel文件下载响应
文件不在浏览器下载。我正在准备文件并将其写入输出响应流。作为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;
}
})();
文件内容是否有响应非可读的格式。但文件不在浏览器下载。
Angular将收到文件内容仅为字符序列。您需要从这些字符创建一个文件,并在前端启动浏览器下载。
你可以做到这样的 -
var blob = new Blob([data],
{type: 'application/vnd.openxmlformat-officedocument.spreadsheetml.sheet;'});
saveAs(blob, fileName);
其中data
是您收到形成你的API响应。 saveAs
函数是FileSaver.js库的一部分。虽然你可以看看如何手动做到这一点,但为什么重新发明轮子?
我使用相同的代码来保存从rest api的Response对象的response.build()方法返回的excel文件。虽然它保存文件,但是当我尝试打开保存的Excel文件时,它显示文件损坏的错误消息。 –
你有没有解决这个问题?我面临同样的问题。 – Chiya
使用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.href
与window.open()
这似乎是下载文件更好的选择。
如果您的API将抛出一个错误页面而不是文件,window.location.href
将取代当前页面(从而失去其状态)。然而,$window.open()
会在新标签页中打开此错误而不会丢失应用程序的当前状态。
嗨@Piotr Lewandowski亲切地检查我的小提琴https://jsfiddle.net/x30v0bym/3/文件下载是正确的,但excel在Microsoft Excel中没有正常打开我没有获取单元格它显示数据与白皮书帮助 – jose
@ jose你的问题是你不会以适当的格式生成内容。您只将HTML保存到文件中,并用* xls *扩展名来命名。它不会自动奇迹地转换成excel文件格式。 *提出另一个问题*,因为它需要更多的空间来描述正确的方式。 –
@ jose我发现你已经问过问题。我在这里回答了它:https://stackoverflow.com/a/44602960/2757140 –
您可以在新选项卡中下载文件。下载完成后,现代浏览器会自动关闭它们。
通过打开新窗口,您可以参考它,下载完成后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
我也做了同样的代码,但一个小的改动response.setContentType( “应用/武力下载”); 它在Chrome浏览器中工作,我没有在其他浏览器中测试 – akhilsk
如果它解决了您的问题,请将其标记为已接受。 –