English 中文(简体)
JSP programmatically render
原标题:

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.

最佳回答

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.

问题回答

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.

Perhaps you could use Tomcat s JspC ant task?

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

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?

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





相关问题
Convert typed-in Text to lowercase

I ve got an index.jsp with [snip] <% String name = request.getParameter("name"); String pass = request.getParameter("pass"); String globalname = "webeng"; String globalpass = "2009"; ...

session transfer issue from Tomcat to ASP.Net

I am using Tomcat to host JSP and using IIS 7.0 to host aspx (C# + .Net 3.5 + VSTS 2008), and I have some session transfer issue from JSP page to ASPX page. JSP page is in one domain and all other ...

Setting the default value in Struts2

I am setting the value(kind of default value) for a drop down select value from action class in a page(given below). When the page loads the value is beig displayed but the other elements of the ...

Evaluate dynamically constructed JSP at runtime

I have a requirement where in the JSP page itself is created by the user and stored in the database. When viewing results we need to render this JSP to the client, evaluating all tags inside this JSP. ...

How to Pack/Encrypt/Unpack/Decrypt a bunch of files in Java?

I m essentially trying to do the following on a Java/JSP-driven web site: User supplies a password Password is used to build a strongly-encrypted archive file (zip, or anything else) containing a ...

JSP exception - class not found (tomcat)

I m setting up an existing application on a new Tomcat 5.5 server connecting to a Postgres database (running on Debian Lenny). When I access it I get a series of stack traces with the following root ...

ArrayList to Table in JSP

I have an ArrayList and i am trying to display it in a table ..... ArrayList rows = .... ..... <table cellspacing="1" cellpadding="4" border="3"> <tr> <TH>...

热门标签