Génération de documents Word avec Apache POI à partir d'un modèle

Pour générer un document Word à partir d'un modèle, on utilise des placeholders au format ${nomChamp} dans le document source. Le code ci-dessous illustre l'appel dans un service :

WellLeakageReportBo rapport = baseMapper.selectWellLeakageReport(1);
String nomFichier = "rapport_perte_" + rapport.getJh();
String cheminModele = "D:\\code\\loss-helper-project\\ruoyi-loss\\src\\main\\resources\\template\\rapport_perte.docx";

byte[] bytesDocument = genererDocumentWord(cheminModele, rapport);

La méthode générique genererDocumentWord prend un flux d'entrée (modèle) et un objet de données, et retourne un tableau d'ocetts représentant le document Word modifié.

public static byte[] genererDocumentWord(InputStream modele, WellLeakageReportBo donnees) {
    try {
        XWPFDocument doc = new XWPFDocument(modele);
        List<Segment> segments = jsonToList(donnees.getSegments());

        remplacerPlaceholders(doc, donnees);
        remplirTableau(doc, segments);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        doc.write(baos);
        return baos.toByteArray();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return new byte[0];
}

Fonction utilitaire pour convertir une chaîne JSON en liste d'objets :

public static List<Segment> jsonToList(String json) {
    Type type = new TypeToken<List<Segment>>() {}.getType();
    return new Gson().fromJson(json, type);
}

Remplacement des placeholders dans les paragraphes et les cellules de tableau :

private static void remplacerPlaceholders(XWPFDocument doc, WellLeakageReportBo donnees) throws IllegalAccessException {
    // Parcourir tous les paragraphes
    for (XWPFParagraph paragraphe : doc.getParagraphs()) {
        String texte = paragraphe.getText();
        if (texte != null && texte.contains("${")) {
            String nouveauTexte = substituerPlaceholders(texte, donnees);
            XWPFRun premierRun = paragraphe.getRuns().get(0);
            premierRun.setText(nouveauTexte, 0);
        }
    }

    // Parcourir tous les tableaux
    for (XWPFTable tableau : doc.getTables()) {
        for (XWPFTableRow ligne : tableau.getRows()) {
            for (XWPFTableCell cellule : ligne.getTableCells()) {
                for (XWPFParagraph paragraphe : cellule.getParagraphs()) {
                    String texte = paragraphe.getText();
                    if (texte != null && texte.contains("${")) {
                        String nouveauTexte = substituerPlaceholders(texte, donnees);
                        paragraphe.getRuns().get(0).setText(nouveauTexte, 0);
                    }
                }
            }
        }
    }
}

Substitution des placeholders avec réflexion :

private static String substituerPlaceholders(String texte, Object obj) throws IllegalAccessException {
    Pattern motif = Pattern.compile("\\$\\{(.+?)\\}");
    Matcher matcher = motif.matcher(texte);
    StringBuffer sb = new StringBuffer();

    while (matcher.find()) {
        String nomChamp = matcher.group(1);
        Object valeur = obtenirValeurChamp(obj, nomChamp);
        matcher.appendReplacement(sb, valeur != null ? valeur.toString() : "");
    }
    matcher.appendTail(sb);
    return sb.toString();
}

private static Object obtenirValeurChamp(Object obj, String nomChamp) throws IllegalAccessException {
    try {
        java.lang.reflect.Field champ = obj.getClass().getDeclaredField(nomChamp);
        champ.setAccessible(true);
        return champ.get(obj);
    } catch (NoSuchFieldException e) {
        return null;
    }
}

Remplissage dynamique d'un tableau à partir d'une liste de données :

private static void remplirTableau(XWPFDocument doc, List<Segment> donnees) {
    XWPFTable tableau = doc.getTables().get(0);
    XWPFTableRow lignePlaceholder = tableau.getRow(2);
    tableau.removeRow(2);

    for (Segment seg : donnees) {
        XWPFTableRow nouvelleLigne = tableau.createRow();
        nouvelleLigne.addNewTableCell();
        nouvelleLigne.getCell(0).setText(seg.getOrdreForage());
        nouvelleLigne.getCell(1).setText(seg.getSequenceOutils());
        nouvelleLigne.getCell(2).setText(seg.getSequenceTubage());

        for (int i = 0; i < 3; i++) {
            nouvelleLigne.getCell(i).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
        }
    }
}

Note : La classe Segment doit avoir les champs ordreForage, sequenceOutils, sequenceTubage et le champ correspondant dans WellLeakageReportBo doit s'appeler segments.

Étiquettes: Apache POI génération de documents Java Word modèle

Publié le 19 juin à 17h32