Création d'un document Pdf en Java sous Struts 2

Java  struts    pdf

Il est toujours pratique de pouvoir générer des documents (facture, devis, Bon de Commande, Avoir, Document de réservation, etc). En entreprise, c’est une option qui n’est pas négociable.

Le Portable Document Format (PDF) est un langage de description de pages présenté par la société Adobe Systems en 1992. La spécificité du PDF est de préserver la mise en forme d’un document. Ces deux gros avantages d’un point de vue pratique :

  • La reconstruction à l’identique avec intégrité des fichiers garantie.

  • La portabilité (consultable sur de très nombreux appareils communicants).

Voici un lien vers Adobe pour ce qui souhaite télécharger la dernière version d’Adobe Acrobat Reader DC.

L’exemple de cet article porte sur la génération d’un Bon de Commande au format pdf.

N’oublions pas que sous le framework Struts2, nous utilisons les classes Action pour permettre la redirection de certaines méthodes. Exemple : la sauvegarde, l'édition, la suppression et aussi la gestion des exports.

Voici donc ci-dessous, un exemple d’une méthode d’export dans une classe action.

 

ExtraOrderAction.java

private InputStream startStream;

private static final String EXPORTPDF = "exportpdf";

//----------

public String doExport() throws DocumentException, DAOException

   {

     

      List<ExportFacturationView> lis = this.proPresta.getExtraSpecExport() ;

      if(lis==null) lis = new ArrayList<ExportFacturationView>();

      ExportFacturationView e = new ExportFacturationView();

      e.setLabel(entity.getLabelFreePrestation());

      e.setPrice(String.valueOf(entity.getPriceFreePrestation()));

      lis.add(e);

     

      ExtraOrderExport f = new ExtraOrderExport();

      f.setLabelTvaPrestationLibre(this.getLabelMontantTvaPrestationLibre());

      f.setHeaderLabel(getText("export.designation"));

      f.setHeaderPrice(getText("export.price"));

      f.setTotalTTC(String.valueOf(this.getMontantTotalTTCDecim()));

      f.setCountrySocietyPrest(this.entity.getProvidersSociety().getCountry());

      f.setNameSocietyPrest(this.entity.getProvidersSociety().getRaisonSociale());

      f.setPrestaList(this.proPresta.getExtraSpecExport());

      f.setContextPath(super.getContext());

      f.setOrder(entity);

      f.setLabelTVA(getTvaExportLabel());

      //---------------    

           

      this.startStream = f.export();

      return EXPORTPDF;

   }

La méthode doExport() permet de récupérer et d’initialiser la majorité des champs utilisés dans le pdf :

  • Certain sont de simple nom,label ou titre. L’appel s’effectue par le biais d’un fichier de properties : getText("export.price").

 

export.price = Prix HT

  • D’autres font appel à des méthodes qui aura permi de calculer des prix (par exemple) : this.getLabelMontantTvaPrestationLibre()

  • Et enfin, encore d’autre font aussi appel à des méthodes mais venant de classe Java étant persistante et donc associée à une table dans la base de données : entity.getLabelFreePrestation()

Ce joyeux mélange permet de récupérer :

  • Données générales liées à une facture : nom du client, numéro de facture,etc).

  • Ainsi que des données spécifiques : TVA, quantité ou prix HT d’un produit sur une ligne de commande.

Un dernier point, toutes ces données sont chargées dans l'attribut startStream. Cette dernière est de type flux d’entrée (InputStream), en lecture sur des ensembles d'octets. Cela permet d’encapsuler les processus d’envoie des données.

Le return EXPORTPDF va faire appel à la classe gérant le contenue du pdf.

ExtraOrderExport.java

Voici donc la classe qui représente les données d’affichage de notre fameux pdf.

- Ce qu’il y a à déclarer :

private String headerLabel;

private String headerPrice;

private String headerTauxTva;

private String headerQty;

private PdfPTable table;

Les attributs déclarés (plus Get/Set) permettent de récupérer les valeurs déclarés dans les variables de la méthode Export de la classe Action.

 

Rappel de la classe Action pour l’attribut headerPrice

