web-dev-qa-db-ja.com

AngularJS $ http-post-バイナリをExcelファイルに変換してダウンロード

$ httpの投稿からExcelブックをダウンロードするためのアプリケーションをAngular JSで作成しました。

次のコードでは、情報をJSONの形式で渡し、REST $ httpポストを介してサーバーangular Webサービス(Java)に送信します。 WebサービスはJSONの情報を使用して、Excelブックを作成します。 $ http投稿の成功本文内の応答で、そのdata変数内にバイナリデータを取得していますが、それを変換して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) {

    });
52
Alex Man

IE8/9のために使用できないことに気づいたが、とにかく送信をプッシュする...多分誰かがそれを便利だと思う

これは、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
});

それにはいくつかの問題があります:

  1. IE 8および9 をサポートしていません:
  2. ポップアップウィンドウが開き、ユーザーがブロックした可能性のあるobjectUrlが開きます
  3. 奇妙なファイル名を生成します

うまくいきました!

blob 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));

編集20.04.2016

ブラウザは、この方法でデータを保存することを難しくしています。良いオプションの1つは、 filesaver.js を使用することです。 saveAsのクロスブラウザー実装を提供し、上記のsuccess promiseのコードの一部を置き換える必要があります。

79
Jorg

これがあなたのやり方です:

  1. IE8/IE9を忘れてください、それは努力の価値がなく、お金を返済しません。
  2. 正しいHTTPヘッダーを使用する必要があります。「application/vnd.openxmlformats-officedocument.spreadsheetml.sheet」にAcceptを使用し、responseTypeを「arraybuffer」(ArrayBufferで小文字に設定)に配置する必要があります。
  3. HTML5のsaveAsは、実際のデータを希望の形式で保存するために使用されます。この場合、タイプを追加しなくても機能することに注意してください。
$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
});

ヒント! 「と」を混在させないでください。常に使用するように固執してください。プロの環境では、たとえばjshintなどのjs検証に合格する必要があります。 :)

保存Excelを別のサービスに配置するので、クリーンな構造になり、投稿は独自の適切なサービスになります。私のサンプルが機能しない場合は、JSフィドルを作成できます。次に、完全な例に使用するJSONデータも必要です。

ハッピーコーディング..エドゥアルド

24

サーバーの応答を配列バッファーとしてダウンロードします。サーバーのコンテンツタイプ(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);
    }
}
10
Edward Brey

私のために働いた-

$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");
5

Javascriptからブラウザのダウンロードウィンドウをトリガーする方法はありません(私の知る限り)。それを行う唯一の方法は、ファイルをブラウザにストリーミングするURLにブラウザをリダイレクトすることです。

RESTサービスを変更できる場合は、POSTリクエストがバイナリファイルではなく、そのファイルのURLで応答するように変更することで解決できる場合があります。これにより、バイナリデータの代わりにJavascriptでURLが取得され、ブラウザをそのURLにリダイレクトできます。これにより、元のページから移動せずにダウンロードが要求されます。

4
Anders Ekdahl

回答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>
1
Vj Singh

別のアプローチを採用することもできます。$ 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>

そして、このコードをangularコントローラーに配置します。

ctrl.value1 = 'some value 1';  
ctrl.value2 = 'some value 2';  
$timeout(function () {
    $window.document.forms['downloadForm'].submit();
});

このコードはデータを/ MyApp/MyFiles/Downloadに投稿し、ダウンロードフォルダーにファイルを受け取ります。
Internet Explorer 10で動作します。

従来のHTMLフォームでは複雑なオブジェクトを投稿できない場合、2つのオプションがあります。

1。オブジェクトを文字列化し、文字列としてフォームフィールドのいずれかに配置します。

<input type="hidden" name="myObjJson" value="{{ctrl.myObj | json:0}}" />


2。 HTML JSONフォームを検討してください: https://www.w3.org/TR/html-json-forms/

0
Evgeny Nikitin

これを行うサービスを作成しました。

標準の$httpオブジェクトを渡し、いくつかの追加パラメーターを追加します。

1)「タイプ」パラメーター。取得するファイルのタイプを指定します。デフォルト:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
2)「fileName」パラメーター。これは必須であり、拡張子を含める必要があります。

例:

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リポジトリは次のとおりです。 https://github.com/stephengardner/ngHttpDownloader

0
Augie Gardner