我已经在Angular JS中创建了一个应用程序,用于通过$ http post下载Excel工作簿。
在下面的代码中,我以JSON的形式传递信息,并通过角度$ http帖子将其发送到服务器REST Web服务(java)。 Web服务使用JSON中的信息并生成Excel工作簿。在$ http帖子的成功主体内的回复中,我在数据变量中获取二进制数据,但不知道如何将其转换并下载为Excel文件。
有人可以告诉我一些解决方案,将二进制转换为Excel文件并下载吗?
我的代码如下:
$http({
url: 'myweb.com/myrestService',
method: "POST",
data: json, //this is your json data string
headers: {
'Content-type': 'application/json'
}
}).success(function (data, status, headers, config) {
// Here i'm getting excel sheet binary datas in 'data'
}).error(function (data, status, headers, config) {
});
答案 0 :(得分:79)
这实际上可以通过浏览器使用blob
来完成。请注意responseType
和success
承诺中的代码。
$http({
url: 'your/webservice',
method: "POST",
data: json, //this is your json data string
headers: {
'Content-type': 'application/json'
},
responseType: 'arraybuffer'
}).success(function (data, status, headers, config) {
var blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}).error(function (data, status, headers, config) {
//upload failed
});
objectUrl
PHP中的服务器端代码我看起来像这样。我相信你可以在Java中设置类似的标题:
$file = "file.xlsx";
header('Content-disposition: attachment; filename='.$file);
header('Content-Length: ' . filesize($file));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');
echo json_encode(readfile($file));
浏览器使得以这种方式保存数据变得更加困难。一个不错的选择是使用filesaver.js。它为saveAs
提供了一个跨浏览器实现,它应该替换上面success
承诺中的一些代码。
答案 1 :(得分:24)
您就是这样做的:
$http({ url: 'your/webservice', method: 'POST', responseType: 'arraybuffer', data: json, //this is your json data string headers: { 'Content-type': 'application/json', 'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } }).success(function(data){ var blob = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); saveAs(blob, 'File_Name_With_Some_Unique_Id_Time' + '.xlsx'); }).error(function(){ //Some error log });
提示!不要混合#34;并且',坚持总是使用',在专业环境中你必须传递js验证例如jshint,同样适用于使用===而不是==,等等,但这是另一个话题:))
我会将save excel放在另一个服务中,所以你有一个干净的结构,帖子是自己的适当服务。如果你不能让我的榜样有效,我可以为你制作一个JS小提琴。然后我还需要你使用的一些json数据作为完整的例子。
快乐的编码..爱德华多
答案 2 :(得分:10)
将服务器响应下载为阵列缓冲区。使用服务器中的内容类型(应为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
)将其存储为Blob:
var httpPromise = this.$http.post(server, postData, { responseType: 'arraybuffer' });
httpPromise.then(response => this.save(new Blob([response.data],
{ type: response.headers('Content-Type') }), fileName));
将blob保存到用户的设备:
save(blob, fileName) {
if (window.navigator.msSaveOrOpenBlob) { // For IE:
navigator.msSaveBlob(blob, fileName);
} else { // For other browsers:
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
window.URL.revokeObjectURL(link.href);
}
}
答案 3 :(得分:5)
为我工作 -
$scope.downloadFile = function () {
Resource.downloadFile().then(function (response) {
var blob = new Blob([response.data], { type: "application/pdf" });
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
},
function (error) {
debugger;
});
};
从我的资源工厂调用以下内容 -
downloadFile: function () {
var downloadRequst = {
method: 'GET',
url: 'http://localhost/api/downloadFile?fileId=dfckn4niudsifdh.pdf',
headers: {
'Content-Type': "application/pdf",
'Accept': "application/pdf"
},
responseType: 'arraybuffer'
}
return $http(downloadRequst);
}
确保您的API也设置标题内容类型 -
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
答案 4 :(得分:4)
根据我的知识,没有办法从Javascript触发浏览器中的下载窗口。唯一的方法是将浏览器重定向到将文件流式传输到浏览器的URL。
如果您可以修改您的REST服务,您可以通过更改来解决它,以便POST请求不响应二进制文件,但是使用该文件的URL。这样就可以获得Javascript中的url而不是二进制数据,并且您可以将浏览器重定向到该URL,该URL应该在不离开原始页面的情况下提示下载。
答案 5 :(得分:1)
回答No 5对我有用,建议面对类似问题的开发人员。
//////////////////////////////////////////////////////////
//Server side
//////////////////////////////////////////////////////////
imports ***
public class AgentExcelBuilder extends AbstractExcelView {
protected void buildExcelDocument(Map<String, Object> model,
HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
//poi code goes here ....
response.setHeader("Cache-Control","must-revalidate");
response.setHeader("Pragma", "public");
response.setHeader("Content-Transfer-Encoding","binary");
response.setHeader("Content-disposition", "attachment; filename=test.xls");
OutputStream output = response.getOutputStream();
workbook.write(output);
System.out.println(workbook.getActiveSheetIndex());
System.out.println(workbook.getNumberOfSheets());
System.out.println(workbook.getNumberOfNames());
output.flush();
output.close();
}//method buildExcelDocument ENDS
//service.js at angular JS code
function getAgentInfoExcel(workgroup,callback){
$http({
url: CONTEXT_PATH+'/rest/getADInfoExcel',
method: "POST",
data: workgroup, //this is your json data string
headers: {
'Content-type': 'application/json'
},
responseType: 'arraybuffer'
}).success(function (data, status, headers, config) {
var blob = new Blob([data], {type: "application/vnd.ms-excel"});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}).error(function (data, status, headers, config) {
console.log('Failed to download Excel')
});
}
////////////////////////////////in .html
<div class="form-group">`enter code here`
<a href="javascript:void(0)" class="fa fa-file-excel-o"
ng-click="exportToExcel();"> Agent Export</a>
</div>
答案 6 :(得分:0)
你也可以采取另一种方法 - 你不必使用$ http,你不需要任何额外的库,它应该在任何浏览器中工作。
<登记/>
只需在页面上放置一个不可见的表单。
<form name="downloadForm" action="/MyApp/MyFiles/Download" method="post" target="_self">
<input type="hidden" name="value1" value="{{ctrl.value1}}" />
<input type="hidden" name="value2" value="{{ctrl.value2}}" />
</form>
将此代码放在角度控制器中。
ctrl.value1 = 'some value 1';
ctrl.value2 = 'some value 2';
$timeout(function () {
$window.document.forms['downloadForm'].submit();
});
此代码会将您的数据发布到/ MyApp / MyFiles / Download,您将在“下载”文件夹中收到一个文件。
它适用于Internet Explorer 10。
如果传统的HTML表单不允许您发布复杂对象,那么您有两个选择:
1。对对象进行字符串化并将其作为字符串放入其中一个表单字段中。
<input type="hidden" name="myObjJson" value="{{ctrl.myObj | json:0}}" />
2。考虑HTML JSON表单:https://www.w3.org/TR/html-json-forms/
答案 7 :(得分:0)
我创建了一项服务,为您完成此任务。
传入标准$http
对象,并添加一些额外参数。
1)A&#34;类型&#34;参数。指定您要检索的文件类型。默认为:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
2)A&#34; fileName&#34;参数。这是必需的,应包括扩展名。
示例:
httpDownloader({
method : 'POST',
url : '--- enter the url that returns a file here ---',
data : ifYouHaveDataEnterItHere,
type : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // this is the default
fileName : 'YourFileName.xlsx'
}).then(res => {}).catch(e => {});
这就是你所需要的一切。该文件将被下载到用户的设备而无需弹出窗口。
这里是git repo:https://github.com/stephengardner/ngHttpDownloader
答案 8 :(得分:-2)
我遇到了同样的问题。让我告诉你我是如何解决它并实现你们似乎都想要的一切。
要求:
在我的服务中,(我使用的是Asp.net Web API),我有一个控制器返回&#34; HttpResponseMessage&#34;。我添加了一个&#34; StreamContent&#34;到response.Content字段,将标题设置为&#34; application / octet-stream&#34;并将数据添加为附件。我甚至给它起了一个名字&#34; myAwesomeFile.xlsx&#34;
response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(memStream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "myAwesomeFile.xlsx" };
现在这就是诀窍;)
我将基本URL存储在一个文本文件中,我将其读入一个名为&#34; apiRoot&#34;的Angular Value中的变量。我这样做是通过声明然后将其设置在&#34;运行&#34;模块的功能,如下:
app.value('apiRoot', { url: '' });
app.run(function ($http, apiRoot) {
$http.get('/api.txt').success(function (data) {
apiRoot.url = data;
});
});
这样我就可以在服务器上的文本文件中设置URL,而不用担心&#34;将其吹走&#34;在上传。 (出于安全原因,您可以随后更改它 - 但这会让开发失败;)
现在神奇了:
我所做的就是创建一个链接,其中包含一个直接命中我的服务端点的网址,并定位了一个&#34; _blank&#34;。
<a ng-href="{{vm.getFileHref(FileId)}}" target="_blank" class="btn btn-default"> Excel File</a>
秘密酱是设置href的功能。你准备好了吗?
vm.getFileHref = function (Id) {
return apiRoot.url + "/datafiles/excel/" + Id;
}
是的,那就是它。 ;)
即使在您正在迭代许多要下载文件的记录的情况下,您只需将Id提供给该函数,该函数会生成提供该文件的服务端点的URL。
希望这有帮助!