The Grand Tour: Old School JSP

Thought I was gone, didn’t you? December was a crazy month for me, so I had to put this blog on hold, but with the new year comes new priorities, and I’m back to serve you, the Java-hungry hordes.

First up this year, another step along the path to understanding the state of the art in Java Web application development. Previously, we looked at servlets, Java classes that are designed to respond to Web browser requests. Using a servlet, we assembled a simple Web interface to our database-driven to-do list. And while it worked, it would be a pain in the butt to write practical Web applications this way, with the application logic all mixed in with the HTML code for the page.

JavaServer Pages (JSP) were created to overcome this weakness of servlets. Instead of writing a Java class with HTML code in it, you write an HTML page with Java code in it. The server then converts this page into a Java servlet on the fly in order to process page requests. As we’ll see, reversing the approach in this way solves some problems, but creates some new ones.

Starting with the to-do list Web application we built last time, let’s do away with our pesky servlet and replace it with a JavaServer page that does the same thing: todo.jsp. Here’s the updated file and directory structure for our application:

/todo.jsp
/styles.css
/WEB-INF/web.xml
/WEB-INF/classes/com/sitepoint/ToDoItem.class
/WEB-INF/classes/com/sitepoint/ToDoItem.java
/WEB-INF/classes/com/sitepoint/ToDoList.class
/WEB-INF/classes/com/sitepoint/ToDoList.java
/WEB-INF/classes/uk/co/anyware/html/HTMLEscaper.class
/WEB-INF/classes/uk/co/anyware/html/HTMLEscaper.java
/WEB-INF/lib/mysql-connector-java-version-bin.jar

So let’s get started writing our todo.jsp file, so open up your favourite text editor and we’ll get cooking!

JSP files look a lot like HTML files, except that scattered throughout them will be special JSP tags. As a general rule, all JSP tags start with <% and end with %>. As we look at more modern and advanced ways of working with JSP in future, this is a rule that will be broken, but for now it’s okay if you take this as gospel.

The first thing we need to do is provide some information about the page. This is done with a page directive. Directives are a type of JSP tag that contain various settings and other types of configuration information. Directives have an @ sign following their opening <%. Here’s our page directive:

<%@ page import="java.util.*,com.sitepoint.*,uk.co.anyware.html.*" %>

The most common use for a page directive is to import Java packages that will be used by the Java code in the JSP file. In this case, we’ve indicated that we need classes from java.util, com.sitepoint, and uk.co.anyware.html. These same packages were imported by our to-do list servlet (the code for which you might like to have nearby for comparison).

We can then proceed to write our page much as we would any (X)HTML file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>To-Do List</title>
  <meta http-equiv="content-type"
      content="text/html; charset=iso-8859-1" />
  <link rel="stylesheet" type="text/css"
      href="<%= request.getContextPath() %>/styles.css" />
</head>

Look closely, and you’ll see another JSP tag in there: <%= request.getContextPath() %>. This is what we call an expression, as indicated by the = sign following the opening < % in the tag. Expressions are used to output the values of Java code; in this case, we're outputting the value returned by the getContextPath() method of the request object–the root directory of our Web application, which the browser needs to locate the styles.css file.

Yes, JSP code, just like servlet code, has access to the browser’s request through a variable called request. There is also a response variable for the browser’s response. Both of these variables are called implicit objects, as they are created implicitly for you.

Other implicit objects include out, an object that works just like the PrintWriter that is used in a servlet to send output to the browser, session, an object for storing values over the course of a particular user’s visit to your site, and application, an object for storing values for use throughout your application.

Now, just as our servlet relied on a ToDoList object to do a lot of the work of the application, so will our JSP file. We need to declare this object, and for this we need another JSP tag: a declaration.

<%!
private ToDoList toDoList;

public void jspInit() {
  toDoList = new ToDoList(getInitParameter("jdbcDriver"),
      getInitParameter("jdbcConnectionString")); 
}
%>

As you can see, declarations are indicated by an exclamation mark (!) following the opening <%, and contain Java property and method declarations just like those you would find in a Java class.

