Java Web Programming with Eclipse contents
Last modified January 14, 2011 10:55 am

back next

Java Server Pages

Objectives

References

Video

Overview

Java Server Pages (JSP) is the technology used in Java web applications to mix HTML and Java code similar to the way it is done in PHP and ASP. JSP pages are files that end with a jsp extension and contain a mixture of HTML, blocks of Java code (called scriplets) and other expressions. These JSP files are translated by JSP interpreters into Java source code. The resulting source code is then compiled, resulting in class files that can be loaded and executed by a Java virtual machine. The process is illustrated by the following diagram.

Transformation process from JSP file into Java byte code

The benefit of JSP is that it allows one to easily mix HTML with Java code. For example, consider the following servlet.

package website.web;
 
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date; 

public class TestServlet extends HttpServlet 
{ 
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
   throws ServletException, IOException 
   {
      Date now = new Date();
      PrintWriter writer = resp.getWriter();
      writer.println("<html><body>");
      writer.println(now.toString());
      writer.println("</body></html>");
   }
}

You can accomplish the same result as the above code with the following JSP file.

<%@ page import="java.util.Date" %>
<html>
   <body>
      <% 
         Date now = new Date();
         out.println(now);
      %>
   </body>
</html>

JSP files can be used to process browser requests directly. To see how this is done, create a file called now.jsp in the web folder of the website project with contents equal to the code given above. Then go to http://localhost:8080/website/now.jsp and verify that the browser displays the current time and date.

The first time you try to access a JSP file, the web container will translate the file into Java source code, compile the source code, load the new class into JVM memory, and execute the service method of the resulting class. This process takes some time, so there is usually a noticable delay the first time you access a JSP page. Subsequent requests for the file will be processed more quickly because the container directly invokes the service method of the class that was generated and loaded into memory the first time the file was requested.

You can examine the source and byte code files that Tomcat generates from the JSP by looking within the following directory.

${TOMCAT_HOME}\work\Catalina\localhost\website\org\apache\jsp

Open the file now_jsp.java in a text editor such as Notepad. The class now_jsp is declared as follows.

public final class now_jsp extends org.apache.jasper.runtime.HttpJspBase ...

If you look up the documentation for org.apache.jasper.runtime.HttpJspBase you will see that this class is a subclass of HttpServlet. That means our now.jsp file was translated into a servlet. In fact, all JSP files are translated into servlets.

Examine the body of the _jspService method within the now_jsp class. In particular, look at the out.write statements in the body of this method. Notice that the content of these lines roughly corresponds to the contents of now.jsp. When the translator encounters ordinary HTML content in a JSP file, it generates a write statement to send this content into the output stream directed to the browser. For example, the <body> tag in now.jsp is translated into the following Java statement.

out.write("   <body>\r\n");

The character symbols '\r' and '\n' represent carriage return and line feed, respectively.

When the translator encounters JSP tags (tags with the format <% ... %>), it processes the contents of these tags rather than simply writing them into the output stream. Observe that the following two lines of Java code in the sample JSP appear embedded within the translated result.

Date now = new Date();
out.println(now);

Create a JSP

In this section, you will add a Java Server Page (JSP) file to the website application and have HomeServlet forward requests to it for generation of HTML content. This design pattern is part of a larger pattern referred to by the term Model-View-Controller in which a controller (a servlet in this case) handles incoming requests from browsers, initiates execution of business logic, and then forwards control to a view component (a JSP file in this case) to generate the HTML that is returned to the browser.

Create a JSP file with the following procedure. Create a folder called jsp under web/WEB-INF. We will place all JSP in the the jsp folder under WEB-INF. The reason for this is that we want to hide the JSP from direct access by browsers, since all requests (other than those for images, css, etc.) coming from the outside will first pass through one of our servlets.

Within the folder web/WEB-INF/jsp create a file called home.jsp with the contents from the following program listing.

home.jsp

<jsp:useBean id="message" scope="request" class="java.lang.String" />
<html>
   <head>
      <title>website</title>
   </head>
   <body>
      <h1>Home</h1>
      <p>
         <%=message%>
      </p>
   </body>
</html>

The first line in the above JSP file is a useBean element. The useBean element will generate code that attempts to locate an instance of a Java class (called a bean in this context) with the name message in something called request scope. What this means is that it tries to find a value that is associated with the key "message" in the HttpServletRequest object that the web container created for handling of the current request. Thus, HttpServletRequest is an associative array, which is also called by the terms map or dictionary. If useBean doesn't find the key "message" in the request object, then it creates an instance of java.lang.String by calling its no-argument constructor. In general, useBean will create an instance of the class specified by its class attribute if the object is not found in the request map.

Next, we modify the HomeServlet so that it creates a String and places it into the request object that gets passed into the home.jsp. In this way, the servlet controls the data that the JSP file presents. This is the general pattern that is followed by MVC-based architectures, which is also referred to by the term multi-tiered architectures.

Modify HomeServlet

