我们正在实现一个门户,用于处理修改和生成 Microsoft Office 2007 文档 (docx) 的请求。后端是用 Java 实现的,使用 Apache POI 作为操作 docx 文件内容的 API。通过来自用 JavaScript 编写的前端的 RestAPI 调用来访问后端。
后端就像一个文档服务器,处理大约 15 个不同的 docx 文档,这些文档充当模板并包含需要替换为实际值的标记。来自前端的请求实际上是一个 token 值映射,后端需要在模板中替换它并为每个请求生成一个新文档。工作流程如下:
- 接收前端请求:token-value映射
- 将模板文档读取为 XWPFDocument 对象
- 解析并替换 XWPFDocument 的所有 XWPFParagraph/XWPFTable 元素中的文本
- 将修改后的 XWPFDocument 写入不同的文件路径
我目前正在尝试实现缓存机制,这是一个真正的性能问题,它是针对每个请求访问磁盘并读取文件的。我需要将每个模板文档视为原型(prototype),并为后端收到的每个请求返回一个克隆,与此类似:
XWPFDocument theDocument = documentCache.clone(documentConfiguration.getInputType());
clone方法目前实现如下:
public XWPFDocument clone(DocumentDictionary.DocumentType type){
if(PACKAGE_MAP.isEmpty())
getPackages();
XWPFDocument document = null;
try {
document = new XWPFDocument(PACKAGE_MAP.get(type));
}catch(IOException exception){
logger.error("Unable to clone document for input type {}", type);
}
return document;
}
此实现没有产生预期的结果,第一个请求处理按预期工作,但第二个请求在写入文档时失败,并出现错误:
Caused by: org.xml.sax.SAXParseException: The processing instruction target matching "[xX][mM][lL]" is not allowed.
在每次请求时重新读取文档的情况下,上述异常不会重复。 查看 Apache POI API,在读/写过程中使用的 XWPFDocument 和 ZipPackage 的 clone() 方法受到保护,因此我无法使用编程语言提供的基本功能,问题似乎来自于 ZipPackage 在文档的读/写过程中共享和使用这一事实。
有人能够使用 Java 和 Apache POI 实现这样的机制吗?
最佳答案
您可以为每个模板类型预加载byte[]
,然后使用ByteArrayInputStream
作为克隆的基础
您还可以仅在请求时实例化模板,因此 getPackages()
变为 getPackage(DocumentDictionary.DocumentType type)
并检查 foreach 中的单一类型
XWPFDocument是在运行时编写的,因此当您对其段落、表格或一般运行进行修改时,您正在编辑模板文档,因此您必须以其他方式重新加载它。
private void getPackages() {
for (DocumentDictionary.DocumentType type : DocumentDictionary.DocumentType.values()) {
PACKAGE_MAP.put(type, FileUtils.readFileToByteArray(new File(getTemplateFromType(type))));
}
}
private String getTemplateFromType(DocumentDictionary.DocumentType type) {
switch(type) {
case TYPE_1:
return "/path/to/template/type_1.docx";
...
}
}
public XWPFDocument clone(DocumentDictionary.DocumentType type) {
if(PACKAGE_MAP.isEmpty())
getPackages();
XWPFDocument document = null;
try {
document = new XWPFDocument(new ByteArrayInputStream(PACKAGE_MAP.get(type)));
} catch(IOException exception) {
logger.error("Unable to clone document for input type {}", type);
}
return document;
ByteArrayInputStream();
}
关于java - 缓存基本 XWPFDocument 模板并重用它们来生成文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48748811/