In this case, we’ve declared a ToDoList object called toDoList, and we have written a method named jspInit() that creates this object from initialization parameters, just as we did in our servlet’s init() method. While init() is a special method for servlets that is called by the server before a servlet is used for the first time, jspInit() is a special method that is called automatically to initialize JSP files.

Next up is the code that will process form submissions in this page. You’ll remember from our servlet that the page will contain two forms: one for adding items to the to-do list, and one for deleting them. The code for processing these submissions will be identical in our JSP, except that it goes inside yet another type of JSP tag: a scriptlet.

<%
String newToDo = request.getParameter("newtodo");
if (newToDo != null) {
  toDoList.addItem(newToDo);
  response.sendRedirect(request.getRequestURI());
  return;
}

String deleteid = request.getParameter("deleteid");
if (deleteid != null) {
  try {
    toDoList.deleteItem(Integer.parseInt(deleteid));
    
    response.sendRedirect(request.getRequestURI());
    return;
  }
  catch (NumberFormatException e) {
    throw new ServletException("Bad deleteid value submitted.", e);
  }
}
%>

When JSP was first conceived, scriptlets were expected to be the most common JSP tag type, so they are indicated with simple <% and %> delimiters–no special character inside the start of the tag. The Java code inside a scriptlet is executed every time the page is requested.

With the form processing taken care of, all that’s left is to produce the forms themselves. First up, we have our to-do list, which displays the current to-do items and allows the user to delete them:

<body>
  <%
  Iterator toDoItems = toDoList.getToDoItems();
  if (toDoItems.hasNext()) {
    %>
    <form action="<%= request.getRequestURI() %>" method="post">
      <select name="deleteid" size="<%= Math.max(2, toDoList.getItemCount()) %>">
        <%
        while (toDoItems.hasNext()) {
          ToDoItem toDoItem = (ToDoItem) toDoItems.next();
          %>
          <option value="<%= toDoItem.getId() %>"><%= HTMLEscaper.escape(toDoItem.toString()) %></option>
          <%
        }
        %>
      </select>
      <input type="submit" value="Delete Selected Item" />
    </form>
    <%
  }
  %>

Looks like a bit of a mess, doesn’t it? What we have here is a mixture of HTML code, JSP scriptlets, and JSP expressions. Allow me to break it down for you.

  <%
  Iterator toDoItems = toDoList.getToDoItems();
  if (toDoItems.hasNext()) {
    %>
    ...
    <%
  }
  %>

The first scriptlet gets an Iterator object containing the items in the to-do list. Our servlet did the exact same thing. Since we don’t need to display the to-do list if it doesn’t contain any items, we use an if statement to check if it does using the Iterator‘s hasNext() method.

All of the code for the form then goes inside this if statement. The closing brace of the if statement is in the last scriptlet of the page. As you can see, the Java code inside a scriptlet doesn’t need to be self-contained; you can think of the HTML code between your JSP tags as instructions to output that HTML code, with the scriptlets providing the logic for when and how that HTML should appear.

In the form, we use JSP expressions to output required values in our <form> and <select> tags:

    <form action="<%= request.getRequestURI() %>" method="post">
      <select name="deleteid" size="<%= Math.max(2, toDoList.getItemCount()) %>">
        ...
      </select>
      <input type="submit" value="Delete Selected Item" />
    </form>

Finally, we need to output an <option> tag for each item in our to-do list. The code is once again remarkably similar to our servlet, as we use a while loop to do the job:

        <%
        while (toDoItems.hasNext()) {
          ToDoItem toDoItem = (ToDoItem) toDoItems.next();
          %>
          <option value="<%= toDoItem.getId() %>">
            <%= HTMLEscaper.escape(toDoItem.toString()) %></option>
          <%
        }
        %>

It’s a mess at a glance, but if you look carefully (or better yet, if you have an editor that highlights JSP tags in a different colour), you can see how the logic is in JSP scriptlets, and the rest of the code is just HTML with JSP expressions to output dynamic values.

