Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 938
Denis Bazhenov Avatar asked Nov 12 '09 01:11

Denis Bazhenov


People also ask

What is rendered in JSP?

jsp page is rendered. All the data bound to the request object sent its (the .jsp file's) way will then be displayed! Here's how we handle that last part: <%@ page contentType="text/html;charset=UTF-8" language="java" %> <!

Are Java Server Pages still used?

Do developers still use JSP? Developers do still use JSP for some applications. It's a simpler technology than more modern approaches like Jamstack, or a template engine like Thymeleaf, but sometimes simple is the way to go. JSP is a core Java web technology.

How do JSPs work?

The JSP engine compiles the servlet into an executable class and forwards the original request to a servlet engine. A part of the web server called the servlet engine loads the Servlet class and executes it. During execution, the servlet produces an output in HTML format.


2 Answers

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.

like image 27
Jason Gritman Avatar answered Oct 25 '22 00:10

Jason Gritman


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.

like image 87
BalusC Avatar answered Oct 25 '22 00:10

BalusC