f.setHeaderPrice(getText("export.price"));

Les attributs de gestion de la police :

 

protected final static Font headerFont = FontFactory.getFont(FontFactory.HELVETICA, 9, Font.NORMAL, new Color(0, 0, 0));

En enfin, l’attribut permettant de générer des tableau en pdf

private PdfPTable table;

- Construction du pdf :

 

La méthode de construction puis de génération du pdf : InputStream export() est construite en trois parties :

  • La définition, l’ouverture du document,

  • Le corps du document,

  • La fermeture du document.

 

Document document = new Document(PageSize.A4, 60, 60, 40, 40);

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

PdfWriter.getInstance(document,buffer);

document.open();

Le document est instancié au bonnes dimensions. ByteArrayOutputStream qui est le Buffer permet de stocker les données.

Grâce à PdfWriter, notre fichier pdf est créé et prêt à recevoir stocker et afficher de l’information.

Enfin, la méthode open(), gère l’ouverture du document.



Dans le corps du document,

this.table = new PdfPTable(4);   

float[] colsWidth = {2f,0.5f,0.5f,0.5f};

this.table.setWidths(colsWidth);

this.table.setWidthPercentage(100);

             

generateHeader();

generateTableCellsStartSheet();

Dans cet exemple, un tableau à quatre colonnes est créé. Il est défini les taille de chacune d’entre elles par un tableau de float.

Les deux dernières méthodes permettent de remplir le tableau. La première stipule le titre de chaque colonne. La seconde les données de chaque colonne dans le tableau.

 

Méthode generateHeader() :

private void generateHeader() throws BadElementException{

       table.addCell(getTopHeaderCell(headerLabel));

       table.addCell(getTopHeaderCell(headerQty));

       table.addCell(getTopHeaderCell(headerTauxTva));

       table.addCell(getTopHeaderCell(headerPrice));

   }

Le getTopHeaderCell programme le CSS qui est définie pour chaque titre.

private PdfPCell getTopHeaderCell(String value) throws BadElementException {

     

      PdfPCell cell = new PdfPCell(new Phrase(StringUtils.trimToEmpty(value),  headerFontBold));

      cell.setVerticalAlignment(Element.ALIGN_TOP);

      cell.setHorizontalAlignment(Element.ALIGN_CENTER);

      cell.setPaddingTop(10f);

      cell.setPaddingBottom(10f);

      return cell;

}

Rappellez vous, le headerFondBold défini le type, la taille et la couleur de la police

protected final static Font headerFontBold = FontFactory.getFont(FontFactory.HELVETICA, 9, Font.BOLD, new Color(0, 0, 0));

Méthode generateTableCellsStartSheet();

 

Pour remplir le tableau, il est important de savoir se situer dans ce dernier. Java travail par cellule de chaque ligne. Donc sur un tableau à quatre colonne, quatre cellules peuvent être remplis (ou pas) ;)

 

Commençons d'abord par les cellules vides.

 

PdfPCell emptycell = getTableLabelCell("");

      emptycell.disableBorderSide(PdfPCell.BOTTOM);

      emptycell.disableBorderSide(PdfPCell.TOP);

     

      this.table.addCell(emptycell);

      this.table.addCell(emptycell);

      this.table.addCell(emptycell);

      this.table.addCell(emptycell);

Voici quatre cellules vide qui n’ont pas de ligne supérieur et inférieur. Ce qui nous fait un retour chariot.

 

Continuons avec un titre ou une phrase sur la première colonne :

PdfPCell cellGenericPrestation = getHeaderCell(genericLabel);

      cellGenericPrestation.setHorizontalAlignment(Element.ALIGN_LEFT);

      cellGenericPrestation.disableBorderSide(PdfPCell.BOTTOM);

      cellGenericPrestation.disableBorderSide(PdfPCell.TOP);

      cellGenericPrestation.setGrayFill(2f);

      this.table.addCell(cellGenericPrestation);

La première ligne permet de déclarer et d'appeler la variable genericLabel.

Cette variable est définie dans la classe action : ExtraOrderAction.java, sous cette forme :

