35

我正在使用 AngularJS 和 Spring 编写应用程序。我想向服务器发送请求并将控制器返回的响应作为文件下载。在控制器中,我有 csv 文件的内容(作为字符串),即1;2;3;4(1 行,4 列)。将此响应下载为文件的最简单方法是什么?

下面,我发布了我的简化代码。在 Spring 控制器中:

@RequestMapping(value = "/csv", method = GET)
@ResponseBody
public String getCsvFile() {
    return getCsvContent();
}

在 javascript (AngularJS) 中

return $http({method: 'GET', url: 'csv/'});

我也试图写入响应流(如下),设置标题,但在客户端我总是将此内容作为字符串获取 - 而不是作为要下载的文件。

@RequestMapping(value = "/csv", method = GET)
@ResponseBody
public void getCsvFile(HttpServletResponse response) {
    response.setContentType("application/csv");
    response.setHeader("Content-Disposition", "attachment; filename=file.csv");
    response.setContentLength(getCsvContent().getBytes().length);
    ServletOutputStream out = response.getOutputStream();
    out.write(getCsvContent());
    out.flush();
    out.close();
}

有谁知道如何正确编写控制器的方法以便在客户端将响应下载为文件?

4

7 回答 7

26

您不能通过 XHR 请求下载文件(这是 Angular 发出请求的方式)。请参阅为什么无法使用 ajax 请求下载文件?您要么需要通过 URL 访问 URL,$window.open要么执行此处显示的 iframe 技巧:JavaScript/jQuery to download file via POST with JSON data

于 2013-06-18T20:51:48.640 回答
8

我自己已经为此苦苦挣扎,试图让它在服务器上工作。不能。反而...

  1. 为了澄清@dnc253 的答案,$window.open(URL)是一种让 Angular 应用程序在另一个窗口中打开给定 URL 的方法。(它实际上只是通用的可测试角度代理window.open()。)这是一个很好的解决方案,可以保留您的历史记录,并下载文件并可能在新的浏览器窗口中呈现它(如果支持)。但它经常遇到弹出窗口阻止程序,这对可靠性来说是一个巨大的问题。用户通常根本不了解他们发生了什么。因此,如果您不介意立即使用当前窗口下载文件,您可以简单地使用同样有效的通用 javascript 方法:location.href = "uriString",这对我来说就像一个魅力。Angular 甚至没有意识到发生了什么。一旦我的 POST/PUT 操作完成,我就会在 Promise 处理程序中调用它。如果需要,让 POST/PUT 返回要调用的 URL(如果您还不能推断它)。您将获得与用户响应 PUT/POST 下载时相同的行为。例如:

    $http.post(url, payload).then(function(returnData){
        var uriString = parseReturn(returnData);
        location.href="uriString"
    })
    
  2. 实际上,您可以直接从 XHR 请求中下载某些内容,但它需要对 HTML5 文件 API 的完全支持,并且通常比它的价值更麻烦,除非您需要在文件提供给用户之前对其执行本地转换. (遗憾的是,我没有时间提供这方面的详细信息,但还有其他关于使用它的 SO 帖子。)

于 2014-01-06T02:27:35.560 回答
3

可以使用 XHR 请求下载文件。您可以使用 angular $http 加载文件,然后使用 HTML5 的 Blob 功能让浏览器保存它。有一个库可以帮助您保存:FileSaver.js

于 2015-07-17T14:04:05.200 回答
2

以防万一你们需要它,这里有几个链接可以帮助你:

  1. 从 Angular js 中的 web api 下载 csv 文件
  2. 无需服务器交互即可将 javascript 数据导出到 CSV 文件

干杯

于 2014-02-19T03:39:54.593 回答
1

我在下面写了评论以了解代码示例。有些人如果使用,他们可以跟随它,因为我相应地命名了文件。

  1. 如果服务器在响应中发送 blob,那么我们的客户端应该能够生成它。

  2. 因为我的目的是通过使用这些来解决的。我可以下载文件,因为我对所有文件都使用了 type: 'application/*' 。

  3. 创建的“downloadLink”变量只是用于响应的技术,因此它会像点击链接一样填充,然后响应来,然后触发它的href。

controller.js
//this function is in controller, which will be trigered on download button hit.	

  $scope.downloadSampleFile = function() {
//create sample hidden link in document, to accept Blob returned in the response from back end
    
		var downloadLink = document.createElement("a");

		document.body.appendChild(downloadLink);
		downloadLink.style = "display: none";

//This service is written Below how does it work, by aceepting necessary params
		downloadFile.downloadfile(data).then(function (result) {

			var fName = result.filename;
			var file = new Blob([result.data], {type: 'application/*'});
			var fileURL = (window.URL || window.webkitURL).createObjectURL(file);

          
//Blob, client side object created to with holding browser specific download popup, on the URL created with the help of window obj.
          
			downloadLink.href = fileURL;
			downloadLink.download = fName;
			downloadLink.click();
		});
	};




services.js

.factory('downloadFile', ["$http", function ($http) {
	return {
		downloadfile : function () {
			return $http.get(//here server endpoint to which you want to hit the request
              , {
				responseType: 'arraybuffer',
				params: {
					//Required params
				},
			}).then(function (response, status, headers, config) {
				return response;
			});
		},
	};
}])

于 2015-12-07T11:16:57.553 回答
0

它对我有用:

  • 弹簧控制器:DownloadController.java

    package com.mycompany.myapp.controller;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.io.IOUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.mycompany.myapp.exception.TechnicalException;
    
    
    @RestController
    public class DownloadController {
    
        private final Logger log = LoggerFactory.getLogger(DownloadController.class);
    
        @RequestMapping(value = "/download", method = RequestMethod.GET)
        public void download(@RequestParam ("name") String name, final HttpServletRequest request, final HttpServletResponse response) throws TechnicalException {
            log.trace("name : {}", name);
    
            File file = new File ("src/main/resources/" + name);
            log.trace("Write response...");
            try (InputStream fileInputStream = new FileInputStream(file);
                    OutputStream output = response.getOutputStream();) {
    
                response.reset();
    
                response.setContentType("application/octet-stream");
                response.setContentLength((int) (file.length()));
    
                response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
    
                IOUtils.copyLarge(fileInputStream, output);
                output.flush();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
    
        }
    
    }
    
  • AngularJs 服务: download.service.js

    (function() {
        'use strict';
    
        var downloadModule = angular.module('components.donwload', []);
    
        downloadModule.factory('downloadService', ['$q', '$timeout', '$window',
            function($q, $timeout, $window) {
                return {
                    download: function(name) {
    
                        var defer = $q.defer();
    
                        $timeout(function() {
                                $window.location = 'download?name=' + name;
    
                            }, 1000)
                            .then(function() {
                                defer.resolve('success');
                            }, function() {
                                defer.reject('error');
                            });
                        return defer.promise;
                    }
                };
            }
        ]);
    })();
    
  • AngularJs 配置:app.js

    (function() {
        'use strict';
    
        var myApp = angular.module('myApp', ['components.donwload']);
       /* myApp.config([function () {
    
        }]);
        myApp.run([function () {
    
        }]);*/
    
    
    })();
    
  • AngularJs 控制器:download.controller.js

    (function() {
        'use strict';
    
        angular.module('myApp')
            .controller('DownloadSampleCtrl', ['downloadService', function(downloadService) {
                this.download = function(fileName) {
                    downloadService.download(fileName)
                        .then(function(success) {
                            console.log('success : ' + success);
                        }, function(error) {
                            console.log('error : ' + error);
                        });
                };
            }]);
    })();
    
  • index.html

    <!DOCTYPE html>
    <html ng-app="myApp">
    
    <head>
        <title>My App</title>
        <link rel="stylesheet" href="bower_components/normalize.css/normalize.css" />
        <link rel="stylesheet" href="assets/styles/main.css" />
        <link rel="icon" href="favicon.ico">
    </head>
    
    <body>
        <div ng-controller="DownloadSampleCtrl as ctrl">
            <button ng-click="ctrl.download('fileName.txt')">Download</button>
        </div>
    
        <script src="bower_components/angular/angular.min.js"></script>
    
        <!-- App config -->
        <script src="scripts/app/app.js"></script>
        <!-- Download Feature -->
        <script src="scripts/app/download/download.controller.js"></script>
        <!-- Components -->
        <script src="scripts/components/download/download.service.js"></script>
    </body>
    
    </html>
    
于 2015-06-27T13:48:46.447 回答
0

//JAVA部分

@RequestMapping(value = "/report-excel", method = RequestMethod.GET)
    public ResponseEntity<byte[]> getReportExcel(@RequestParam("bookingStatusType") String bookingStatusType,
            @RequestParam("endDate") String endDate, @RequestParam("product") String product, @RequestParam("startDate") String startDate)throws IOException, ParseException {

//Generate Excel from DTO using any logic after that do the following
byte[] body = wb.getBytes();
HttpHeaders header = new HttpHeaders();
        header.setContentType(new MediaType("application", "xlsx"));
        header.set("Content-Disposition", "inline; filename=" + fileName);
        header.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        header.setContentLength(body.length);

 return new ResponseEntity<byte[]>(body, header, HttpStatus.OK);
}



//HTML PART
<html>
<head>
<title>Test</title>
<meta http-equiv="content-type" content="application/x-www-form-urlencoded; charset=UTF-8">
</head>
<body>
  <form name="downloadXLS" method="get" action="http://localhost:8080/rest/report-excel" enctype="multipart/form-data">
    <input type="text" name="bookingStatusType" value="SALES"></input>
    <input type="text" name="endDate" value="abcd"></input>
    <input type="text" name="product" value="FLIGHT"></input>
    <input type="text" name="startDate" value="abcd"></input>
    <input onclick="document.downloadXLS.submit()" value="Submit"></input>
  </form>
</body>
</html>
于 2015-12-03T10:23:31.110 回答