The form for adding new to-do list items is a piece of cake compared to the first one:

  <form action="<%= request.getRequestURI() %>" method="post">
    <input type="text" name="newtodo" />
    <input type="submit" value="Add New Item" />
  </form>
</body>
</html>

That takes care of our JSP file! The only thing left is to update the web.xml configuration file for our application to make the initialization parameters (jdbcDriver and jdbcConnectionString) available to our JSP file:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
  <display-name>ToDoJSP</display-name>
  <servlet>
    <servlet-name>toDo</servlet-name>
    <jsp-file>/todo.jsp</jsp-file>
    <init-param>
      <description>The JDBC driver class.</description>
      <param-name>jdbcDriver</param-name>
      <param-value>com.mysql.jdbc.Driver</param-value>
    </init-param>
    <init-param>
      <description>The JDBC connection string.</description>
      <param-name>jdbcConnectionString</param-name>
      <param-value>jdbc:mysql://localhost/todo?user=root&amp;password=password</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>toDo</servlet-name>
    <url-pattern>/todo.jsp</url-pattern>
  </servlet-mapping>
</web-app>

There are two significant changes from the web.xml file we used with our servlet:

  • Instead of a <servlet-class> tag to indicate the servlet for which we are providing parameters, we have a <jsp-file> tag to indicate the JSP file.

  • The <url-pattern> tag in the <servlet-mapping> points to the JSP file as well.

With those changes made, you’re ready to bundle up the application and deploy it on your server. Unlike servlets, you don’t need to compile JSP files in advance–the server will convert them to servlets and compile them for you on the fly. You do, however, still need to compile the classes that your JSP uses (ToDoList, ToDoItem, HTMLEscaper).

As with the servlet, use the jar command-prompt utility to create a WAR file containing your application:

jar cvf ToDoJSP.war .

Drop this file in Tomcat’s webapps directory to deploy it (or deploy it using whatever Java-compatible server you prefer), and edit the deployed web.xml file to match your database configuration.

Then load http://localhost:8080/ToDoJSP/todo.jsp to try out your application. You should see your familiar to-do list interface, this time generated by a JSP.

Here’s the finished WAR file, including source code, for you to play with:

Download the code (250KB)

Now, you’ll recall that the whole point of JSP was to overcome the messiness of mixing HTML code into the Java code of a servlet. If you’ve looked at the code for our new JSP file, I’d forgive you for being skeptical about whether we’ve achieved our aim.

Our to-do list JSP file is written with what I call “old school JSP”. It’s pure JSP, as it was originally conceived years ago, with none of the modern amenities. Over the next few weeks, I’ll show you how to modify it using current and advanced features of JSP. First of all, we’ll bring servlets back into the picture (but in a much simpler form!), then we’ll look at standards like JavaBeans, the Java Standard Tag Library, and JSP Expression Language.

Generally speaking, the goal will be to get rid of all the Java code in the JSP file, either by replacing it with more designer-friendly tag constructs, or by moving it into external, independent Java classes. By the time we’re done, you’ll know how to write a JSP file so that it is barely distinguishable from a standard HTML file.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://mike-tek.blogspot.com Mike Borozdin

    By the way, as for the ‘modern’ techniques, I found this MVC framework today – http://mav.sourceforge.net/.

  • Robert

    Do you must use so many scriptlets? is there a way to avoid so much java in JSP? how should we deal with logging and exception handling in JSP (on application level)? could you, please, show us how to do it? thanx

  • Pompiuses

    I’m getting the following error message:

    An error occurred at line: 9 in the jsp file: /todo.jsp
    Generated servlet error:
    C:Tomcat 5.0workCatalinalocalhosttodo2orgapachejsptodo_jsp.java:14: cannot access com.sitepoint.ToDoList

    An error occurred at line: 9 in the jsp file: /todo.jsp
    Generated servlet error:
    bad class file: G:workjavatodo2WEB-INFclassescomsitepointToDoList.class
    class file has wrong version 49.0, should be 48.0
    Please remove or make sure it appears in the correct subdirectory of the classpath.
    private ToDoList toDoList;

    What am I doing wrong??