Angularjs 将响应下载为excel文件
文件未在浏览器上下载。我正在准备文件并将其写入响应的输出流 Rest API有:Angularjs 将响应下载为excel文件,angularjs,spring,servlets,spring-boot,apache-poi,Angularjs,Spring,Servlets,Spring Boot,Apache Poi,文件未在浏览器上下载。我正在准备文件并将其写入响应的输出流 Rest API有: @RequestMapping(value = "/export-companies", method = {RequestMethod.GET, RequestMethod.HEAD}) @Timed public void downloadCompanies(HttpServletResponse response) throws URISyntaxException {
@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();
}
}
文件内容以不可读格式响应。但该文件不会在浏览器上下载 Angular将仅接收字符序列中的文件内容。您需要从这些字符创建一个文件,并在前端启动浏览器下载 你可以这样做-
var blob = new Blob([data],
{type: 'application/vnd.openxmlformat-officedocument.spreadsheetml.sheet;'});
saveAs(blob, fileName);
其中,
data
是您从API收到的响应。saveAs
函数是库的一部分。虽然您可以查看如何手动执行此操作,但为什么要重新发明轮子?使用XHR下载文件是有问题的。只要您只获取请求,就有更简单的方法触发浏览器下载文件
使用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);
}
}
})();
请注意,此操作超出了Angular的范围,您无法处理错误或等待文件下载。若要生成巨大的Excel文件或API速度较慢,则可能会出现问题
有关更多详细信息,请阅读问题:
更新:
我将window.location.href
替换为window.open()
,这似乎是下载文件的更好选择
如果API将抛出错误页面而不是文件,
window.location.href
将替换当前页面(从而丢失其状态)$window.open()
但是将在新选项卡中打开此错误,而不会丢失应用程序的当前状态。您可以在新选项卡中下载文件。现代浏览器会在下载完成后自动关闭它们
通过打开新窗口,您可以获得对它的引用,下载完成后,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");
}
var newWindowRef=$window.open(url、名称);
if(newWindowRef){
if(newWindowRef.document.body){//不在IE上工作
newWindowRef.document.title=“下载…”;
newWindowRef.document.body.innerHTML='您的文件正在生成…请稍候';
}
var interval=setInterval(函数(){
如果(!!newWindowRef.关闭){
//下载完成
间隔时间;
}
}, 1000);
}否则{
$log.error(“打开新窗口可能被阻止”);
}
在Chrome v52、FF v48和IE 11上测试并运行我已经完成了相同的代码,但有一个微小的更改响应;它在chrome浏览器中工作,我没有在其他浏览器中测试。请在解决您的问题时将答案标记为已接受。我使用相同的代码保存从rest api响应对象的response.build()方法返回的excel文件。虽然它保存了文件,但是当我试图打开保存的excel文件时,它显示了文件损坏的错误消息。您找到解决方案了吗?我也面临同样的问题,这对我来说很有效。不过只有一个问题。如何保留服务器发送的文件名?也就是说,我不想在
saveAs(blob,fileName)
中提供我自己的fileName
。谢谢。hi@Piotr Lewandowski请检查我的小提琴,一旦文件下载正确,但excel未在microsoft excel中正确打开,我没有得到单元格,它用白皮书显示数据help@jose您的问题是没有以适当的格式生成内容。您只将HTML保存到文件中,并使用xls扩展名命名它。它不会自动神奇地转换为excel文件格式。问另一个问题,因为描述正确的方法需要更多的空间。@jose我发现你们已经问过这个问题了。我在这里回答:
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");
}