代码之家  ›  专栏  ›  技术社区  ›  Berlin Brown

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

  •  6
  • Berlin Brown  · 技术社区  · 15 年前

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

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

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

    我宁愿远离的可选路径。

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

    2. 使用筛选器获取最终页面输出。这没问题,但我一直有过滤器和非法状态异常的问题。它似乎从来没有100%的工作方式,我需要。

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

    1 回复  |  直到 15 年前
        1
  •  7
  •   MostafaR    9 年前

    这是一个完全令人恼火的问题,一个我不得不处理几次,一个我从来没有找到满意的解决办法。

    最基本的问题是ServletAPI在这里没有帮助,所以您必须欺骗它。我的解决方案是编写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规范指出,转发时不能替换完全不同的请求或响应对象,您必须使用它们的原始版本或包装版本。