JSP以编程方式呈现

时间:2009-11-12 01:19:07

标签: java jsp servlets rendering jstl

我需要以编程方式呈现JSP页面。据我所知,JSP应该有一些编译器。问题是我可以在没有JspServlet和其他人的情况下直接使用这个编译器吗?我需要的只是文档如何使用JSP编译器(例如Jasper)。

我认为,一些额外的信息可以澄清情况。我不能使用标准的JspServlet。我想以某种方式在编译之前更改源JSP(确切地将两个JSP合并在一起),因此我需要一种方法直接使用JSP编译器从InputStream(或Reader)编译JSP结果。

两个JSP的合并是布局要求。你可以问:“但为什么这个人不使用SiteMesh或类似的东西?”。其中一个JSP页面不是静态的。它由用户提供并存储在数据库中。我们清理并验证了这个JSP布局(用户只能使用标签的子集,并且所有这些标签都不是标准的,而是专门为它们创建的),缓存它们等等。但是现在我们需要一种方法来使用这些JSP页面(存储在内存中)作为用户请求的所有JSP页面的布局。

6 个答案:

答案 0 :(得分:8)

  

我需要programmaticaly渲染JSP页面。

毕竟功能要求是什么?你正在寻找一个错误方向的解决方案。是什么,您认为这是解决方案的问题/要求是什么?我们可能会提出更好的建议。

例如,您是否只需要输出?如果是这样,那么java.net.URLConnection就足够了。

修改:您修改了问题:

  

我想以某种方式在编译之前更改源JSP(准确地将两个JSP合并在一起),所以我需要一种方法直接使用JSP compiller从InputStream(或Reader)编译JSP结果。

好的,这是更清晰。但你需要什么呢?这些JSP实际代表什么?应该用于最终结果的是什么?

您是否只想在另一个中包含一个JSP?例如。在head.jsp中包含main.jsp?如果是这样,那么<jsp:include>就足够了。或者更糟糕的是,它们是否包含原始Java代码以及您想要重用的某些特定代码?如果是这样,那么你应该使用普通的Java类,如果需要的话,使用taglibs。

编辑2 :正如您所评论的那样:

  

但是现在我们需要一种方法来使用这些JSP页面(顺便说一下存储在内存中)作为用户请求的所有JSP页面的布局

只需将JSP文件存储在webapp的webcontent内的磁盘文件系统上(ServletContext#getRealPath()可能会在这里拯救)并将请求转发到您自己的主JSP文件,其中包含两个JSP文件,例如:

<jsp:include page="${page1}" />
<jsp:include page="${page2}" />

编辑3 :我创建了SSCCE来证明其有效。

package mypackage;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        File root = new File(getServletContext().getRealPath("/"));

        String main = "<jsp:include page=\"${page1}\" /><jsp:include page=\"${page2}\" />";
        write(main, new File(root, "main.jsp"));

        String page1 = "<p>We are in ${data1}";
        write(page1, new File(root, "page1.jsp"));
        request.setAttribute("page1", "page1.jsp");
        request.setAttribute("data1", "first jsp");

        String page2 = "<p>We are in ${data2}";
        write(page2, new File(root, "page2.jsp"));
        request.setAttribute("page2", "page2.jsp");
        request.setAttribute("data2", "second jsp");

        request.getRequestDispatcher("main.jsp").forward(request, response);
    }

    private static void write(String content, File file) throws IOException {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
            writer.write(content);
        } finally {
            if (writer != null) try { writer.close(); } catch (IOException ignore) {}
        }
    }

}

http://localhost:8080/playground/test(或您正在使用的任何主机/上下文名称)执行它,您将看到

We are in first jsp
We are in second jsp

为了提高效率,我会缓存每个资源,并使用File#exists()检查特定页面是否已保存在磁盘上。

答案 1 :(得分:5)

我不完全确定这是否是您要查找的内容,但DWR framework包含一个名为WebContext.forwardToString的方法,该方法将当前请求和假响应对象转发到URL,然后读取缓冲区的内容到内存中。以下是代码示例:

StringWriter sout = new StringWriter();
StringBuffer buffer = sout.getBuffer();

HttpServletResponse realResponse = getHttpServletResponse();
HttpServletResponse fakeResponse = new SwallowingHttpServletResponse(realResponse, sout, realResponse.getCharacterEncoding());

HttpServletRequest realRequest = getHttpServletRequest();
realRequest.setAttribute(WebContext.ATTRIBUTE_DWR, Boolean.TRUE);

getServletContext().getRequestDispatcher(url).forward(realRequest, fakeResponse);

return buffer.toString();

您可以使用它来获取jsp重新生成的结果并将它们存储在内存中。您可以从上面的链接下载源代码,了解SwallowingHttpServletResponse的工作原理。

答案 2 :(得分:1)

也许您可以使用Tomcat's JspC ant task

答案 3 :(得分:1)

JSTL只是JSP文件中使用的标记库。所以在这种情况下,这无关紧要。

由于JSP编译器将JSP文件转换为Java Servlet,我怀疑你可以直接运行它(编译器实际上没有运行任何东西!)或者为JSP文件渲染。

实际上很难从你的问题中理解你真正想要的东西。

编辑:我会推荐jsp:include for the job

答案 4 :(得分:1)

如果JSP已经由appserver预编译,那么您可以查找生成的.class文件。在Tomcat中,这应该在$ CONTEXT_ROOT / org / apache / jsp /目录下。您可以以某种方式运行此类并生成输出。

编辑:错过了关于修改JSP源的编辑。

查看org.apache.jasper.compiler.AntCompiler(包含在Tomcat中的jasper.jar中)。有一个名为generateClass的受保护方法,您可能可以覆盖并乱用:)

答案 5 :(得分:1)

你必须这样做的原因是什么? 如果您需要合并2个jsp文件来处理,可能使用 include 或者你需要其他想法?你能举例说明你的要求吗?