5

我正在尝试实现 Paul Calhoun 的 Apache FOP 解决方案,用于从 Xpages 创建 PDF(来自 Notes In 9 #102)。尝试运行执行处理的 xAgent 时出现以下 java 异常-> 在 OutputStream 已在使用时无法获取 Writer

我对 Paul 的代码所做的唯一更改是更改包名称。当 SSJS 行发生异常时,我已经隔离: var jce: DominoXMLFO2PDF = new DominoXMLFO2PDF(); 该行所做的只是实例化类,没有自定义构造函数。我不相信这是代码本身,而是一些配置问题。SSJS 代码位于应该在的 beforeRenderResponse 事件中,我没有更改 xAgent 上的任何内容。

我已将 Paul 示例数据库中的 jar 文件复制到我的,我已验证两个数据库之间的构建路径相同。一切都编译得很好(在我完成了所有这些之后。)这个异常似乎是一个 xpages 唯一的异常。

4

3 回答 3

12

以下是此错误的实际情况:

XPage 本质上是 servlet……XPage 中发生的一切都只是 servlet 引擎之上的层。基本上,servlet 可以将两种类型的数据发送回任何发起连接的对象(例如浏览器):文本和二进制。

一个普通的 XPage 发送文本——特别是 HTML。一些 xAgent 还发送文本,例如 JSON 或 XML。然而,在任何这些场景中,Domino 都使用 Java Writer来发送响应内容,因为 Writer 已针对发送字符数据进行了优化。

当我们需要发送二进制内容时,我们使用OutputStream代替,因为流已针对发送通用字节数据进行了优化。因此,如果我们发送 PDF、DOC/XLS/PPT、图像等,我们需要使用流,因为我们发送的是二进制数据,而不是文本。

问题(您很快就会看到,这是一个双关语)是我们每个响应只能使用一个。

一旦任何 HTTP 客户端被告知响应的内容类型是什么,它就会假设如何处理该内容。因此,如果您告诉它 expect application/pdf,它只会接收二进制数据。相反,如果你告诉它期望application/json,它期望只接收字符数据。如果响应包含与承诺的内容类型不匹配的任何数据,则几乎总是会使整个响应无效。

因此,Domino 以其无限的智慧保护我们不犯这个错误,只允许我们在一个请求中发送一个或另一个,如果我们不遵守该规则则抛出异常。

不幸的是……如果在我们尝试发送二进制内容时我们的代码中有任何异常,Domino 想要向消费者报告……它试图调用输出编写器发送 HTML 报告出现问题。除非我们已经获得了输出流的句柄,所以不允许 Domino 获得输出写入器的句柄,因为这将违反它自己的规则,即每个响应只使用一个句柄。反过来,这会引发您报告的异常,掩盖实际导致问题的异常(在您的情况下,可能是ClassNotFoundException)。

那么我们如何确保我们看到了真正的问题,而不是这种误导呢?我们try

try {
  /*
   * Move all your existing code here...
   */
} catch (e) {
  print("Error generating dynamic PDF: " + e.toString());
} finally {
  facesContext.responseComplete();
}

这是首选方法有两个原因:

  1. 如果我们的代码出现问题,我们不会让 Domino 抛出异常。相反,我们记录它(而不是print用来将它发送到控制台并记录,你也可以将它扔到 OpenLog,或者你喜欢的任何日志机制)。这意味着 Domino 不会尝试向用户报告错误,因为我们已经承诺我们已经向自己报告了错误。
  2. 通过将关键facesContext.responseComplete()调用(最终告诉 Domino 不要发送自己的任何内容)移动到finally块中,可以确保它会被执行。如果我们将它留在try块中,如果发生异常,它将被跳过,因为我们会直接跳到catch... 所以即使 Domino 没有报告我们的异常,因为我们捕获了它,它仍然会尝试调用响应作家,因为我们没有告诉它不要。

如果您遵循上述模式,并且您的代码有问题,那么浏览器将收到一个不完整或损坏的文件,但日志会告诉您出了什么问题,而不是报告与根本原因无关的错误问题。

于 2013-10-30T00:10:19.953 回答
0

我几乎删除了这个问题,但决定自己回答,因为当你搜索异常时,谷歌上几乎没有。

问题出在 xAgent 中,有一行 importPackage 不正确。解决这个问题使一切正常。异常措辞:“OutputStream 已在使用时无法获取 Writer”非常具有误导性。我不知道还有什么会触发此异常,但另一种描述是“Java 类??yourClass??未找到”

如果你发现了这个问题,那么你可能有同样的问题。我会忽略异常的实际含义,并在整个应用程序中检查您的包语句。java 代码会自行出错,但引用 java 的 SSJS 直到运行时才会出错,请关注该代码。

于 2013-10-29T21:10:40.907 回答
-1

在body之后更新response header就可以解决这类问题,例如:

HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();

response.getWriter().write("<html><body>...</body></html>");

response.setContentType("text/html");
response.setHeader("Cache-Control", "no-cache");
response.setCharacterEncoding("UTF-8");     
于 2018-12-05T14:19:04.247 回答