JSP examples

Examples include:


The Guru

The Guru example consists of the Advice.jsp page, and the Guru class. Because of the way that JSPs are now compiled into servlets (becoming servlets that are defined as part of the org.apache.jsp package) the Guru class must also be defined as being a member of a package - in this case package mystuff.

The code of the Advice.jsp page is:


<%@ page import="mystuff.Guru" %>
<html><head><title>The Guru</title></head>
<body bgcolor=white>
<h1 align=center><font color=red>
Today's advice from the Guru
</font></h1>
<% Guru theGuru = new Guru(); %>
<p>
<%= theGuru.enlightenMe() %>
</body></html>

The Guru class definition is:

package mystuff;

import java.util.Random;
public class Guru {
	private static Random rr;
	private static final String[ ] Sayings = {
		"Women like silent men. They think they're listening. ",
		...
   		"If you cannot have what you want, then want what you have. "
	};
	public String enlightenMe() {
		int select = rr.nextInt(Sayings.length);
		return Sayings[select];
	}
	{
		rr = new Random();
	}
}

This webapp needs a directory (context) that contains the Advice.jsp file and a subdirectory hierarchy: WEB-INF, WEB-INF/classes, WEB-INF/classes/mystuff. The WEB-INF/classes/mystuff directory contains the Guru.java source file.

If you, a Windows Tomcat user, seek advice from the Guru:

(Unix/Linux users should create the appropriate subdirectories and files in tom/webapps/advice and then restart their Tomcat.)

When you have installed the Guru webapp correctly, point your browser at http://localhost:8080/advice/Advice.jsp and you should receive enlightenment.


Taggy Guru

Naturally, you want to minimize the amount of scriptlet code and maximize the use of tags in your JSPs (it does lead to better JSPs as well as more marks in assignments). So you probably prefer the tag-style version of the Guru. The appropriately modified JSP page is:

<html><head><title>The Guru</title></head>
<body bgcolor=white>
<h1 align=center><font color=red>
Today's advice from the Guru
</font></h1>
<p>
<jsp:useBean id="theGuru" class="mystuff.Guru" />
<jsp:getProperty name="theGuru" property="enlightenment" />
</body></html>

The Guru class must also be changed to define a getEnlightenment method that replaces the enlightenMe function:

	public String getEnlightenment() {
		int select = rr.nextInt(Sayings.length);
		return Sayings[select];
	}

Subscriber, using a "bean" to save data to a database

This is a reworking of the membership example from the servlets. Input data from the initial form are handled by a JSP that transfers the data to a SubscriberRecord bean. The bean is then asked whether its data are valid.

If the data are invalid, the bean is forwarded to a second JSP that reports on the problems (this illustrates passing an extra attribute with a forwarded request). The second JSP simply reports on the errors, it does not generate a new form.

If the data entered into the SubscriberRecord are acceptable, the main JSP requests transfer of the data to the database. If this fails, the client is redirected to an apology page, otherwise the JSP prints a simple acknowledgement page.

This webapp should be deployed in the context /subscriber; its components are:

The servlet example had the servlet manage the database connection. The same approach could be used here but the code has the SubscriberRecord bean open a temporary database connection when it needs to write its data to the database.

There is still no need for any deployment web.xml file, the example is too simple. The webapp consists of its HTML and JSP files in the top level (context) directory and a WEB-INF/classes/membership directory with the modified SubscriberRecord class.

The code for the Subscriber JSP is:

<%@ page language="java" contentType="text/html" session="false" %>
<jsp:useBean scope="request" id="userInfo" class="membership.SubscriberRecord">
<jsp:setProperty name="userInfo" property="*" />
</jsp:useBean>
<% if(! userInfo.isValid()) { %>
<jsp:forward page="badInput.jsp" />
<%}%>
<% if(userInfo.createInDatabase() < 1) { %>
<jsp:forward page="NoDB.html" />
<%}%>
<html><head><title>Thank you for registering</title></head><body>
<h1>Thank you</h1>
<p>Your membership number is
<jsp:getProperty name="userInfo" property="id" />
</ul></body></html>

