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.