web-dev-qa-db-fra.com

AngularJS $ http-post - convertit un fichier binaire en fichier Excel et télécharge

J'ai créé une application dans Angular JS pour le téléchargement d'un classeur Excel via $ http post.

Dans le code ci-dessous, je passe les informations sous la forme de JSON et les envoie au serveur REST service Web (Java) via un angular $ http post. Le service Web utilise les informations du JSON et génère un classeur Excel. Dans la réponse contenue dans le corps de succès de $ http post, je reçois des données binaires dans cette variable data, mais sais pas comment le convertir et le télécharger en fichier Excel.

Quelqu'un peut-il me dire s'il vous plaît une solution pour convertir le fichier binaire en fichier Excel et le télécharger?

Mon code est comme donné ci-dessous:

$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

Je viens juste de remarquer que vous ne pouvez pas l'utiliser à cause d'IE8/9, mais je vais quand même envoyer en soumission ... peut-être que quelqu'un le trouvera utile

Cela peut être fait via le navigateur, en utilisant blob. Notez le responseType et le code dans la promesse 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
});

Il y a cependant quelques problèmes avec:

  1. Il ne supporte pas IE 8 et 9 :
  2. Il ouvre une fenêtre pop-up pour ouvrir le objectUrl que les gens auraient pu bloquer
  3. Génère des noms de fichiers étranges

Cela a fonctionné!

blob Le code côté serveur dans PHP). J'ai testé ceci avec un aspect similaire à celui-ci. Je suis sûr que vous pouvez définir des en-têtes similaires en 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));

Modifier le 20.04.2016

Les navigateurs rendent plus difficile la sauvegarde des données de cette façon. Une bonne option consiste à utiliser filesaver.js . Il fournit une implémentation multi-navigateurs pour saveAs, et il devrait remplacer une partie du code de la promesse success ci-dessus.

79
Jorg

Voici comment vous le faites:

  1. Oubliez IE8/IE9, cela ne vaut pas la peine et ne rembourse pas l'argent.
  2. Vous devez utiliser le bon en-tête HTTP, utilisez Accepter pour 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' et vous devez également mettre responseType sur 'arraybuffer' (ArrayBuffer mais défini avec des minuscules).
  3. HTML5 saveAs est utilisé pour enregistrer les données réelles au format souhaité. Notez que cela fonctionnera toujours sans ajouter de type dans ce cas.
$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
});

Pointe! Ne mélangez pas "et", tenez-vous-en à toujours utiliser ", dans un environnement professionnel, vous devrez passer la validation js, par exemple, jshint. Même chose pour utiliser === et non ==, etc., mais c'est un autre sujet :)

Je mettrais la sauvegarde Excel dans un autre service, de sorte que vous avez une structure propre et que le message est dans un service approprié. Je peux faire un violon JS pour vous, si mon exemple ne fonctionne pas. Ensuite, j'aurais aussi besoin de quelques données JSON de votre part que vous utiliseriez comme exemple complet.

Joyeux codage .. Eduardo

24
Eduardo in Norway

Téléchargez la réponse du serveur sous forme de tampon de tableau. Stockez-le en tant que blob en utilisant le type de contenu du serveur (qui devrait être application/vnd.openxmlformats-officedocument.spreadsheetml.sheet):

var httpPromise = this.$http.post(server, postData, { responseType: 'arraybuffer' });
httpPromise.then(response => this.save(new Blob([response.data],
    { type: response.headers('Content-Type') }), fileName));

Enregistrez le blob sur le périphérique de l'utilisateur:

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

A travaillé pour moi -

$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;
        });
    };

Qui appelle les suivants de mon usine de ressources

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

Assurez-vous que votre API définit également le type de contenu de l'en-tête -

        response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
5
Jonathan Forster

À ma connaissance, il n’existe aucun moyen de déclencher la fenêtre de téléchargement de votre navigateur à partir de Javascript. La seule façon de le faire est de rediriger le navigateur vers une URL qui diffuse le fichier dans le navigateur.

Si vous pouvez modifier votre service REST, vous pourrez peut-être le résoudre en modifiant la demande POST ne répond pas avec le fichier binaire, mais avec une URL vers ce fichier. Vous obtiendrez l’URL en Javascript au lieu des données binaires, et vous pourrez rediriger le navigateur vers cette URL, ce qui devrait provoquer le téléchargement sans quitter la page d’origine.

4
Anders Ekdahl

Réponse n ° 5 a fonctionné pour moi, suggestion au développeur qui fait face à un problème similaire.

//////////////////////////////////////////////////////////
//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

Vous pouvez également adopter une approche alternative: vous n'avez pas besoin d'utiliser $ http, vous n'avez pas besoin de bibliothèques supplémentaires et cela devrait fonctionner dans n'importe quel navigateur.

Placez simplement un formulaire invisible sur votre page.

<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>

Et placez ce code dans votre angular contrôleur.

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

Ce code publiera vos données sur/MyApp/MyFiles/Download et vous recevrez un fichier dans votre dossier Téléchargements.
Cela fonctionne avec Internet Explorer 10.

Si un formulaire HTML conventionnel ne vous permet pas de publier votre objet complexe, vous avez deux options:

1. Stringify votre objet et le mettre dans l'un des champs de formulaire sous forme de chaîne.

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


2. Considérons les formulaires HTML JSON: https://www.w3.org/TR/html-json-forms/

0
Evgeny Nikitin

J'ai créé un service qui le fera pour vous.

Passer dans un standard $http objet, et ajouter des paramètres supplémentaires.

1) Un paramètre "type". Spécifier le type de fichier que vous récupérez. La valeur par défaut est: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
2) Un paramètre "fileName". Cela est nécessaire et devrait inclure l'extension.

Exemple:

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 => {});

C'est tout ce dont vous avez besoin. Le fichier sera téléchargé sur le périphérique de l'utilisateur sans fenêtre contextuelle.

Voici le dépôt Git: https://github.com/stephengardner/ngHttpDownloader

0
Augie Gardner