使用Tomcat / Websphere将JSP编译为字符串或内存bytearray

我正在转换为图像和PDF输出。 我需要一个由我们的应用程序JSP生成的输入HTML文档。 本质上,我需要将基于JSP的应用程序的最终输出产品呈现给String或内存,然后使用该字符串进行其他处理。

有什么方法可以调用JSP渲染器来获取通常输出给用户的最终HTML内容? 理想情况下,我正在寻找适用于多个应用程序服务器(如websphere)的东西。 但是Tomcat特有的东西也会起作用。

还有其他几种不同的方法,但我认为渲染JSP(可能包括子JSP)是最好的方法。

我宁愿远离的可选路径。

  1. 我可以使用Socket API对页面执行网络请求,然后读取从该特定页面呈现的最终输出。 这可能是下一个最佳选择,但我们在多个服务器和JVM上工作,针对我需要的页面会很复杂。

  2. 使用filter来获取最终页面输出。 这很好,但我一直遇到filter和非法状态exception的问题。 它似乎永远不会像我需要的那样100%工作。

看起来这应该很简单。 JSP编译器本质上只是一个用于解析输入JSP文档和子文档然后输出一些HTML内容的库。 我想通过Java代码调用该过程。 在服务器上,可能作为独立的控制台应用程序。

这是一个彻头彻尾的刺激性问题,一个我必须处理几次,一个我从来没有找到一个令人满意的解决方案。

基本问题是servlet API在这里没有帮助,所以你必须欺骗它。 我的解决方案是编写HttpServletResponseWrapper的子类,它覆盖getWriter()和getOutput()方法并将数据捕获到缓冲区中。 然后,将您的请求转发()到您要捕获的JSP的URI,用您的包装器响应替换原始响应。 然后,您从缓冲区中提取数据,对其进行操作,并将最终结果写回原始响应。

这是我的代码:

public class CapturingResponseWrapper extends HttpServletResponseWrapper { private final OutputStream buffer; private PrintWriter writer; private ServletOutputStream outputStream; public CapturingResponseWrapper(HttpServletResponse response, OutputStream buffer) { super(response); this.buffer = buffer; } @Override public ServletOutputStream getOutputStream() { if (outputStream == null) { outputStream = new DelegatingServletOutputStream(buffer); } return outputStream; } @Override public PrintWriter getWriter() { if (writer == null) { writer = new PrintWriter(buffer); } return writer; } @Override public void flushBuffer() throws IOException { if (writer != null) { writer.flush(); } if (outputStream != null) { outputStream.flush(); } } } 

使用它的代码可以是这样的:

 HttpServletRequest originalRequest = ... HttpServletResponse originalResponse = ... ByteArrayOutputStream bufferStream = new ByteArrayOutputStream(); CapturingResponseWrapper responseWrapper = new CapturingResponseWrapper(originalResponse, bufferStream); originalRequest.getRequestDispatcher("/my.jsp").forward(originalRequest, responseWrapper); responseWrapper.flushBuffer(); byte[] buffer = bufferStream.toByteArray(); // now use the data 

它非常难看,但它是我发现的最佳解决方案。 如果您想知道,包装器响应必须包含原始响应,因为servlet规范说您在转发时无法替换完全不同的请求或响应对象,您必须使用它们的原件或包装版本。