We need to modify HomeServlet so that it forwards processing of requests to home.jsp. This is done by calling the forward method of a RequestDispatcher that encapsulates the JSP file, which can be thought of as a wrapper around the JSP. We only need to create a single instance of RequestDispatcher and reuse this instance throughout the life time of the application. For this reason, we create this instance of RequestDispatcher in the init method of HomeServlet, since the init method is invoked when the servlet container loads the servlet for the first time, which is generally done when the first request for that servlet arrives.

Add the following member variable declaration to HomeServlet. Remember to organize imports to import the javax.servlet.RequestDispatcher class.

private RequestDispatcher homeJsp;

We will set the value of homeJsp in the Servlet's init() method. To do this, do the following.

  1. Select Source ... Override/Implement Methods.
  2. Expand the branch for the class GenericServlet.
  3. Check the box next to the init(ServletConfig) method.
  4. Set the insertion point to First Member (or First Method). (This will insert the new method before doGet, which helps to document the workflow through the class in the sense that init is called first and only once.) The following screen shot shows the result of carrying out steps 1 through 4.
  5. Click the OK button.
Override/Implement Methods window

The init method runs the first time the web container loads HomeServlet, therefore it is the logical place to put initialization code. We will use the init method to create a RequestDispatcher that will be used to run home.jsp. To do this, replace the body of the init method with the following (and organize imports).

ServletContext context = config.getServletContext();
homeJsp = context.getRequestDispatcher("/WEB-INF/jsp/home.jsp");

Change the body of doGet() to the following code.

logger.debug("HomeServlet.doGet()");
req.setAttribute("message", "bye");
homeJsp.forward(req, resp);

The following sequence diagram illustrates the flow of execution resulting from a browser request for the home page of the website application.

Sequence diagram for handling a browser request using the Model-View-Controller (MVC) pattern

When the user issues the command in his browser to retrieve the home page, the browser establishes a TCP connection with the server and uses this to send an HTTP GET request to the web server. When Tomcat gets the incoming GET request, it parses the HTTP request message and finds that the browser is requesting a resource by the name /website/home. Tomcat uses the url-pattern elements in the web.xml file to determine how to process these requests. In this case, the requested resource matches with the url-pattern associated with the home servlet. As a result, Tomcat invokes the doGet method of the home servlet. The home servlet sets an attribute (with key message) in the request object passed to it by Tomcat, and then forwards execution to homeDispatcher, which passes control to home.jsp. Finally, home.jsp generates the HTML content that is returned to the browser within an HTTP response message. After the browser receives the HTML, it closes the TCP connection with the server.

The following listing shows the modified HomeServlet.java file.

Modified HomeServlet.java for JSP

package website.web;
 
import java.io.IOException;
 
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.log4j.Logger;
 
public class HomeServlet extends HttpServlet {
        
       private Logger logger = Logger.getLogger(this.getClass());
        
       private RequestDispatcher homeJsp;
        
       public void init(ServletConfig config) throws ServletException {
               ServletContext context = config.getServletContext();
               homeJsp = context.getRequestDispatcher("/WEB-INF/jsp/home.jsp");
       }
        
       protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
       throws ServletException, IOException {
               logger.debug("HomeServlet.doGet()");
               req.setAttribute("message", "bye");
               homeJsp.forward(req, resp);
       }
}

Notice in the doGet method of HomeServlet that we pass the value of message through the HttpServletRequest object req. As stated earlier, HttpServletRequest acts as a map that associates keys (message in this case) with values (bye in this case). The expression <%=message> in the JSP is used to insert the value associated with "message" within the HTML that is sent to the browser. The expression <%=message> is approximately equivalent to the following.

String message = req.getAttribute("message");
outputStream.write(message);

Test

Reload the website application with the Tomcat manager application. Then, go to http://localhost:8080/website/home to verify that your code is working correctly. Also, check the logging window for the new logging message. The the next two screen shots show the web page generated by the JSP and the output of the logging window.

Result page of JSP
Output of LogWatcher window

In general, Tomcat will monitor the timestamps on the JSP files in order to detect changes. When a JSP file changes, Tomcat will re-translate the files, so you do not need to explicitly reload an application after making changes to the JSP. For changes to servlet code and other Java code in your project, you need to reload the application through the manager application.

Exercises

(1) Methods doGet and doPost, Revisited

Rework your solution to exercise 2 in the servlet chapter so that your solution follows the model-view-controller pattern presented in this chapter.

For now, keep the HTML form in an HTML file located directly under the web folder. In later chapters, we will do away with the static HTML file altogether.

When the user submits the message string through the form, the servlet should place the string into the request object and then forward execution to the JSP. The JSP should write the message string into the HTML code that it returns to the user's browser.

(2) Adding Two Numbers, Revisited

Rework your solution to exercise 3 in the servlet chapter so that your solution follows the model-view-controller pattern presented in this chapter. Use an approach similar to the one used for the previous exercise.

back next

Copyright 2007-2009 David Turner and Jinseok Chae. All rights reserved.