The SubscriberRecord bean is created with scope="Request" - it is attached to the request object and so can easily be forwarded to another servlet or JSP if necessary. The data from the form fields are transferred automatically to the matching data members of the SubscriberRecord with the jsp:setProperty ... property="*" tag. Then scriptlet style checks are used to ask the SubscriberRecord object to check itself, and if appropriate save itself.

The changes to the SubscriberRecord include its incorporation into a package and the standardization of the interfaces for the getAge and setAge methods as explained in the text.


Soccer League

This example is related to the PHP soccer example. This webapp has a HTML form that allows users to request listings of all matches, drawn matches, away wins, or home wins (it doesn't include the data upload feature of the PHP example). The search choice from the form is submitted to a JSP (or servlet) that uses an instance of SoccerSearchBean to actually run the search against a database. A SoccerSearchBean runs the appropriate SQL query and builds a collection(java.util.Vector) of SoccerGame objects (these are just little structs that hold the names of the two teams and their scores). The SoccerSearchBean has a method that supplies an Iterator to work through the collection of SoccerGame objects. This is used in the JSP page to produce the listing of the results.

Three versions of this example are provided (only first version is complete, others share components). The first has a JSP that does all the organizational work as well as handling the generation of the "pretty" response page. In the second version, the organizational work is handled by a servlet so that the JSPs need focus only on presentation. The final version changes the scriptlet code needed to print a table of entries to a tag iterator style.

The webapp should be registered as the /soccer1 context and modified to produce whatever version is desired. The application comprises a couple of HTML pages, one or two JSPs (depending on version), maybe a servlet, and the SoccerSearchBean, SoccerGame and DBInfo classes. The versions that use a servlet require web.xml files; the tag version requires tag library "tag library descriptor" files and the .jar file with the tag library classes.

The database has a single table "Teams". The rows have two varchar fields - Name1, and Name2 - for the team names, and two integer fields - Score1 and Score2 - for the teams' goals.

JSP and beans

The first version of the Soccer JSP is quite scripty:

<%@ page import="java.util.*" %>
<%@page import="soccer.*" %>
<html><head><title>Soccer League Results</title></head>
<body bgcolor=white>
<!--
Imagine that this is page contains lots of HTML directives to build a
really pretty page. A page with a tiled picture background (soccer balls
ad infinitum); assorted advertisements strategically placed. All created
by some creative artist utilizing an interactive editing program.
Embedded in amongst that auto-generated HTML will be a
few fragments of JSP scripting: actions, scriptlets, etc.
-->
<h1 align=center><font color=red>Little league soccer results</font></h1><p>
<jsp:useBean id="theLeague" class="soccer.SoccerSearchBean" />
<jsp:setProperty name="theLeague" property="searchType" />
<%
theLeague.doSearch();
%>
<% if(theLeague.numGames()==0) { %>
  <p>There haven't been any such games yet. But the season
     is young; come back again soon.
<%
   }
   else {
%>
   <table align=center border=2>
      <caption>Results</caption>
      <tr>
         <th align=center>Home Team</th>
         <th align=center>Away Team</th>
         <th align=right>Home Team Score</th>
         <th align=right>Away Team Score</th>
      </tr>
      <%
         Iterator it = theLeague.games();
         while(it.hasNext()) {
         SoccerGame sg = (SoccerGame) it.next();
      %>
      <tr>
         <td><%= sg.getTeam1() %></td>
         <td><%= sg.getTeam2() %></td>
         <td><%= sg.getScore1() %></td>
         <td><%= sg.getScore2() %></td>
     </tr>
     <%
       }
     %>
     </table>
<%
    }
%>
</body></html>

The SoccerSearchBean is instantiated, and the search parameter ("home", "away", etc) from the form is used to set the search method required.

<jsp:useBean id="theLeague" class="soccer.SoccerSearchBean" />
<jsp:setProperty name="theLeague" property="searchType" />

Then the search operation is invoked:

theLeague.doSearch();

The scriptlet conditional code then determines which of two outputs is generated - the one for cases where there are no games, and the one for where there are results that must be presented in tabular form. If a table is to be generated, a little stock HTML is output to print the table header. Then, an Iterator is obtained from the SoccerSearchBean and scriptlet code is used to print rows for a HTML table with data from successive SoccerGame objects returned by the Iterator. Scriptlet expressions are used to get data from each SoccerGame for incorporation in the generated HTML page.

The SoccerGame bean is:

package soccer;

import java.sql.*;

public class SoccerGame {
	private String team1;
	private String team2;
	private int score1;
	private int score2;

	public String getTeam1() {
		return team1;
	}

	public String getTeam2() {
		return team2;
	}

	public String getScore1() {
		return Integer.toString(score1);
	}

	public String getScore2() {
		return Integer.toString(score2);
	}

	public void loadFromResultSet(ResultSet rset) throws SQLException {
		team1 = rset.getString("NAME1");
		team2 = rset.getString("NAME2");
		score1 = rset.getInt("SCORE1");
		score2 = rset.getInt("SCORE2");
	}
}

The SoccerSearchBean is:

package soccer;

import java.sql.*;
import java.util.*;
public class SoccerSearchBean {
	private static final String allstr =
		"select * from TEAMS";
	private static final String drawstr =
		"select * from TEAMS where SCORE1=SCORE2";
	private static final String awaystr =
		"select * from TEAMS where SCORE1<<SCORE2";
	private static final String homestr =
		"select * from TEAMS where SCORE1>SCORE2";
	private String searchType;
	private Vector results;
	
	public void setSearchType(String typ)
	{
		searchType = typ;
	}

	public Iterator games() {
		if(results!=null)
			return results.iterator();
		else
			return null;
	}
	
	public int numGames() {
		if(results!=null)
			return results.size();
		else
			return 0;
	}
	
	public void doSearch()
	{
		results = new Vector();
		try {
			Connection db = DBInfo.connectToDatabase();
			Statement stmt = db.createStatement();
			String request = allstr;
			if("drawn".equals(searchType))
				request = drawstr;
			else
			if("away".equals(searchType))
				request = awaystr;
			else
			if("home".equals(searchType))
				request = homestr;
			else
			if("all".equals(searchType))
				request = allstr;
		
			ResultSet rset = stmt.executeQuery(request);
			while(rset.next()){
				SoccerGame sg = new SoccerGame();
				sg.loadFromResultSet(rset);
				results.addElement(sg);
			}
			rset.close();
			stmt.close();
			db.close();
		}
		catch(Exception e) { 
			System.out.println("Database problems- soocer jsp");
			System.out.println(e.toString());
		}
	}
}
	

Preprocessing servlet, JSP, and beans

While it wasn't that elaborate, the Soccer JSP was getting too code focussed. A better solution uses a servlet to organize the handling of the request:

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import soccer.*;

public class PreprocessServlet extends HttpServlet {
// Constant strings;
// The first few are different forms of failure message that can be
// forwarded to a JSP that reports failed searches
	private final static String
			allstr = "We couldn't show you any results, the season hasn't started!";
	private final static String
			drawstr = "There haven't been any drawn games yet this season.";
	private final static String
			homestr = "There haven't been any home wins yet this season.";
	private final static String
			awaystr = "There haven't been any away wins yet this season.";
// These strings define the URLs for the JSPs that pretty
// up the final response.
	private final static String jspFailPage = "NoResult.jsp";
	private final static String jspReportPage = "MatchReport.jsp";



	public void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
// Get form data from request
		String search = request.getParameter("searchType");
// Create and initialize the bean
		SoccerSearchBean ssb = new SoccerSearchBean();
		ssb.setSearchType(search);
// Run the search
		ssb.doSearch();
// Select appropriate reporting stage
		if (ssb.numGames() == 0) {
			doSearchFail(search, request, response);
		} else {
			doSuccess(ssb, request, response);
		}
	}


	private void doSearchFail(String search,
			HttpServletRequest request, HttpServletResponse response)
			 throws ServletException, IOException {
// A failure results in a explanatory message being
// forwarded along with the request to the "No Result" JSP
// Pick the appropriate message string
		String reason = allstr;
		if ("drawn".equals(search)) {
			reason = drawstr;
		} else
				if ("home".equals(search)) {
			reason = homestr;
		} else
				if ("away".equals(search)) {
			reason = awaystr;
		}
// Add message as attribute of request
		request.setAttribute("Message", reason);
// Prepare to forward
		RequestDispatcher dispatch =
				request.getRequestDispatcher(jspFailPage);
// Forward request and error message
		dispatch.forward(request, response);
	}


	private void doSuccess(SoccerSearchBean ssb,
			HttpServletRequest request, HttpServletResponse response)
			 throws ServletException, IOException {
// The SoccerSearchBean has a vector of results for display
// to the client. Add this bean as an attribute of the request,
// and forward to the "Match Result" JSP
		request.setAttribute("theLeague", ssb);
		RequestDispatcher dispatch =
				request.getRequestDispatcher(jspReportPage);
		dispatch.forward(request, response);
	}
}

