Java JSP 以编程方式呈现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1719254/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JSP programmatically render
提问by Denis Bazhenov
I need to programmatically render JSP page. As far as I understand, JSP should have some compiler. The question is can I use this compiler dirrectly without JspServlet and others? All I need is documentation how to use JSP compiler (Jasper, for example).
我需要以编程方式呈现 JSP 页面。据我了解,JSP 应该有一些编译器。问题是我可以在没有 JspServlet 等的情况下直接使用这个编译器吗?我所需要的只是如何使用 JSP 编译器(例如 Jasper)的文档。
Some additional information would clarify situation, I think. I can not use standard JspServlet. I want to change source JSP before compilation in some way (merge two JSP together to be precise), so I need a way to compile JSP result from InputStream (or Reader) using the JSP compiler directly.
我认为,一些额外的信息可以澄清情况。我不能使用标准的 JspServlet。我想在编译之前以某种方式更改源 JSP(准确地说是将两个 JSP 合并在一起),所以我需要一种直接使用 JSP 编译器从 InputStream(或 Reader)编译 JSP 结果的方法。
Merging of two JSP is layout requirement. You can ask: "But why this guy just doesn't use SiteMesh or something like this?". One of JSP pages is not static. It's provided by user and stored in database. We sanitify and validates this JSP layout (users are able to use only subset of tags, and all of them are not standart but created specially for them), cache them and so on. But now we need a way to use these JSP pages (which are stored in memory) as layouts for all JSP pages that user request.
合并两个 JSP 是布局要求。你可以问:“但为什么这个家伙不使用 SiteMesh 或类似的东西?”。JSP 页面之一不是静态的。它由用户提供并存储在数据库中。我们清理和验证这个 JSP 布局(用户只能使用标签的子集,所有这些都不是标准的,而是专门为他们创建的),缓存它们等等。但是现在我们需要一种方法来使用这些 JSP 页面(它们存储在内存中)作为用户请求的所有 JSP 页面的布局。
采纳答案by BalusC
I need programmaticaly render JSP page.
我需要以编程方式呈现 JSP 页面。
What's the functional requirement after all? You're clearly looking for a solution in the wrong direction. What is it, the problem/requirement for which you think that this is the solution? We may come up with better suggestions.
毕竟功能需求是什么?您显然是在错误的方向寻找解决方案。它是什么,您认为这是解决方案的问题/要求?我们可能会提出更好的建议。
Do you for example need just its output? If so, then java.net.URLConnection
may suffice.
例如,您是否只需要它的输出?如果是这样,那么java.net.URLConnection
可能就足够了。
Edit: you edited your question:
编辑:您编辑了您的问题:
I want to change source JSP before compilation in some way (merge two JSP together to be precise), so I need a way to compile JSP result from InputStream (or Reader) using JSP compiller directly.
我想在编译之前以某种方式更改源 JSP(准确地说是将两个 JSP 合并在一起),所以我需要一种直接使用 JSP 编译器从 InputStream(或 Reader)编译 JSP 结果的方法。
OK, that's a bitmore clear. But what for do you need this? What does those JSPs actually represent? What is the final result supposed to be used for?
OK,这是一个有点更加清晰。但是你需要这个做什么?这些 JSP 实际上代表什么?最终结果应该用于什么?
Do you for example just want to include the one JSP in the other? E.g. including a head.jsp
in a main.jsp
? If so, then <jsp:include>
may suffice. Or is it more worse, do they contain raw Java code with some specific code which you wanted to reuse? If so, then you should use plain Java classes and if necessary taglibs for this.
例如,您是否只想将一个 JSP 包含在另一个中?例如,head.jsp
在 a 中包含a main.jsp
?如果是这样,那么<jsp:include>
可能就足够了。或者更糟糕的是,它们是否包含原始 Java 代码和一些您想要重用的特定代码?如果是这样,那么您应该为此使用普通的 Java 类和标签库(如有必要)。
Edit 2: as you commented:
编辑 2:正如您评论的那样:
But now we need a way to use these JSP pages (which are store is in memory by the way) as layouts for all JSP pages that user request
但是现在我们需要一种方法来使用这些 JSP 页面(顺便说一下它们存储在内存中)作为用户请求的所有 JSP 页面的布局
Just store the JSP files on the disk file system inside the webapp's webcontent (the ServletContext#getRealPath()
may come into rescue here) and forward the request to your own main JSP file which includes the two JSP files using for example:
只需将 JSP 文件存储在 web 应用程序的 web 内容中的磁盘文件系统上(ServletContext#getRealPath()
可能会在这里进行救援)并将请求转发到您自己的主 JSP 文件,其中包含两个 JSP 文件,例如:
<jsp:include page="${page1}" />
<jsp:include page="${page2}" />
Edit 3: I created an SSCCEto prove its working.
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) {}
}
}
}
Execute it at http://localhost:8080/playground/test(or whatever host/contextname you're using) and you'll see
在http://localhost:8080/playground/test(或您使用的任何主机/上下文名称)执行它,你会看到
We are in first jsp
We are in second jsp
To make it more efficient I would cache every resource and make use of File#exists()
to check if the particular page is already saved on disk.
为了提高效率,我会缓存每个资源并使用它File#exists()
来检查特定页面是否已保存在磁盘上。
回答by Jonathan Feinberg
Perhaps you could use Tomcat's JspC ant task?
也许您可以使用Tomcat 的 JspC ant 任务?
回答by Marius Burz
JSTL is just a library of tags used inside JSP files. So it really doesn't matter in this context.
JSTL 只是 JSP 文件中使用的标签库。所以在这种情况下这真的无关紧要。
Since a JSP compiler transforms JSP files into Java Servlets, I doubt you can have it directly run(a compiler doesn't actually run anything!) or render for that matter a JSP file.
由于 JSP 编译器将 JSP 文件转换为 Java Servlet,我怀疑您是否可以直接运行它(编译器实际上不运行任何东西!)或为此渲染 JSP 文件。
It's actually quite hard to understand from your question what you're really looking for.
实际上很难从你的问题中理解你真正在寻找什么。
Edit: I would recommend jsp:include for the job
编辑:我会推荐 jsp:include 来完成这项工作
回答by Thimmayya
If the JSP has already been precompiled by the appserver then you could look for the generated .class file . In Tomcat this should be under the $CONTEXT_ROOT/org/apache/jsp/ directory. You might be able to run this class somehow and generate your output.
如果 JSP 已经由 appserver 预编译,那么您可以查找生成的 .class 文件。在 Tomcat 中,这应该在 $CONTEXT_ROOT/org/apache/jsp/ 目录下。您也许能够以某种方式运行这个类并生成您的输出。
EDIT: Missed your edit about modifying the JSP source.
编辑:错过了关于修改 JSP 源代码的编辑。
Take a look at org.apache.jasper.compiler.AntCompiler (included in jasper.jar in Tomcat). There is a protected method called generateClass which you might be able to override and mess around with :)
看看 org.apache.jasper.compiler.AntCompiler(包含在 Tomcat 的 jasper.jar 中)。有一个名为 generateClass 的受保护方法,您可以覆盖和使用它:)
回答by misamap
Which reason you have to do that? If you need merge 2 jsp file to process, maybe using includeOr you need other ideas? Can you give sample about your request?
你有什么理由这样做?如果您需要合并2个jsp文件来处理,可能使用include或者您需要其他想法?你能提供关于你的要求的样品吗?
回答by Jason Gritman
I'm not totally sure if this is what you are looking for but the DWR frameworkcontains a method called WebContext.forwardToString
that forwards the current request plus a fake response object to a URL and then reads the contents of the buffer into memory. Here's a sample of the code:
我不完全确定这是否是您要查找的内容,但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();
You could use this to get the results of the jsp rednering and store them in memory. You can download the source from the above link to see how SwallowingHttpServletResponse works.
您可以使用它来获取 jsp rednering 的结果并将它们存储在内存中。你可以从上面的链接下载源代码,看看 SwallowingHttpServletResponse 是如何工作的。