Partage
  • Partager sur Facebook
  • Partager sur Twitter

Afficher un PDF dans un fichier temporaire

dans un nouvel onglet

    19 janvier 2018 à 19:05:51

    Bonjour tout le monde. Voilà j'ai bloqué là-dessus tout l'après-midi. Je génère un pdf avec la librairie java itext. (https://itextpdf.com/) J'arrive à générer un fichier dans mon projet mais là j'essaye de le générer dans un fichier temporaire pour pouvoir l'afficher dans un nouvel onglet et qu'il puisse être téléchargé. Mon projet tourne avec Play Framework. Voici ma fonction java appelée en ajax quand l'utilisateur clique sur un bouton:

    public static Result getMyAdsPdf() {
            if(HttpHelper.isAjaxRequest(request())) {
                try {
                    List<Ad> ads = AdHelper.getActive(SecurityHelper.getConnectedClient());
                    ListIterator<Ad> adsIteration = ads.listIterator()
                    
                    Path file = Files.createTempFile("Mes_annonces", ".pdf");
                    Document document = new Document();
                    PdfWriter.getInstance(document, new FileOutputStream(file.toFile()));
    
                    document.open();
    
                    PdfPTable table = new PdfPTable(4);// Declaration of the table
    
                    // Table's header
                    PdfPCell column1 = new PdfPCell(new Phrase("N°"));
                    column1.setHorizontalAlignment(Element.ALIGN_CENTER);
                    table.addCell(column1);
    
                    PdfPCell column2 = new PdfPCell(new Phrase("Produit"));
                    column1.setHorizontalAlignment(Element.ALIGN_CENTER);
                    table.addCell(column2);
    
                    PdfPCell column3 = new PdfPCell(new Phrase("Perime le"));
                    column1.setHorizontalAlignment(Element.ALIGN_CENTER);
                    table.addCell(column3);
    
                    PdfPCell column4 = new PdfPCell(new Phrase("CIP/ACL"));
                    column1.setHorizontalAlignment(Element.ALIGN_CENTER);
                    table.addCell(column4);
    
                    // Table's content
                    int adIndex = 0;
                    while(adsIteration.hasNext()) {
                        Ad ad = adsIteration.next();
                        LOG.info("N°"+String.valueOf(++adIndex)+"|Produit:"+ad.getProductVidal().getName()+"|Perime le: "+String.valueOf(ad.getLapsing())+"|CIP/ACL: "+ad.getProductVidal().getCip());
                        table.addCell(String.valueOf(++adIndex));
                        table.addCell(String.valueOf(ad.getProductVidal().getName()));
                        table.addCell(String.valueOf(String.valueOf(ad.getLapsing())));
                        table.addCell(ad.getProductVidal().getCip());
                    }
    
                    document.add(table);
                    document.close();
    
                    InputStream pdfFile = new FileInputStream(file.toAbsolutePath().toString());
    
                    response().setHeader("Content-Disposition", "attachment; filename=client_ads_list.pdf");
                    return ok(pdfFile).as("application/pdf");
    
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (java.io.IOException e) {
                    e.printStackTrace();
                } catch (DocumentException e) {
                    e.printStackTrace();
                }
            } else {
                return notFound(views.html.error.notFound.render());
            }
            return ok();
        }

    Et la fonction ajax:

    getMyAdsPdf = function() {
      var requestOptions;
      requestOptions = jsWebRoutes.controllers.web.AdController.getMyAdsPdf();
      $.ajax(requestOptions)
        .done(function(data) {
          var file, fileURL;
          file = new Blob([data], {type: 'application/pdf'});
          fileURL = URL.createObjectURL(file);
          window.open(fileURL);
        })
       .fail(function(data) {});
    };
    
    return;

    Le soucis c'est que ça m'ouvre bien un pdf dans un nouvel onglet mais les pages sont blanches alors que quand je crée le pdf dans un dossier il est correctement affiché.

    Voilà si l'un de vous a déjà fait ce genre de chose je suis ouvert à toutes les suggestions. Merci d'avance.

    -
    Edité par KroBlan 19 janvier 2018 à 19:21:03

    • Partager sur Facebook
    • Partager sur Twitter
      20 janvier 2018 à 9:13:17

      Bonjour

      Pourquoi passes-tu pas un fichier temporaire ? En terme de performance ce n'est pas top, le seul intérêt que je vois est de pouvoir vérifier que le pdf est correct en cas de problème, mais en production il faut éviter les accès au disque.

      Je pense que ton problème vient du fait que tu n'écris jamais le pdf dans le flux de réponse.

      Tu as alors 2 solutions

      • la première (que je déconseilles) tu écris ton fichier pdf dans un répertoire accessible en http, et tu retournes une url de téléchargement pointant sur ce fichier. Le problème est que tous les fichiers ainsi générés sont accessibles à toute personne ayant l'url
      • tu écris directement dans le flux de réponse (ce qui est beaucoup plus performant) en remplaçant
      PdfWriter.getInstance(document, new FileOutputStream(file.toFile()));

      par

      PdfWriter.getInstance(document, response().getOutputStream());

      (je n'ai pas l'api Play sous la main, donc la méthode peut ne pas être getOutputStream() mais quelque chose d'équivalent)

      • Partager sur Facebook
      • Partager sur Twitter
        21 janvier 2018 à 22:30:29

        Merci pour ta réponse. Je vais regarder ça.

        JDesm a écrit:

        Pourquoi passes-tu pas un fichier temporaire ? En terme de performance ce n'est pas top, le seul intérêt que je vois est de pouvoir vérifier que le pdf est correct en cas de problème, mais en production il faut éviter les accès au disque.

        Quelle serait la meilleur solution selon toi ?

        -
        Edité par KroBlan 21 janvier 2018 à 22:31:45

        • Partager sur Facebook
        • Partager sur Twitter
          22 janvier 2018 à 6:52:30

          Si ton objectif est juste de retourner le Pdf, alors écris-le dans le flux de la réponse. Tu gagneras en performance et en consommation mémoire.

          Donc utilises la solution que je t'ai donnée dans le 2ème bout de code

          • Partager sur Facebook
          • Partager sur Twitter
            22 janvier 2018 à 12:40:56

            J'ai cet exemple qui écrit le pdf dans le flux de réponse en java "brut":

            https://developers.itextpdf.com/question/how-can-i-serve-pdf-browser-without-storing-file-server-side

            Mais quand je copie cette fonction la console Play me sors "value getMyAdsPdf is not a member of object controllers.web.AdController"

            getMyAdsPdf étant le nom que je donne à la fonction et controllers.web.AdController le chemin de ma classe Java qui contient la fonction.

            L'objet response() natif de Play n'a pas de méthode du style de .getOutputStream() et j'ai essayé pas mal de manips qui n'ont pas marché. J'avoue être un peu perdu, je débute en Java et j'ai découvert le framework play il y a deux semaines.

            • Partager sur Facebook
            • Partager sur Twitter
              22 janvier 2018 à 13:06:50

              Essaye alors cette approche (je ne l'ai pas validée)

              - instancie un PipedOutpuStream et passe-le à la méthode PdfWriter.getInstance

              - pour le return, remplace juste ton return ok(pdfFile).... par return ok(new PipedInputStream(pipedOutputStream))...

              C'est sans garantie, mais le principe reste de créer un pipe entre la sortie de ton générateur de pdf et la sortie de ta réponse Http (qui est encapsulée dans Play)

              • Partager sur Facebook
              • Partager sur Twitter
                22 janvier 2018 à 15:07:19

                Je crois que je vien de réaliser que le problème vient de ma requête ajax car quand je crée le pdf dans un fichier (pas temporaire, juste avec File file = new File("Mes_annonces.pdf"))à la racine, j'ai le même résultat, c'est à dire que ça m'ouvre un pdf blanc dans un nouvel onglet. Mais quand je vais voir le fichier à la racine, je constate qu'il y est bien sous "Mes_annonces.pdf" avec les données correctement écrites dedans. Donc il faudrait que je puisse ouvrir le pdf avec javascript sachant que si j'écris direct dans le flux ou dans un fichier temporaire, il faut que je récupère dynamiquement le chemin et le nom du fichier pour pouvoir l'ouvrir. Des idées ?

                Je remet le script jquery actuel, c'est les deux lignes sous la déclaration des variables file et fileURL qui sont à changer certainement :

                getMyAdsPdf = function() {
                  var requestOptions;
                  requestOptions = jsWebRoutes.controllers.web.AdController.getMyAdsPdf();
                  $.ajax(requestOptions)
                    .done(function(data) {
                      var file, fileURL;
                      file = new Blob([data], {type: 'application/pdf'});
                      fileURL = URL.createObjectURL(file);
                      window.open(fileURL);
                    })
                   .fail(function(data) {});
                };


                Edit:

                Ça ne marche toujours pas mais j'ai trouvé comment ouvrir le fichier temporaire, je renvoie tout simplement le chemin absolu en chaine de caractères dans ma fonction java:

                return ok(file.toAbsolutePath().toString());

                et j'ouvre directement la chaine de caractère à la sortie en ajax:

                getMyAdsPdf = function() {
                  var requestOptions;
                  requestOptions = jsWebRoutes.controllers.web.AdController.getMyAdsPdf();
                  $.ajax(requestOptions)
                    .done(function(data) {
                      window.open(data); // data = le chemin absolu du fichier temporaire en chaine de caractères
                    })
                   .fail(function(data) {});
                };

                Ça m'envoie bien le chemin du fichier temporaire, en tous cas ça y ressemble:

                http://localhost:9000/var/folders/h9/tf93js_d0fv_v9g7_s5qf6bm0000gn/T/Mes_annonces5995486566242776429.pdf

                Mais j'ai une erreur 404. Je commence à désespérer.

                Edit:

                Bon j'ai réussi à trouver le chemin du fichier:

                return ok(String.valueOf(file.toURI().toURL()));

                Ça me sort file:///var/folders/h9/tf93js_d0fv_v9g7_s5qf6bm0000gn/T/Mes_annonces3343945634679475234pdf

                Sauf que je dois manuellement le rentrer dans un nouvel onglet parce-que window.open(data) dans la requète ajax ne fonctionne plus alors que ça marchait très bien jusque là. Quand ça veut pas, ça veut pas. Alors que ça marchait quand je lui rentrais n'importe quoi. Quelqu'un a une idée de ce qui arrive au javascript tout d'un coup ?

                -
                Edité par KroBlan 22 janvier 2018 à 18:15:48

                • Partager sur Facebook
                • Partager sur Twitter

                Afficher un PDF dans un fichier temporaire

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown