JSP 以编程方式呈现

发布于 2024-08-11 02:49:39 字数 445 浏览 6 评论 0原文

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

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

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

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).

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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

つ可否回来 2024-08-18 02:49:39

如果服务器的部署文件夹是可写的,并且服务器配置为热发布部署文件夹中的任何更改(Tomcat 默认情况下是这样),那么您可以让 servlet 在此处写入 JSP 文件,并将请求转发到某个主 JSP 文件。

想象一下,您想要动态创建一个包含以下内容的 main.jsp

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

其中 ${page1} 解析为 page1.jsp${page2} 解析为 page2.jsp,然后这是一个 SSCCE

package com.stackoverflow.q1719254;

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;

@WebServlet("/test")
public class TestServlet extends HttpServlet {

    @Override
    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 {
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
            writer.write(content);
        }
    }
    
}

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

We are in first jsp
We are in second jsp

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

If the server's deploy folder is writable and the server is configured to hotpublish any changes in deploy folder (Tomcat by default does), then you could just let a servlet write JSP files right there and forward the request to some main JSP file.

Imagine that you want to dynamically create a main.jsp with this contents:

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

Where ${page1} resolves to page1.jsp and ${page2} resolves to page2.jsp, then here's an SSCCE:

package com.stackoverflow.q1719254;

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;

@WebServlet("/test")
public class TestServlet extends HttpServlet {

    @Override
    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 {
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
            writer.write(content);
        }
    }
    
}

Execute it at http://localhost:8080/playground/test (or whatever host/contextname you're using) and you'll see

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.

情场扛把子 2024-08-18 02:49:39

我不完全确定这是否是您正在寻找的,但 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 rednering 的结果并将它们存储在内存中。您可以从上面的链接下载源代码以查看 SwallowingHttpServletResponse 的工作原理。

I'm not totally sure if this is what you are looking for but the DWR framework contains 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:

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.

向日葵 2024-08-18 02:49:39

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

Perhaps you could use Tomcat's JspC ant task?

亣腦蒛氧 2024-08-18 02:49:39

JSTL 只是 JSP 文件中使用的标记库。所以在这种情况下这真的不重要。

由于 JSP 编译器将 JSP 文件转换为 Java Servlet,因此我怀疑您是否可以直接运行它(编译器实际上并不运行任何内容!)或呈现 JSP 文件。

实际上很难从你的问题中理解你真正在寻找什么。

编辑:我会推荐 jsp:include 来完成这项工作

JSTL is just a library of tags used inside JSP files. So it really doesn't matter in this context.

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.

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

北城孤痞 2024-08-18 02:49:39

出于什么原因你必须这样做?
如果你需要合并2个jsp文件来处理,也许使用include
或者您需要其他想法?您能提供有关您的要求的样本吗?

Which reason you have to do that?
If you need merge 2 jsp file to process, maybe using include
Or you need other ideas? Can you give sample about your request?

妳是的陽光 2024-08-18 02:49:39

如果 JSP 已经由应用程序服务器预编译,那么您可以查找生成的 .class 文件。在 Tomcat 中,它应该位于 $CONTEXT_ROOT/org/apache/jsp/ 目录下。您也许能够以某种方式运行此类并生成输出。

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

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

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.

EDIT: Missed your edit about modifying the JSP source.

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 :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文