
apache poi 不支持直接读取或填充 word 97–2003(.dot/.doc)二进制格式中的表单域;但可通过 xwpf 组件完整操作 word 2007+(.docx)的 xml 格式表单字段,包括查找、赋值与状态控制。
apache poi 不支持直接读取或填充 word 97–2003(.dot/.doc)二进制格式中的表单域;但可通过 xwpf 组件完整操作 word 2007+(.docx)的 xml 格式表单字段,包括查找、赋值与状态控制。
在现代 Java 文档自动化开发中,使用 Apache POI 处理 Word 表单是常见需求。需特别注意:POI 的 HWPF 组件(用于 .doc/.dot)不提供对 legacy form fields(如 FORMTEXT、FORMCHECKBOX)的读写支持——这些字段在二进制格式中以复杂结构嵌入,POI 官方明确未实现解析逻辑。
✅ 正确路径是迁移到 .docx(Office Open XML)格式,并使用 XWPFDocument 及其配套 API 操作表单域。.docx 中的表单字段本质为 Content Controls(内容控件),例如 <w:sdt> 元素,POI 通过 XWPFSDT 类提供访问能力。
✅ 基础操作示例:填充文本内容控件与复选框
import org.apache.poi.xwpf.usermodel.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;
public class DocxFormFiller {
public static void main(String[] args) throws Exception {
try (XWPFDocument doc = new XWPFDocument(new FileInputStream("template.docx"))) {
// 遍历所有结构化文档标签(即内容控件)
List<XWPFSDT> sdtList = doc.getSDTs();
for (XWPFSDT sdt : sdtList) {
// 获取控件标题(常用于标识字段名),需确保模板中已设置 Title 属性
String title = sdt.getContent().getTitle();
if ("fullName".equals(title)) {
// 填充文本型内容控件
sdt.getContent().setText("张三");
} else if ("agreeTerms".equals(title)) {
// 设置复选框状态:true=勾选,false=未勾选
sdt.getContent().setCheckBoxValue(true);
}
}
// 保存结果
try (FileOutputStream out = new FileOutputStream("filled.docx")) {
doc.write(out);
}
}
}
}⚠️ 关键前提与注意事项:
- 模板 .docx 必须由 Word 2007+ 创建,并显式插入“开发工具”选项卡中的内容控件(非旧式“表单域”);
- 内容控件需在 Word 中设置 Title(右键 → “属性” → “标题”),否则 sdt.getContent().getTitle() 返回 null;
- 若需动态定位(如按标签名/占位符文本),可结合 XWPFParagraph.searchText() 或遍历 XWPFRun 进行辅助匹配;
- POI 当前(5.2.4+)仍不支持创建新内容控件,仅支持修改已有控件;新建需借助模板或低层 XmlCursor 操作(不推荐生产环境);
- 复选框控件必须是 Checkbox Content Control(类型 CTSDTType.CHECKBOX),普通 FORMCHECKBOX(旧格式)无法识别。
✅ 替代方案提示(兼容旧文档场景)
若必须处理遗留 .dot 文件,建议:
- 使用 LibreOffice SDK 或 UNO API 转换为 .docx 后再处理;
- 通过 jacob 调用 Windows COM 接口(仅限 Windows 环境);
- 改用专业文档生成库(如 Aspose.Words for Java),其对双格式表单支持更完善(但为商业授权)。
总之,面向 .docx 的 XWPF + 内容控件是 Apache POI 下唯一稳定、可维护的 Word 表单自动化方案。务必从模板设计阶段即采用标准内容控件,并规范命名,方可实现高效、可靠的字段填充。










