使用 ANGULARJS 从 Jersey rest api 调用中下载/保存文件。文件附加响应为“Content-Disposition”

Posted

技术标签:

【中文标题】使用 ANGULARJS 从 Jersey rest api 调用中下载/保存文件。文件附加响应为“Content-Disposition”【英文标题】:File download/save from a Jersey rest api call using ANGULARJS . file is attached with response as "Content-Disposition" 【发布时间】:2016-01-19 14:11:54 【问题描述】:

我是 Angular 的新手。我有 java rest api,它返回 CSV 文件作为附件作为响应 | “内容处置”,“附件;文件名=”|内容类型 :application/octet-stream

现在,当我使用 $http 从 AngularJS 调用这个 api 时,我得到 response.data =""(空白)

我正在使用基本授权来确保安全,因此我必须在调用 API 时传递标头,因此无法使用链接单击或从 CSV 下载打开新窗口。

测试我何时删除授权并在浏览器中点击 url,然后下载 CSV 文件。所以在服务器端没有问题。

我需要 angularjs 方面的帮助才能从 web api 响应中下载 CSV 文件作为附件。

这是我的 Java API 代码

public class ServiceAPI 

@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFileAsCSVFile()

byte[] file=null;
    try 
        ArrayList<> List=new ArrayList<>();// data retrieved from DB 

        if(null != List)
             file=convertJsonToCSV(new Gson().toJson(List));

        

     catch (ParseException e) 


        e.printStackTrace();
     catch (IOException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    


    return            Response.ok(getBytes(file),MediaType.APPLICATION_OCTET_STREAM).header("Content-Disposition", "attachment; filename=" + "FileName.csv").build();
 
 

和 Angular 代码:

app.controller('review', ['$scope', '$http',  function ($scope, $http)



$scope.fromDate = new Date();
$scope.toDate = new Date();


$scope.minDate = new Date(
    $scope.fromDate.getFullYear(),
    $scope.fromDate.getMonth() - 2,
    $scope.fromDate.getDate(),

    $scope.toDate.getFullYear(),
    $scope.toDate.getMonth() - 2,
    $scope.toDate.getDate()
);

$scope.maxDate = new Date(
    $scope.fromDate.getFullYear(),
    $scope.fromDate.getMonth() - 2,
    $scope.fromDate.getDate(),

    $scope.toDate.getFullYear(),
    $scope.toDate.getMonth() - 2,
    $scope.toDate.getDate()
);

$scope.reviews = json;


function openSaveAsDialog(filename, content, mediaType) 
    var blob = new Blob([content], type: mediaType);
    saveAs(blob, filename);


function callApi(url) 

   // var dat=apiFactory.getServiceData(url);
   // console.log(dat);
   // apiFactory.getServiceData(url);

    var responseType='arraybuffer';
    var expectedMediaType='application/octet-stream';
    $http.get(url, 

        headers: 

            accept: expectedMediaType
        ,
        responseType:responseType,
        cache: true,
        transformResponse: function (data) 
            var pdf;
            if (data) 
                pdf = new Blob([data], 
                    type: expectedMediaType
                );
            
            return 
                response: pdf
            ;
        
    ).then(function (data,status,headers) 
        var filename='Preview.csv',
            octetStreamMime = "application/octet-stream",
            contentType;

        headers = data.headers();
        contentType = headers["content-type"] || octetStreamMime;


     //   openSaveAsDialog(filename, response.data, expectedMediaType);
        if (navigator.msSaveBlob) 
            var blob = new Blob([data],  type: contentType );
            navigator.msSaveBlob(blob, filename);
         else 
            var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;

            if (urlCreator) 
                // Try to use a download link
                var link = document.createElement("a");

                if ("download" in link) 
                    // Prepare a blob URL
                    var blob = new Blob([data.data],  type: contentType );
                    var url = urlCreator.createObjectURL(blob);

                    link.setAttribute("href", url);
                    link.setAttribute("download", filename);

                    // Simulate clicking the download link
                    var event = document.createEvent('MouseEvents');
                    event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
                    link.dispatchEvent(event);
                 else 
                    // Prepare a blob URL
                    // Use application/octet-stream when using window.location to force download
                    var blob = new Blob([data],  type: octetStreamMime );
                    var url = urlCreator.createObjectURL(blob);
                    $window.location = url;
                
            
        
    );

;
    $scope.submit = function (fromDate, toDate) 


       $scope.url = API_url;


        var resp =callApi(($scope.url).split(" ").join("%20"));

        console.log(resp);
    ;
,
]);

【问题讨论】:

【参考方案1】:

我有一个使用 spring MVC 而不是 JAX-RS (Jersey) 的示例

HTML:

<button ng-click="downloadPdf()" class="btn btn-primary">download PDF</button>

Angularjs 控制器:

$scope.downloadCsv = function () 
    console.log("downloadCsv");
    var fileName = "test.csv";
    var a = document.createElement("a");
    document.body.appendChild(a);
    XxxxxxServiceCSV.downloadCsv().then(function (result) 
        console.log("downloadCsv callback");
        var file = new Blob([result.data], type: 'application/csv');
        var fileURL = URL.createObjectURL(file);
        a.href = fileURL;
        a.download = fileName;
        a.click();
    );
;

Angularjs 服务:

angular.module('xxxxxxxxApp')
    .factory('XxxxxxServiceCSV', function ($http) 
        return 
            downloadCsv: function () 
            return $http.get('api/downloadCSV',  responseType: 'arraybuffer' ).then(function (response) 
                return response;
            );
        
    ;
);

Java 代码 JAX-RS(spring MVC):

@RequestMapping(value = "/downloadCSV", method = RequestMethod.GET, produces = "application/csv")
public void demo(HttpServletResponse response) throws IOException 
    List<String> names = new ArrayList<String>();
    names.add("First Name");
    names.add("Second Name");
    names.add("Third Name");
    names.add("Fourth Name");
    BufferedWriter writer = new BufferedWriter(response.getWriter());
    try 
        response.setHeader("Content-Disposition", "attachment; filename=\"test.csv\"");
        for (String name : names) 
            writer.write(name);
            writer.write(",");
        
        writer.newLine();
     catch (IOException ex) 
     finally 
        writer.flush();
        writer.close();
    

【讨论】:

使用 JAX-RS(Jersey):@Produces(MediaType.TEXT_PLAIN) 或 @Produces("text/csv") 谢谢哥们...它就像魅力一样...节省了我的时间:) 可以在 JAX-RS(Jersey) 中使用@POST 方法吗

以上是关于使用 ANGULARJS 从 Jersey rest api 调用中下载/保存文件。文件附加响应为“Content-Disposition”的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Security、Jersey 和 AngularJS 验证表单

AngularJS + Jersey RESTful 后端:身份验证和授权

AngularJS $http、CORS 和 Jersey 的基本身份验证

前端Angularjs +后端Jersey REST Services +需要设置开发环境

AngularJS 和位于不同域的 Jersey Webservice 之间的通信。无法访问正确的会话

Angularjs - TypeError:路径必须是绝对路径或指定根到 res.sendFile