In its doGet() method, the servlet extracts the form data and uses the data to initialize a SoccerSearchBean:

	String search = request.getParameter("searchType");
	SoccerSearchBean ssb = new SoccerSearchBean();
	ssb.setSearchType(search);

The bean then runs the search and if successful builds its collection of SoccerGame objects:

	ssb.doSearch();

The servlet uses two private functions to handle the cases of no data to report and some results matching the search request. Both involve forwarding the request to a JSP along with some additional data that are attached to the request. If there were no matching game results, the request is formwarded to a NoResult JSP and the extra appended data are in the form of a java.lang.String. If there are results, they are contained within the SoccerSearchBean; this gets forwarded to a MatchReport servlet.

	request.setAttribute("theLeague", ssb);
	RequestDispatcher dispatch =
			request.getRequestDispatcher(jspReportPage);
	dispatch.forward(request, response);

The NoResult JSP is quite simple - merely embedding into some HTML text the string that was passed with the request:

<%--
Imagine this to be a page filled with graphic pretties, along with the
small amount of dynamic content as shown!
--%>
<html><head><title>Soccer League Results</title></head>
<body bgcolor=white>
<h1 align=center><font color=red>No Results</font></h1>
<p>
<jsp:useBean scope="request" id="Message" class="String" />
<p>
<%= Message %>
</body></html>

The revised MatchReport JSP is slightly less scripty. The conditional blocks (which are very vulnerable to tidying edits by your web designer colleague) have gone. However, the iterator structure remains.


<%-- The usual apology - "this is really a pretty page with lots of
HTML" --%>

<%@ page import="java.util.*" %>
<%@ page import="soccer.*" %>
<html><head><title>Soccer League Results</title></head>
<body bgcolor=white>
<h1 align=center><font color=red>Search Results</font></h1>
<p>
<%-- Pick up SoccerSearchBean with the data --%>
<jsp:useBean scope="request" id="theLeague" class="soccer.SoccerSearchBean" />
<table align=center border=2>
<caption>Results</caption>
<tr>
<th align=center>Home Team</th>
<th align=center>Away Team</th>
<th align=right>Home Team Score</th>
<th align=right>Away Team Score</th>
</tr>
<%-- Get Iterator from bean, use it to control while loop --%>
<%

Iterator it = theLeague.games();
while(it.hasNext()) {
SoccerGame sg = (SoccerGame) it.next();
%>
<%-- Body of while loop, --%>
<%-- Once again a mix of template text and expressions --%>
<tr>
<td><%= sg.getTeam1() %></td>
<td><%= sg.getTeam2() %></td>
<td><%= sg.getScore1() %></td>
<td><%= sg.getScore2() %></td>
</tr>
<%-- Scriptlet tag closing the block started at while --%>
<%
}
%>

</table></body></html>

This version requires a simple web.xml deployment file to identify the servlet:

<web-app>
	<servlet>
		<servlet-name>SoccerServlet</servlet-name>
		<servlet-class>PreprocessServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>SoccerServlet</servlet-name>
		<url-pattern>/SoccerInfo</url-pattern>
	</servlet-mapping>
</web-app>

The configuration in the /soccer1 context is:

The links in the Soccer.html page must of course be modified to reference "SoccerInfo" (the URL for the servlet as defined in the web.xml file) rather than Soccer.jsp as in the original version of the page.

Move from scriptlet to tag style in JSP

Using a tag library that supports iterative constructs, such as the Apache struts library, allows further simplification of the JSP page:

<%-- The usual apology - "this is really a pretty page with lots of
HTML" --%>
<%@ page import="java.util.*" %>
<%@ page import="soccer.*" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html><head><title>Soccer League Results</title></head>
<body bgcolor=white>
<h1 align=center><font color=red>Search Results</font></h1>
<p>
<%-- Pick up SoccerSearchBean with the data --%>
<jsp:useBean scope="request" id="theLeague" class="soccer.SoccerSearchBean" />
<table align=center border=2>
<caption>Results</caption>
<tr>
<th align=center>Home Team</th>
<th align=center>Away Team</th>
<th align=right>Home Team Score</th>
<th align=right>Away Team Score</th>
</tr>
<logic:iterate id="sg" collection="<%= theLeague.games() %>" >
<tr>
<td><bean:write name="sg" property="team1" /></td>
<td><bean:write name="sg" property="team2" /></td>
<td><bean:write name="sg" property="score1" /></td>
<td><bean:write name="sg" property="score2" /></td>
</tr></logic:iterate>
</table></body></html>

The JSP starts by identifying the extra tag libraries that it uses. The two "tag library descriptor" file (struts-bean.tld and struts-logic.tld) must be included in the WEB-INF directory and the struts.jar file is needed in WEB-INF/lib. (Note, the struts library is evolving in the same way as many other parts of the Servlet/JSP/Servlet-engine system. If you use a later version of struts than that used here, you may encounter minor differences that could require some reworking of the code.)

The web.xml file is more elaobrate because it must identify the tag libraries:

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>

	<servlet>
		<servlet-name>SoccerServlet</servlet-name>
		<servlet-class>PreprocessServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>SoccerServlet</servlet-name>
		<url-pattern>/SoccerInfo</url-pattern>
	</servlet-mapping>
                                      

  <!-- Struts Tag Library Descriptors -->
  <taglib>
    <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>


  <taglib>
    <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>
	
</web-app>

The configuration in the /soccer1 context is:


DateStamper tag

This little example illustrates how to define a simple tag class. Realistically, most developers have no need to define tag classes - the existing libraries already include versions of the tags that one is most likely to need.

The DateStamper class extends the simple TagSupport class. If has a couple of application specific methods, getComment and setComment, and overrides the doEndTag method. Naturally, it must be defined as part of a package (package mine)

package mine;
import java.util.*;
import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

public class DateStamper extends TagSupport {

	protected String comment = null;


	public String getComment() {
		return comment;
	}

	public void setComment(String cm) {
		comment = cm;
	}

	public int doEndTag() {
		try {
			String datestr = (new Date()).toString();
			pageContext.getOut().println(
					"<hr>This page entitled, " +
					comment
					 + ", was printed on " +
					datestr +
					"<br>");
		} catch (Exception e) {}
		return EVAL_PAGE;
	}
}

The following example JSP uses the DateStamper:

<%@ taglib uri="/mytaglib" prefix="mytag" %>
<html><head><title>My Tag Test</title></head>
<body bgcolor=white>
<h1 align=center>Test Document</h1>
<p>
Hello Work, Hi Mom, and other standard greetings.
<mytag:DateStamper comment="My Tag Test" />
</body></html>

The complexities come with the deployment! There has to be a tld file that is described in the web.xml file:

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
    
 <web-app>
	<taglib>
		<taglib-uri>
			/mytaglib
		</taglib-uri>
		<taglib-location>
			/WEB-INF/tlds/mytaglib.tld
		</taglib-location>
	</taglib>
</web-app>

The tld file contains the specification for the DateStamper tag, identifying the class, and the requirement for a "comment" attribute in any use of the tag:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
	<tlibversion>1.0</tlibversion>
	<jspversion>1.1</jspversion>
	<shortname>mytag</shortname>
	<tag>
		<name>DateStamper</name>
		<tagclass>mine.DateStamper</tagclass>
		<bodycontent>empty</bodycontent>
		<attribute>
			<name>comment</name>
			<required>true</required>
		</attribute>
	</tag>
</taglib>

Typically, a tag library will contain many tag classes; the compiled version being packaged as a jar file. The jar file would be installed in a WEB-INF/lib directory. In a simple case such as this, the compiled tag class files can simply be located in the WEB-INF/classes directory.

The configuration for this example, to be deployed as the context /tagsdemo, is: