简体   繁体   English

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

[英]JSP compilation to string or in memory bytearray with Tomcat/Websphere

I am doing conversion to image and PDF output. 我正在转换为图像和PDF输出。 I need an input HTML document that is generated by our application JSPs. 我需要一个由我们的应用程序JSP生成的输入HTML文档。 Essentially, I need to render the final output product of a JSP based application to a String or memory and then use that string for other processing. 本质上,我需要将基于JSP的应用程序的最终输出产品呈现给String或内存,然后使用该字符串进行其他处理。

What are some ways that I can just invoke the JSP renderer to get the final HTML content that is normally output to the user? 有什么方法可以调用JSP渲染器来获取通常输出给用户的最终HTML内容? Ideally, I am looking for something that will work for multiple application servers like websphere. 理想情况下,我正在寻找适用于websphere等多个应用服务器的东西。 But something that is Tomcat specific will also work. 但是特定于Tomcat的东西也会起作用。

There are a couple of other different approaches, but I think rendering the JSP (which may include sub JSPs) is the best approach. 还有其他几种不同的方法,但我认为渲染JSP(可能包括子JSP)是最好的方法。

Optional Paths that I would rather stay away from. 我宁愿远离的可选路径。

  1. I could perform a network request to the page using the Socket APIs and then read the final output that is rendered from that particular page. 我可以使用Socket API对页面执行网络请求,然后读取从该特定页面呈现的最终输出。 This is probably the next best option, but we work on multiple servers and JVMs, targeting the page I need would be complicated. 这可能是下一个最佳选择,但我们在多个服务器和JVM上工作,针对我需要的页面会很复杂。

  2. Use a filter to get that final page output. 使用过滤器来获取最终页面输出。 This Ok but I have always had problems with filters and illegalstateexceptions. 这很好,但我一直遇到过滤器和非法状态异常的问题。 It never seems to work 100% the way I need to. 它似乎永远不会像我需要的那样100%工作。

It seems like this should be simple. 看起来这应该很简单。 The JSP compiler is essentially just a library for parsing an input JSP document and subdocuments and then output some HTML content. JSP编译器本质上只是一个用于解析输入JSP文档和子文档然后输出一些HTML内容的库。 I would like to invoke that process through Java code. 我想通过Java代码调用该过程。 On the server and possibly as a standalone console application. 在服务器上,可能作为独立的控制台应用程序。

This is a downright irritating problem, one I've had to handle a few times and one I've never found a satisfactory solution to. 这是一个彻头彻尾的恼人问题,一个我不得不处理几次,一个我从来没有找到一个令人满意的解决方案。

The basic problem is that the servlet API is of no help here, so you have to trick it. 基本问题是servlet API在这里没有帮助,所以你必须欺骗它。 My solution is to write a subclass of HttpServletResponseWrapper which override the getWriter() and getOutput() methods and captures the data into a buffer. 我的解决方案是编写HttpServletResponseWrapper的子类,它覆盖getWriter()和getOutput()方法并将数据捕获到缓冲区中。 You then forward() your request to the URI of the JSP you want to capture, substituting your wrapper response for the original response. 然后,将您的请求转发()到您要捕获的JSP的URI,用您的包装器响应替换原始响应。 You then extract the data from the buffer, manipulate it, and write the end result back to the original response. 然后,您从缓冲区中提取数据,对其进行操作,并将最终结果写回原始响应。

Here's my code that does this: 这是我的代码:

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();
        }
    }

}

The code to use it can be something like this: 使用它的代码可以是这样的:

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

It's very ugly, but it's the best solution I've found. 它非常难看,但它是我发现的最佳解决方案。 In case you're wondering, the wrapper response has to contain the original response because the servlet spec says that you cannot substitute a completely different request or response object when you forward, you have to use the originals, or wrapped versions of them. 如果您想知道,包装器响应必须包含原始响应,因为servlet规范说您在转发时无法替换完全不同的请求或响应对象,您必须使用它们的原件或包装版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM