The Grand Tour: A crash course in Java-less JSP

Tweet

It’s time to take the Java out of JavaServer Pages.

In the last instalment of my “Grand Tour” of Java Web application technology, we split our to-do list Web application into three parts: the model, classes that manage the data at the heart of our application; the controller, servlets that process incoming requests and then send display values to the view; and the view, JSP files that generate Web pages from those display values.

While this separation generally did a good job of separating the Java application logic from the HTML user interface code, it still left us with some Java code in our JSP file(s). This code was needed to grab the values supplied by the controller and massage them into our HTML interface. We’ll call this display logic.

This time around, I’ll show you how to get rid of the Java code in your JSP files, and implement that display logic with a simpler and more powerful alternative.

Let’s start by reviewing just what the Java display logic in our example’s JSP file does. First it gets the list of items supplied by the controller:

  List toDoItems = (List)request.getAttribute("toDoItems");
  Iterator it = toDoItems.iterator();

Then it checks if there are any items in the list:

  if (it.hasNext()) {

To keep the HTML <select> displaying as a standard list of the correct size and not a drop-down list, display logic is needed to set the size attribute:

<select name="deleteid" size="<%= Math.max(2, toDoItems.size()) %>">

Display logic is then used to process each of the to-do list items in turn:

        while (it.hasNext()) {
          ToDoItem toDoItem = (ToDoItem) it.next();

Finally, display logic is used to extract the ID and text content of each to-do list item, and to escape any special characters that may appear in the latter:

<option value="<%= toDoItem.getId() %>"><%= HTMLEscaper.escape(toDoItem.toString()) %></option>

Given that this is a relatively simple application, that’s quite a bit of Java code still lingering in a file which will ostensibly be created and edited by Web designers, who typically aren’t well versed in the finer points of the Java language and APIs.

So, what to do? Obviously this display logic is required, but we need a better way of implementing it than including Java code in our page.

There are actually quite a few alternatives written by various groups floating around the Web. From simple JSP tag libraries (collections of custom tags that you can mix in with your HTML to implement your display logic) to complete JSP replacements, the galaxy of options can be humbling. The solution proposed by the JSP 2.0 standard, however, is a combination of a tag library called the JSP Standard Tag Library (JSTL) and a syntax for accessing Java values without Java code called JSP Expression Language (EL).

While EL is built into JSP 2.0, and is therefore available automatically in your JSP files, JSTL is a separate library that must be specifically included in your Web application before you can use it. In Tomcat 5.x, you can grab the JSTL 1.1 library files from the jsp-examples Web application included with the server. Simply go into the webapps/jsp-examples/WEB-INF/lib subdirectory of the server installation, grab jstl.jar and standard.jar and copy them into the WEB-INF/lib subdirectory of the to-do list Web app.

You can now use JSTL tags in your JSP files. Let’s modify the todo.jsp file to produce the same To-Do List user interface without any Java scripting.

First, we need to declare our intention to use JSTL tags in the file. JSTL is actually divided into a number of sub-libraries, so you don’t have to load the entire library if you just want to use a couple of its tags. The most commonly-used tags are found in the Core sub-library, which we can load using this @taglib directive immediately following the @page directive at the top of the file:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

Here’s the first piece of Java code in our todo.jsp file. We use it to get the context path (the root) of our Web application, so that we can locate the CSS file to be used by the page:

  <link rel="stylesheet" type="text/css" href="<%= request.getContextPath() %>/styles.css" />

For example, if our Web application is installed in http://www.example.com/todo, then the context path for the application is /todo and therefore our style sheet will be correctly located at /todo/styles.css.

The <c:url> tag of the JSTL Core library lets us produce URLs relative to the context path automatically. Here’s how the adjusted code looks:

  <link rel="stylesheet" type="text/css" href="<c:url value="/styles.css"/>" />

Yes, you read right. That’s a JSTL tag within the attribute value of an HTML tag. XML sticklers in the audience may grit their teeth at this, but JSP was never meant to be valid XML. For XHTML standards compliance, you just need to make sure that the code generates valid XML.

The next chunk of Java code in our todo.jsp file is a little more challenging. It grabs the List object that the controller stored in a request object attribute called toDoItems, and then checks if it actually contains any to-do items:

  <%
  List toDoItems = (List)request.getAttribute("toDoItems");
  Iterator it = toDoItems.iterator();
  if (it.hasNext()) {
    %>

The <c:if> tag lets us test a condition and only output the contents of the tag when that condition is true. The tag looks like this:

  <c:if test="<i>condition</i>">...</c:if>

But how do we specify a condition? That’s where JSP Expression Language (EL) comes in. The test attribue of the <c:if> tag takes an EL expression as the condition to be tested.

EL was designed specifically to be really, really good at fetching values out of request, session, and application attributes. As a matter of fact, the EL expression that will fetch the toDoItems request attribute is simply this:

${toDoItems}

For our purposes, we actually want to go a step further and check how many items are in the toDoItems list. To do this, we need to use an EL function, which requires another JSTL sub-library to be added with a @taglib directive at the top of the page:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

With that done, we can get the number of items in the list with this EL expression:

${fn:length(toDoItems)}

And we can determine if the list contains items with this expression:

${fn:length(toDoItems) > 0}

We can now write the <c:if> tag to test this condition:

  <c:if test="${fn:length(toDoItems) > 0}">...</c:if>

Next, we’ll use JSTL not to replace some Java design logic, but to improve some pure HTML in our todo.jsp file. The form that displays the to-do list items and allows the user to delete them begins with this <form> tag:

    <form action="DeleteItem.do" method="post"></form>

This is just fine as long as our JSP is in the root directory of our Web application, but if we were to move it into a subdirectory, the action attribute of this tag would no longer point to DeleteItem.do in the root of the application. To ensure this attribute always points to the correct URL, we can use a <c:url> tag just like we used for the style sheet URL above:

    <form action="<c:url value="/DeleteItem.do"/>" method="post">

Incidentally, we can make the same change to the second <form> tag on the page, which points to AddItem.do.

The next piece of Java display logic in todo.jsp is a bit trickier to reproduce with JSTL/EL:

      <select name="deleteid" size="<%= Math.max(2, toDoItems.size()) %>">

There is no JSTL or EL equivalent to Java’s Math.max method, so to get a <select> list with a size equal to the number of items in toDoItems but no less than 2 using only standard JSTL/EL features we need to implement this logic more verbosely:

      <c:set var="selectSize" value="${fn:length(toDoItems)}"/>
      <c:if test="${selectSize < 2}">
        <c:set var="selectSize" value="2"/>
      </c:if>

The JSTL <c:set> tag lets us set a variable for use in EL expressions in the rest of the page. In this case, we set it to the number of items in toDoItems (which we again get with the fn:length EL function). We then use a <c:if> to test if the value is less than 2, in which case we use another <c:set> to set the variable to that minimum.

We can then go ahead and output the value with an expression in our <select> tag’s size attribute:

      <select name="deleteid" size="${selectSize}">

Yes–you can use EL expressions in HTML tag attributes too.

This solution is pretty messy, though. Wouldn’t it be nicer if we had an EL function that did the same thing as Math.max? As it turns out, extending EL with your own functions is pretty easy.

First, you need to create a Java class with a public, static method that does what you want your EL function to do. For this project, let’s create a class called com.sitepoint.jsp.Functions (in com/sitepoint/jsp/Functions.java). The code for this class will be dead simple:

package com.sitepoint.jsp;

public class Functions {
  public static int max(int i1, int i2) {
    return Math.max(i1, i2);
  }
}

Next you need to define a custom tag library to set this class’s max method as a custom EL function. To do this, create an XML file called functions.tld and put it in the WEB-INF directory of the project. Aside from the first tag (which is always the same), most of the code is pretty self-explanatory:

<?xml version="1.0" encoding="iso-8859-1"?>
<taglib 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-jsptaglibrary_2_0.xsd"
  version="2.0">
  <tlib-version>1.0</tlib-version>
  <short-name>Functions</short-name>
  <uri>http://www.sitepoint.com/jsp/taglibs/functions</uri>
  <function>
    <name>max</name>
    <function-class>com.sitepoint.jsp.Functions</function-class>
    <function-signature>int max(int, int)</function-signature>
  </function>
</taglib>

What this file does is associate a unique identifier in the form of a URL (http://www.sitepoint.com/jsp/taglibs/functions) with a library of EL functions. The one function in this library will be called max and will call the max method of the com.sitepoint.jsp.Functions class.

To use this library in our JSP, we need to add a @taglib directive for it to the top of the page:

<%@ taglib prefix="spfn" uri="http://www.sitepoint.com/jsp/taglibs/functions" %>

We can now calculate the size attribute of our <select> tag using a single EL expression:

      <select name="deleteid" size="${spfn:max(2,fn:length(toDoItems))}">

Next up in our Java display logic, we have a while loop that iterates through the to-do list items, pulling each out in turn to be processed:

        <%
        while (it.hasNext()) {
          ToDoItem toDoItem = (ToDoItem) it.next();
          %>

This is almost shamefully simple to do with JSTL’s <c:forEach> tag:

        <c:forEach var="toDoItem" items="${toDoItems}">

Again, we’re using the simple EL expression ${toDoItems} to access the request attribute supplied by the controller. This tag will output its contents once for each item in the list, assigning that item to the EL variable name specified by the var attribute (toDoItem, in this case).

Our final tidbits of Java display logic are used to output the ID and text of the ToDoItem objects contained in the list:

          <option value="<%= toDoItem.getId() %>"><%= HTMLEscaper.escape(toDoItem.toString()) %></option>

Here’s where EL really comes into its own. In addition to drastically simplifying the process of pulling values out of request attributes, it’s also really good at pulling values out of those values! Let me show you what I mean…

Although I didn’t mention it at the time, the ToDoItem class was designed according to the JavaBeans standard. Though it has some more complicated sections, the JavaBeans specification (not to be confused with Enterprise JavaBeans–a completely different spec) is mainly just a naming convention for classes and methods.

Under the JavaBeans spec, if an object has a property (a value that can be read and written), then it should have getPropertyName and setPropertyName methods to access it. If it’s a read-only property, then it should only have a getPropertyName method. If the property contains a boolean value, then the ‘get’ method should be called isPropertyName instead.

There’s a lot more to the spec than that, but those are the bare essentials. Since the ToDoItem class has a getId method, it has a read-only property named id.

Now the point of all this is that EL is JavaBeans-savvy. It makes it really easy to get values of JavaBean properties. So to output the value of a ToDoItem’s id property, we can just use this expression:

${toDoItem.id}

As for the text value of the ToDoItem, EL will automatically convert any object to a String using its toString method, so we could just use ${toDoItem}. Our Java code, however, was also using the HTMLEscaper class to escape any characters that might be interpreted as HTML code. But wait: JSTL/EL can do that too!

Actually there are two ways to escape HTML special characters with JSTL/EL. The first is to use the JSTL <c:out> tag with the escapeXml attribute:

<c:out value="${toDoItem}" escapeXml="true"/>

Even more convenient is the EL function fn:escapeXml:

${fn:escapeXml(toDoItem)}

So here’s how to output our to-do list items in our new todo.jsp file:

          <option value="${toDoItem.id}">${fn:escapeXml(toDoItem)}</option>

Since we’re no longer using the HTMLEscaper class, we can remove the relevant files from our Web application. We can also remove the @page directive that imported this and the other classes that were used by our Java display logic code: no Java code, no imports needed!

With all those changes made, our finished todo.jsp file looks like this:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="spfn" uri="http://www.sitepoint.com/jsp/taglibs/functions" %>
<!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="<c:url value="/styles.css"/>" />
</head>
<body>
  <c:if test="${fn:length(toDoItems) > 0}">
    <form action="<c:url value="/DeleteItem.do"/>" method="post">
      <select name="deleteid" size="${spfn:max(2,fn:length(toDoItems))}">
        <c:forEach var="toDoItem" items="${toDoItems}">
          <option value="${toDoItem.id}">${fn:escapeXml(toDoItem)}</option>
        </c:forEach>
      </select>
      <input type="submit" value="Delete Selected Item"/>
    </form>
  </c:if>
  <form action="<c:url value="/AddItem.do"/>" method="post">
    <input type="text" name="newtodo"/>
    <input type="submit" value="Add New Item"/>
  </form>
</body>
</html>

Though certainly new, the JSTL/EL syntax in this file will be a lot easier for your average Web designer to grasp than the Java code that was there previously!

Here’s the file and directory structure of our updated application:

/todo.jsp
/styles.css
/WEB-INF/functions.tld
/WEB-INF/web.xml
/WEB-INF/classes/com/sitepoint/AddToDoServlet.class
/WEB-INF/classes/com/sitepoint/AddToDoServlet.java
/WEB-INF/classes/com/sitepoint/DeleteToDoServlet.class
/WEB-INF/classes/com/sitepoint/DeleteToDoServlet.java
/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/com/sitepoint/ToDoServlet.class
/WEB-INF/classes/com/sitepoint/ToDoServlet.java
/WEB-INF/classes/com/sitepoint/jsp/Functions.class
/WEB-INF/classes/com/sitepoint/jsp/Functions.java
/WEB-INF/lib/jstl.jar
/WEB-INF/lib/mysql-connector-java-version-bin.jar
/WEB-INF/lib/standard.jar

Download the code (759KB)

As far as JSP best practices go, this updated to-do list example is about as good as you’re gonna get by following the official specs. And admittedly, we’ve got a pretty powerful Web application platform happening here. You could certainly build sizeable applications using nothing but Java classes for the model, Java servlets for the controller, and JSPs using JSTL/EL for the view, but there are more powerful options out there.

Instead of hand-coding database access in your model classes, you can use a persistence framework to synchronize your database with a set of auto-generated Java objects automatically. Hibernate is the darling of the day in this area.

Instead of writing all of your application logic as a twisty set of servlets, you can use a Web application framework like Struts to manage the complexity.

Instead of relying on JSTL tags and EL expressions enhanced with your own custom functions, you can use other tag libraries like JavaServer Faces or one of the many open source taglibs, or you can step away from JSP and use a templating system like Velocity or XMLC.

You could almost say that there are more ways to build Web applications with Java than without it! In the coming months, I’ll look at many of these options with a critical eye and try to advise you on which to use for what sort of project.

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.

  • Dr Livingston

    Keep these articles going, and you might just yet convince me that JSP is suitable for web development.

    I add, you might, as I see PHP being the ideal solution for web development, but I have an open mind :)

  • willthiswork

    Having recently started working with jsp and after reading this article (5 out of 5 five stars anyway) I admit that it looks like PHP claim to be the best suited tool for webdevelopment is not very far from absolute truth.(imho obviously)

  • andre

    java may be the most scaleable stuff there is currently, but it’s also complex and you need to do a lot of stuff before you can do something as simple as “hello world.” nevertheless, thanks kevin for these great articles. i hope there can be many more people like you in the java community who can make java easier and more accessible for the rest of us :)

  • http://www.functionflow.com Geof Harries

    Kevin,

    When are you going to be putting out a Sitepoint Java/JSP book?! I’ve been doing your tutorials here in the blog but would love to buy a book much like your PHP version, only focused on beginner/intermediate Java/JSP. What an incredible asset that would be to the community.

    geof

  • http://www.sitepoint.com/ Kevin Yank

    Trust me, Geof, I want to write it as much as you want to read it. If all goes well I should have time to do so towards the end of this year.

  • http://www.functionflow.com Geof Harries

    yay! Thanks for the hopefully great news ;)

    geof

  • Greg

    Tag libs have one problem:

    “<c:if test=”${fn:length(toDoItems) > 0}”>…”

    Don’t remember seeing that in any html tutorials ;-) How is the page designer supposed to REALLY know what condition you are testing for?

    Just because the language has “<” & “>” doesn’t make it any easier to read to a page designer. Seems like there needs to be an evolution of this process to simplify even more. It’s a great start, but there has to be something better….

  • http://www.game-machines.com/ fatnewt

    As Greg comments above, using Java tags is still Java, and it’s not suddenly a markup language. But it is a little less intimidating, and if you’re not familiar with it, it’s still a little easer to see how it maps in with your end-user markup.

    I generally prefer the XML-esque nature of the Java tag libraries… not because I don’t understand the Java, but because it’s cleaner and easier to read.

    I hold that PHP is better for building most Web sites, but Java/JSP is a good choice for a larger-scale Web application.

  • Dr Livingston

    > When are you going to be putting out a Sitepoint Java/JSP book?!

    :agree:

    Never really got into JSP but it’s something I’d like to in the future, so hurry up Kevin :)

  • arunkumar

    Hi kevin sir..

    As you said that yuo will fininsh this book by this..PLease make it faster sir..As i get a lots of idea from PHP from your Book hope this will also do.

    ArunKumar

  • Stijn

    check this though:

    <c:set var="max" value="5" scope="page" />
    <c:set var="huh" value="10" scope="page" />
    
    <c:choose>
      <c:when test="${huh < max}">
        DOH!
      </c:when>
      <c:otherwise>
        HUH???
      </c:otherwise>
    </c:choose>

    Will actually print:

    HUH???

    Not an improvement to Java I think…

    To get it to work you actually have to write the test like this:

    <c:when test="${huh < (max + 0)}">

    Ugly as hell I think

  • benow

    Or, there’s also XSL. It’s not used much, but is simpler still for interface developers, and can use template libraries for higher level ops.

    <xsl:variable name="selSize">
    <xsl:choose>
      <xsl:when test="count(toDoItems)&gt;2">
        <xsl:value-of select="count(toDoItems)"/>
      </xsl:when>
      <xsl:otherwise>2</xsl:otherwise>
    </xsl:choose>
    </xsl:variable>
    <select name="deleteid" size="{$selSize}">
    <xsl:for-each select="toDoItem">
    <option value="{id}"><xsl:value-of select="."/></option>
    </xsl:for-each>
    </select>

    A bit wordier, but clearer, imo. No non-standard xml. XSL does require a step of marshalling to XML before generating HTML via a transform, which can be impractical for large data sets (there are workarounds). Templates can be cached and reloaded on modification for real-time app dev. XML object marshalling can be done with castor, or similar. Including other XSL sheets is possible, and differing output is easy to do by replacing the XSL (ie have XSL’s for each output language HTML (if not using a resource bundle of sorts) or output to CSV, PDF, SVG or practically any output). It can be a bit more work in prepping the data for XSL transform, but the simplicity of XSL design and XML modularity make it worthwhile.

  • Get back to basics

    What the hell is happening to the world of webdesign? This fancy new technologies aren’t making things easier, but rather more complicated. All the geeks are making this stuff less accessible to the general public. JSTL isn’t any improvement over a well designed jsp page where all of the business logic is stored elsewhere. I’ve met so many developers so obsessed with this or that framework that they are paralyzed to create anything that might actually be a useful tool for the general public.