加油,打工人!
工作需求,将现有的word模板有段落和表格,从数据库中查出数据并填充,word里面也有表格数据,需要将excel表格数据单独处理,然后插入到生成好的word文档中。
下面代码模拟从数据库查出来数据,生成word。
此代码,版本4.X,5.X都可以使用。
封面
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version>
</dependency>
package com.wh.filedownload.controller;import org.apache.poi.xwpf.usermodel.*;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/**
*@author wh
*@date 2024年05月24日8:59
*/
public class ReaderWord{static class User {String name;String email;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public User(String name, String email) {this.name = name;this.email = email;}}public static void generateWordFromTemplate(String templatePath, String outputPath, List<User> users) throws IOException {FileInputStream fis = new FileInputStream(templatePath);XWPFDocument doc = new XWPFDocument(fis);int userIndex = 0; // 用来追踪当前处理的用户索引for (XWPFParagraph p : doc.getParagraphs()) {for (XWPFRun r : p.getRuns()) {String text = r.getText(0);if (text != null) {text = replaceUserData(text, users.get(userIndex));r.setText(text, 0);}}// 处理完一个段落后检查是否需要开始下一个用户的数据填充if (shouldMoveToNextUser(p)) {userIndex++;if (userIndex >= users.size()) break; // 防止数组越界}}// 处理表格for (XWPFTable table : doc.getTables()) {for (XWPFTableRow row : table.getRows()) {for (XWPFTableCell cell : row.getTableCells()) {for (XWPFParagraph para : cell.getParagraphs()) {for (XWPFRun run : para.getRuns()) {String text = run.getText(0);if (text != null) {text = replaceUserData(text, users.get(userIndex));run.setText(text, 0);}}}}}// 同样,处理完一个表格后可能需要切换到下一个用户的数据userIndex++;if (userIndex >= users.size()) break; // 防止数组越界}FileOutputStream out = new FileOutputStream(outputPath);doc.write(out);out.close();doc.close();fis.close();}// 简化的替换逻辑,实际应用可能需要更复杂的正则表达式匹配private static String replaceUserData(String text, User user) {return text.replace("{{name}}", user.name).replace("{{email}}", user.email);}// 假设某些特定的段落标记(如特殊文本或样式)意味着应该开始下一个用户的数据显示private static boolean shouldMoveToNextUser(XWPFParagraph paragraph) {// 这里可以根据实际情况定义何时跳到下一个用户的数据// 例如,检查段落是否包含特定标记文本return paragraph.getText().contains("<!--NEXT_USER-->");}private static void replaceText(XWPFDocument doc, String oldText, String newText) {for (XWPFParagraph p : doc.getParagraphs()) {for (XWPFRun r : p.getRuns()) {String text = r.getText(0);if (text != null && text.contains(oldText)) {text = text.replace(oldText, newText);r.setText(text, 0);}}}}public static List<User> getUsersFromDatabase() {List<User> users = new ArrayList<>();User user = new User("小米", "");users.add(user);return users;}public static void main(String[] args) {List<User> users = getUsersFromDatabase();try {generateWordFromTemplate("template.docx", "output.docx", users);System.out.println("Word文档生成成功!");} catch (IOException e) {e.printStackTrace();}}
}
运行结果
这样就可了,如果字段没有数据,自动不显示,不用去掉空标签了。