IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

Télécharger un .docx depuis le serveur vers le client


Sujet :

Entrée/Sortie Java

  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2012
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2012
    Messages : 79
    Par défaut Télécharger un .docx depuis le serveur vers le client
    Bonjour à tous !

    J'espère me trouver dans la bonne section après avoir pas mal hésité, si jamais ce n'est pas le cas, je m'en excuse et peut-être qu'un admin se chargera de déplacer le topic

    Je développe actuellement une application Java qui utilise le framework jhipster.
    J'utilise aussi docx4j pour créer le document, et je souhaite télécharger ce document depuis mon serveur vers mon client.
    Quand j'essaie d'ouvrir le fichier word téléchargé, j'ai un message d'erreur en me disant qu'il est corrompu...

    Côté serveur

    Je génère mon fichier et le place dans un byte[].

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    WordprocessingMLPackage p = null;
    ...
    File f = new File(filePath);
    p.save(f);
    byte[] stream = Files.readAllBytes(f.toPath());
    J'ai essayé de l'envoyer vers le client dans différents formats:

    • byte[]
    • byte[] encoded Base64
    • String
    • String encoded Base64



    Voici à quoi ressemble ma méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // send back as String encoded in Base64
    public ResponseEntity<FileDTO> getFile(@PathVariable Long id) throws URISyntaxException, IOException {
        FileDTO result = fillRepository.findOne(id);
        byte[] stream = FileUtil.getFile(id) // retrieve file as byte[]
        byte[] encoded = Base64.encodeBase64(stream);
        String encodedString = new String(encoded, "UTF-8");
        result.setFile(encodedString);
        return ResponseUtil.wrapOrNotFound(Optional.ofNullable(result));
    }
    Côté client

    Je récupère mon fichier en tant que byte[] ou String et je le mets dans un blob pour qu'il soit téléchargé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    FileService.get({id: id}, function(result) {
        var res = result.file;
        // var res = Base64.decode(result.file);
        vm.blob = new Blob([res], {type: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
        vm.url = (window.URL || window.webkitURL).createObjectURL(vm.blob);
    });
    Et mon service est déclaré comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    (function() {
        'use strict';
        angular
            .module('deliverymanagerApp')
            .factory('BillGenerate', BillGenerate);
     
        BillGenerate.$inject = ['$resource', 'DateUtils'];
     
        function BillGenerate ($resource, DateUtils) {
            var resourceUrl =  'api/bill/:id/generate';
     
            return $resource(resourceUrl, {}, {
                'get': {
                    method: 'GET',
                    responseType:'arraybuffer'
                },
                'update': {
                    method: 'PUT',
                    transformRequest: function (data) {
                        data.startDate = DateUtils.convertLocalDateToServer(data.startDate);
                        data.endDate = DateUtils.convertLocalDateToServer(data.endDate);
                        return angular.toJson(data);
                    }
                }
            });
        }
    })();
    Quand je le télécharge, voici le message qui apparaît :

    "Désolé... Nous ne pouvons pas ouvrir *fichier*.docx, car nous avons découvert un problème avec son contenu. Nous ne pouvons pas ouvrir le fichier, car celui-ci est endommagé."
    Mais quand je le compare avec mon original en les ouvrant avec notepad++, je vois que le contenu binaire n'est pas exactement le même, comme s'il y avait des problèmes d'encodage/décodage...
    Leur taille est différente aussi, le fichier original fait 13Ko et le téléchargé 18Ko.

    Ca fait déjà plusieurs jours que je suis sur cette tâche mais sans trouver de solution. Donc toute l'aide que vous êtes susceptibles de m'apporter est la bienvenue

    Merci !

    infos: Eclipse, Spring, java, jhipster, angularjs.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    Citation Envoyé par CaNiBaLe Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        byte[] encoded = Base64.encodeBase64(stream);
        String encodedString = new String(encoded, "UTF-8");
        result.setFile(encodedString);
    }
    Pourquoi ne pas encoder directement en String :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        String encodedString = Base64.encodeBase64String(stream);
        result.setFile(encodedString);
    }
    ou avec la classe du JDK
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        String encodedString = Base64.getEncoder().encodeToString(stream);
        result.setFile(encodedString);
    }

    Avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String encodedString = new String(encoded, "UTF-8");
    tu supposes que le résultat de l'encodage en base 64 (non chunked) sous forme binaire est compatible UTF-8 ! Ce qui n'est probablement pas le cas (c'est du base64, il y a possible des codes en commun qui n'ont pas du tout le même sens et qui vont se perdre dans la conversion.
    Pour la partie client, je ne sais pas, je ne connais pas cet aspect.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    moi je demande surtout, pourquoi diable encoder le fichier et ne pas le retourner tel quel? T'a vraiment besoin de wrapper ça dans un JSON? Ca fait plein de chipotage, ça bouffe de la mémoire à crever et ça rends les choses tordues coté client.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // send back file content
    public void getFile(@PathVariable Long id, HttpServletResponse response) throws .... {
        FileDTO result = fillRepository.findOne(id);
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        InputStream stream = FileUtil.getFileStream(id) // retrieve file as InputStream
        IOUtils.copyStream(stream,response.getOutputStream()); //commons-io a un truc du genre pour copier entre stream, tu peux aussi le coder à la main
    }

  4. #4
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2012
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2012
    Messages : 79
    Par défaut
    Merci pour vos réponses.
    Je suis parti sur la solution de tchize_. Voilà les modifications que j'ai apporté à mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
        public void getFile(@PathVariable Long id, HttpServletResponse response) throws URISyntaxException, IOException {
            FileInputStream stream = fileService.getFile(id);
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            IOUtils.copy(stream,response.getOutputStream());
            stream.close();
        }
    Côté client :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    FileService.get({id: id}, function(res) {
        var data = [];
        for(var i = 0; res[i] !== undefined; i++) {
            data[i] = res[i];
        }
        vm.blob = new Blob([res], {type: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
        vm.url = (window.URL || window.webkitURL).createObjectURL(vm.blob);
    });
    Hors, lorsque je télécharge le fichier j'ai toujours des problèmes d'encodage.
    Voici le début des 2 fichiers (en image pour bien voir le problème d'encodage).
    Original :
    Nom : original.png
Affichages : 884
Taille : 2,6 Ko
    Fichier reçu :
    Nom : reception.png
Affichages : 873
Taille : 2,6 Ko

    Pouvez-vous m'aider à contourner ce problème d'encodage ?

    Merci d'avance.

  5. #5
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    je sais pas ce que c'est ce vm.blob là, mais tu ne devrais pas avoir à traiter la réponse en javascript. Pointe simplement le browser vers l'adresse du document et laisse le faire son boulot. Ton javascript devrait se résumer à un truc du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    window.location="http://serveur/path/to/api/1234567"
    C'est du binaire. Il est vainc d'essayer de traiter ça comme une réponse json. Et il n'y a pas de question d'encodage avec un flux binaire. Si tu parle d'encodage, c'est que t'es occupé de faire quelque chose que tu ne devrais pas faire. De plus ce n'est pas une bonne pratique de récupérer un document binaire en mémoire pour essayer de le faire ouvrir après par le browser. C'est assez compliqué à faire, tu va devoir chipoter avec le local sotrage, prier pour qu'il soit assez gros, y mettre le document, pointer le browser vers ce document. Alors que tu aurais pu pointer le borser dès le départ vers l'url en question.

  6. #6
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2012
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2012
    Messages : 79
    Par défaut
    J'ai réussi à résoudre mon problème.
    Il restait un problème côté back :
    J'avais l'annotation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @RequestMapping("/api")
    dans mon controleur.
    Cette annotation étant là à la génération du fichier par Jhipster.
    J'ai donc extrait ma méthode du controlleur et créé un nouveau sans l'annotation.
    Au final ça donne :
    Rest Controller :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    @RestController
    public class FileGenerationResource {
        ...
        @GetMapping("/file/{id}")
        @Timed
        public void getFile(@PathVariable Long id, HttpServletResponse response) throws URISyntaxException, IOException {
            FileInputStream stream = fileService.getFile(id);
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setHeader("Content-disposition", "attachment; filename=test.docx");
            IOUtils.copy(stream,response.getOutputStream());
            stream.close();
        }
    }
    Angular Contrioller :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    (function() {
        'use strict';
     
        angular
            .module('myApp')
            .controller('MyController', MyController);
     
        MyController.$inject = ['$timeout', '$scope', '$stateParams', '$uibModalInstance'];
     
        function MyController ($timeout, $scope, $stateParams, $uibModalInstance) {
            var vm = this;
            vm.clear = clear;
            vm.dwl = dwl;
     
            function dwl (id) {
            	window.location = "http://localhost:8080/file/"+id;
            	vm.clear();
            }
     
            function clear () {
                $uibModalInstance.dismiss('cancel');
            }
        }
    })();
    La vue :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <a type="submit" ng-click="vm.dwl()" class="btn btn-success">
    	<span class="glyphicon glyphicon-list-alt"></span>&nbsp;<span translate="myApp.download.action"></span>
    </a>
    Merci pour vos réponses pertinentes !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Pousser des données depuis le serveur vers le client dans le header HTTP
    Par Barsy dans le forum Général Conception Web
    Réponses: 2
    Dernier message: 31/12/2010, 14h03
  2. Pousser des donnees depuis le serveur vers plusieurs clients avec WCF
    Par NoussaL dans le forum Windows Communication Foundation
    Réponses: 6
    Dernier message: 30/09/2008, 17h11
  3. Impossible de télécharger des fichiers depuis mon serveur
    Par amine55555 dans le forum Mode d'emploi & aide aux nouveaux
    Réponses: 1
    Dernier message: 12/05/2007, 14h15
  4. [WebForms]Comment télécharger un fichier depuis le serveur ?
    Par pepin21 dans le forum Général Dotnet
    Réponses: 6
    Dernier message: 26/04/2006, 16h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo