Article
All Java, No Froth: 6 Easy Steps to MVC Web Apps
A Crash Course in Java-less JSP
It's time to take the Java out of JavaServer Pages.
We've 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 approach 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.
Now, I'll show you how to get rid of the Java code ftrom 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, we use display logic 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 text:
<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 -- people 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 that have been written by various groups floating around the Web. From simple JSP tag libraries (collections of custom tags that you can mix 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 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 therefore is available automatically in your JSP files, JSTL is a separate library that must specifically be 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 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, which this will.
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 checks if it 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 output the contents of the tag only 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 would 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'd set it to the number of items in toDoItems (which we'd again get with the fn:length EL function). We'd then use a <c:if> to test if the value was less than 2, in which case we'd use another <c:set> to set the variable to that minimum.
We could 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 would be pretty messy, though. Wouldn't it be nice 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 very simple:
package com.sitepoint.jsp;
public class Functions {
public static int max(int i1, int i2) {
return Math.max(i1, i2);
}
}
Next, we 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 fairly 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 simplifying drastically 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.
The point of all this is that EL is JavaBeans-savvy: EL makes it really easy to get values of JavaBean properties. So, to output the value of a ToDoItem's id property, we can 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, also uses 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)}
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, though EJB 3.0 is on the horizon with all the same benefits in a standardized package.
Instead of writing all of your application logic as a twisty set of servlets, you can use a web application framework like Struts, WebWork, Tapestry or Stripes 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! Be sure to follow The Daily Grind, SitePoint's Java blog, as I explore these many options, and watch sitepoint.com for more articles to help you discover the joys of Java web development.