java - 缓存基本 XWPFDocument 模板并重用它们来生成文档

标签 java rest templates apache-poi xwpf

我们正在实现一个门户,用于处理修改和生成 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/

相关文章:

java - 为数字添加前缀,例如 (1 = 001)

rest - HTTP 客户端如何向服务器请求最新数据/刷新缓存?

java - @Transactional 在 REST 层还是在服务层?哪个更好?

c++ - 为什么我不能模板重载?

c++ - 可变参数函数指针参数的模板参数推导 - 处理不明确的情况

java - 如何固定边框节点?

java - 连接GUI与游戏

c# - ASP.NET Core 中的 HttpRequestMessage 是什么?

c++ - 模板定义中的友元函数

java - 设计模式 - 使用通用对象来更新 GUI