使用Tomcat/Websphere将JSP编译到字符串或内存中

Ber*_*own 6 java websphere jsp tomcat

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

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

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

我宁愿远离的可选路径.

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

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

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

ska*_*man 7

这是一个彻头彻尾的恼人问题,一个我不得不处理几次,一个我从来没有找到一个令人满意的解决方案.

基本问题是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();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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