String genericLabel = getText("export.intraOrder.genericlabel1");

      genericLabel+=" ";

      genericLabel+= entity.getMonitoringSheet().getStartSheetInUse().getCollaborator().getCivility();

      genericLabel+=" ";

      genericLabel+= entity.getMonitoringSheet().getStartSheetInUse().getCollaborator().getFirstName();

      genericLabel+=" ";

      genericLabel+= entity.getMonitoringSheet().getStartSheetInUse().getCollaborator().getLastName();

      genericLabel+=" - ";

      genericLabel+= entity.getMonitoringSheet().getStartSheetInUse().getSociety().getRaisonSociale();

      f.setGenericLabel(genericLabel);

Donc, la variable genericLabel (fichier export) représente un attribut qui fait appelle a un fichier de properties et des méthodes.

Les autres lignes cellGenericPrestation sont du CSS. Il est possible de les programmer directement avec la variable comme dans l’exemple. Ou de gérer le CSS dans une méthode permettant sa réutilisation pour d’autre variables. Exemple : getHeaderCell().

La dernière déclaration  : this.table.addCell(cellGenericPrestation) a une importance toute particulière car elle permet d’ajouter le contenu de la variable dans la cellule du tableau.

Ne pas oublier de déclarer trois cellules vides pour effectuer un retour chariot.

Voici l’exemple d’une ligne affichant le prix hors-tax :

PdfPCell cellLabel = getLastTableCell(labeltotal);

cellLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);

this.table.addCell(cellLabel);

     

PdfPCell cellQty = getLastTableCell("");

this.table.addCell(cellQty);

this.table.addCell(cellQty);

     

PdfPCell cellprice = getLastTableCell(total  + " "+Constant.EURO);

cellprice.setHorizontalAlignment(Element.ALIGN_RIGHT);

this.table.addCell(cellprice);

Après l’exemple du tableau, voici deux autres contenu dans le document :

  • une image :

Image i2 = Image.getInstance(ConstantMoving.LOGO_EMO);

              i2.setAbsolutePosition(5f,5f);

              i2.setWidthPercentage(1f);

              i2.scalePercent(60);

              document.add(i2);

  • Des lignes (hors-tableau) :

import com.lowagie.text.Paragraph;

Paragraph p0 = new Paragraph("  ",FontFactory.getFont(FontFactory.COURIER, 11,Font.BOLD));

             

Paragraph p1 = new Paragraph(this.nameSociety,FontFactory.getFont(FontFactory.HELVETICA, 11,Font.BOLD));

p1.setIndentationLeft(300f);

Paragraph p2 = new Paragraph(this.streetSociety,FontFactory.getFont(FontFactory.HELVETICA, 10));

p2.setIndentationLeft(300f);

Paragraph p3 = new Paragraph(this.citySociety,FontFactory.getFont(FontFactory.HELVETICA, 10));

p3.setIndentationLeft(300f);

Paragraph p4 = new Paragraph(this.countrySociety,FontFactory.getFont(FontFactory.HELVETICA, 10));

p4.setIndentationLeft(300f);

             

document.add(p1);

document.add(p2);

document.add(p3);

document.add(p4);

             

document.add(p0);

Date d = new Date(); DateFormat df = DateFormat.getDateInstance( DateFormat.FULL , Locale.FRANCE );

String where = "Le " + df.format(d);

Paragraph pWhere = new Paragraph(where,FontFactory.getFont(FontFactory.HELVETICA, 9,Font.NORMAL));

pWhere.setIndentationLeft(100f);

document.add(pWhere);

Ces variables sont toutes instanciées puis définis par un attribut et le FontFactory. Enfin, elles sont ajoutées au document : document.add(p1);



Fermeture du document :

document.close();

             

ByteArrayInputStream byteArray=new ByteArrayInputStream(buffer.toByteArray());

return byteArray;

Fermeture du document par la méthode close().

ByteArrayInputStream permet de considérer un tableau d'octets comme un flux en entrée.



Voici l'un des résultats possibles :

 

 

J’espère que cet article vous aura aidé dans vos recherches.

@JonathanC

Tags :
Java
Struts2
Pdf