JSP以编程方式呈现

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

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

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

我需要programmaticaly渲染JSP页面。

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

例如,你需要它的输出吗? 如果是这样,那么java.net.URLConnection可能就足够了。

编辑 :您编辑了您的问题:

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

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

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

编辑2 :正如您所说:

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

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

   

编辑3 :我创建了一个SSCCE来certificate它的工作原理 。

 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 = ""; write(main, new File(root, "main.jsp")); String page1 = "

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

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()来检查特定页面是否已保存在磁盘上。

我不完全确定这是否是您正在寻找的但DWR框架包含一个名为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的工作原理。

也许你可以使用Tomcat的JspC ant任务 ?

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

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

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

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

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

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

编辑:错过了有关修改JSP源代码的编辑。

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