我需要以编程方式呈现JSP页面。据我所知,JSP应该有一些编译器。问题是我可以在没有JspServlet和其他人的情况下直接使用这个编译器吗?我需要的只是文档如何使用JSP编译器(例如Jasper)。
我认为,一些额外的信息可以澄清情况。我不能使用标准的JspServlet。我想以某种方式在编译之前更改源JSP(确切地将两个JSP合并在一起),因此我需要一种方法直接使用JSP编译器从InputStream(或Reader)编译JSP结果。
两个JSP的合并是布局要求。你可以问:“但为什么这个人不使用SiteMesh或类似的东西?”。其中一个JSP页面不是静态的。它由用户提供并存储在数据库中。我们清理并验证了这个JSP布局(用户只能使用标签的子集,并且所有这些标签都不是标准的,而是专门为它们创建的),缓存它们等等。但是现在我们需要一种方法来使用这些JSP页面(存储在内存中)作为用户请求的所有JSP页面的布局。
答案 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 或者你需要其他想法?你能举例说明你的要求吗?