使用Gson+Apache POI实现Docx动态变量替换的问题求助
Got it, let's walk through how to solve this problem step by step. The core issue here is making your JSON-derived variables reusable in the text replacement logic, instead of hardcoding checks for every single variable. Here's a practical, scalable approach:
1. Define a Java Class to Match Your JSON Structure
First, create a plain old Java object (POJO) that mirrors the keys in your JSON file. This lets Gson parse the JSON directly into an object you can easily pull variables from.
For example, if your JSON looks like this:
{ "name": "John Doe", "testName": "Spring Boot Certification", "score": "92/100" }
Your POJO would be:
import com.google.gson.annotations.SerializedName; public class ExamResult { // Use @SerializedName if your JSON key doesn't match the Java field name private String name; private String testName; private String score; // Getters (and setters if needed) public String getName() { return name; } public String getTestName() { return testName; } public String getScore() { return score; } }
2. Parse JSON to Java Object with Gson
Next, read your JSON file and parse it into an instance of your POJO. This gives you easy access to all the variables you need to replace.
import com.google.gson.Gson; import java.io.FileReader; import java.io.IOException; public class DocxProcessor { public static ExamResult parseJson(String jsonFilePath) throws IOException { Gson gson = new Gson(); try (FileReader reader = new FileReader(jsonFilePath)) { return gson.fromJson(reader, ExamResult.class); } } }
3. Build a Replacement Map (The Key to Dynamic Variables)
Instead of writing separate text.contains("name") checks for each variable, create a Map<String, String> where the key is the placeholder in your DOCX (like {{name}} or [name]—pick a format that won't clash with regular text) and the value is the corresponding value from your JSON object.
This makes your replacement logic flexible—add new JSON fields later, and you just update the map without touching the POI code.
import java.util.HashMap; import java.util.Map; public class DocxProcessor { // ... previous parseJson method ... public static Map<String, String> buildReplacementMap(ExamResult result) { Map<String, String> replacements = new HashMap<>(); replacements.put("{{name}}", result.getName()); replacements.put("{{testName}}", result.getTestName()); replacements.put("{{score}}", result.getScore()); return replacements; } }
4. Use Apache POI to Scan & Replace Text in DOCX
Now, write the logic to read your DOCX, iterate through all text elements, and replace placeholders using the map. Note that in DOCX, text is split into XWPFParagraph objects, and each paragraph can have multiple XWPFRun segments—you'll need to check each run for placeholders.
import org.apache.poi.xwpf.usermodel.*; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Map; public class DocxProcessor { // ... previous methods ... public static void replaceTextInDocx(String inputDocxPath, String outputDocxPath, Map<String, String> replacements) throws IOException { try (XWPFDocument document = new XWPFDocument(new FileInputStream(inputDocxPath))) { // Iterate through all paragraphs for (XWPFParagraph paragraph : document.getParagraphs()) { replaceInParagraph(paragraph, replacements); } // Also check tables (if your DOCX has tables with placeholders) for (XWPFTable table : document.getTables()) { for (XWPFTableRow row : table.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { for (XWPFParagraph cellParagraph : cell.getParagraphs()) { replaceInParagraph(cellParagraph, replacements); } } } } // Save the modified document try (FileOutputStream out = new FileOutputStream(outputDocxPath)) { document.write(out); } } } private static void replaceInParagraph(XWPFParagraph paragraph, Map<String, String> replacements) { for (XWPFRun run : paragraph.getRuns()) { String text = run.getText(0); if (text != null) { // Replace all placeholders in the run's text for (Map.Entry<String, String> entry : replacements.entrySet()) { if (text.contains(entry.getKey())) { text = text.replace(entry.getKey(), entry.getValue()); } } run.setText(text, 0); } } } }
5. Put It All Together in Your Main Class
Finally, tie everything together in your main method to run the full workflow:
import java.io.IOException; import java.util.Map; public class Main { public static void main(String[] args) { try { // 1. Parse JSON to get variables ExamResult result = DocxProcessor.parseJson("exam-result.json"); // 2. Build replacement map Map<String, String> replacements = DocxProcessor.buildReplacementMap(result); // 3. Process DOCX and save new file DocxProcessor.replaceTextInDocx("template.docx", "final-result.docx", replacements); System.out.println("Document processed successfully!"); } catch (IOException e) { e.printStackTrace(); } } }
Common Issues to Troubleshoot
- Placeholder not being replaced? Check if your DOCX uses the exact placeholder format (e.g.,
{{name}}vs{name}). Also, POI might split a single placeholder across multipleXWPFRunobjects (if the text was formatted differently). For this edge case, you'd need to concatenate runs first before checking for placeholders. - Gson parsing fails? Ensure your POJO fields match the JSON keys (case-sensitive!) or use
@SerializedNameto map mismatched names. - POI dependencies missing? Make sure you have the correct Apache POI dependencies in your
pom.xml(if using Maven) orbuild.gradle:<!-- Maven example --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.5</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency>
内容的提问来源于stack exchange,提问作者Ibosh

