Tag languages are systems of XML-like tag structures which
are meant to substitute for, minimize, or possibly eliminate
JSP "scripting", i.e.,
actual Java code introduced through JSP tags:
<% ... %>
The sample application in this document requires two new JAR files.
You can use these directly, or use NetBeans' built-in JSTL library.
for NetBeans, download the
TagBasics.ziparchive and install this as a Web Application from Existing Sources.
Add the two JAR files or the JSTL Library to the application.
EL, or more formally, the
unimaginatively
named United Expression Language is a
script-like language built into JSP. The common
structure is that its expressions are all of the form:
${... some EL expression ...}
Without anything else, it provides simple script-like ways
of creating expressions using either:
session values
the bean properties of session values
request values
The first sample script illustrates the basic properties:
bean.Sample
package bean;
import java.util.*;
public class Sample {
private String[] names = {"jim", "karen", "joe"};
private Map<String, Integer> ages = new LinkedHashMap<String, Integer>();
private List<Integer> ids = new ArrayList<Integer>();
private int count = 0;
@Override
public String toString() { return "This is a Sample bean"; }
public Sample() {
ages.put("kevin", 22); ages.put("fred", 15); ages.put("john", 30);
ids.add(33); ids.add(18); ids.add(57);
}
public String[] getNames() { return names; }
public Map<String, Integer> getAges() { return ages; }
public List<Integer> getIds() { return ids; }
public int getCount() { return count; }
public void setCount(int count) { this.count = count; }
}
We need the sample bean, but only for the execution of the single
GET request. There would be no difference if we were to use
scope="session" so far, because we did not modify any
of the Bean state.
Observe some of the key points:
We use Bean properties, i.e., those names exposed by public
get/set methods. In particular, we only need a getter to do
what we've done so far.
EL treats all list/map accesses via the array-like [..] operations,
replacing the ".get" operations for collection data structures
The EL object param, with usage param.xx acts like the
request.getParameter("xx") operation.
For a multivalued parameter, say "yy",
use the paramValues object, with usage like
paramValues.yy corresponding to
request.getParameterValues("yy").
JSTL overview
JSTL stands for the Java Server Pages
Standard Tag Library.
This library provides
a set of XML-tags which are meant to use
in conjunction with EL expressions to replace JSP scripting.
Refer to these hyperlinks for documentation.
The JSTL tags are those described in the table below.
We have omitted the sql
tags since we don't want to use
SQL operations directly in JSP.
Using a tag groups is effected by the addition of one
of the following respective tag statements below.
These and other tag systems are used in JSP in one of two forms:
<tagPrefix:tagType attribute1="VALUE1" ...
or, as functions to create expressions:
tagPrefix:function(arg1,arg2,...)
As in XML, tags can be complete, using a single tag ending with
"/>", or in pairs, containing a content
terminated by a matching
ending tag </tagPrefix:tagType>.
Some example of the common usages of the "c" tags are these:
EL is meant to be used in conjuction with JSTL to yield
the fullest usage.
In particular,
EL variables are typeless like most script languages.
EL expressions can also be boolean expression used as
the value of test attributes.
The
== operator for strings
replaces like the Java .equals operator.
The word null represents an undefined value, similar to Java,
but is equivalent to the empty string and is
often printed as the empty string.
EL has a unary operator empty where
empty(x) is true if x==null
or x is the empty string.
The operators or, and
are synonyms for ||, &&, respectively.
EL variables can also be created in a number of ways, typically
as temporary variables needed to effect some operation such
as iteration.
In order to iterate over an array, list, map, or set, the
c:forEach tag pair serves our interests.
Iteration with c:forEach
treats arrays, lists and sets identically. For example,
this code will iteratively print the elements:
<!-- L represents either an array, list or set -->
<c:forEach var="x" items="${L}" >
${x}
</c:forEach>
When using a map, the iteration generates
Map.Entry pairs. Using the
getKey and getValue functions
the structure of the JSTL code to iteratively print the
key/value pairs looks like this:
<!-- M is a map -->
<c:forEach var="x" items="${M}" >
${x.key}: ${x.value}
</c:forEach>
Other JSTL core tags
The c:set tag can be used to
initialize an EL variable directly with
<c:set var="str" value="..." />
When used on a bean
the c:set tag, along with property call the setter for that property, e.g.
The EL_BOOLEAN_EXPRESSION uses the usual
boolean operators with simplifications and additions as
mentioned above.
If-else structures are based on the
c:choose/c:when/c:otherwise tags:
To avoid JSP code sections, Java classes and functions must be
accessible through the tag system. Beans provide a limited way of
doing so with "get/set" member functions, but this does not cover all
programming needs.
The fn tags provide some utility functions, but
we must be able to extend this ourselves.
Towards this end, JSP provides a means to add your own tag libraries
using a combination of Java classes and Tag Library Definition
(TLD) files. Both XML-like tags and EL function tags can be added,
but it's much easier to create user-defined EL function tags.
The utility functions used must be static functions. For
example, suppose we want to use
the function defined in this class in an EL expression.
mytaglib/MyFunctions.java
package mytaglib;
public class MyFunctions {
public static boolean contains(java.util.Set set, String target) {
return set.contains(target);
}
public static java.util.Set keySet(java.util.Map map) {
return map.keySet();
}
}
The glue connecting this function to a tag is the
XML file mytags.tld in the /WEB-INF/ directory
WEB-INF/mytags.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0"
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 web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>mytags</short-name>
<uri>/WEB-INF/mytags</uri>
<function>
<name>keySet</name>
<function-class>mytaglib.MyFunctions</function-class>
<function-signature>
java.util.Set keySet(java.util.Map)
</function-signature>
</function>
<function>
<name>contains</name>
<function-class>mytaglib.MyFunctions</function-class>
<function-signature>
boolean contains(java.util.Set,java.lang.String)
</function-signature>
</function>
<tag>
<name>currenttime</name>
<tag-class>mytaglib.CurrentTime</tag-class>
<attribute>
<name>color</name>
<required>false</required> <!-- this is the default -->
</attribute>
<body-content>empty</body-content>
</tag>
</taglib>
This file defines a uri by which it is accessed
and a set of function
prototypes in XML format. Each function has a tag name, the class
it belongs to and the actual function prototype within this class.
The necessary specification within
the JSP file is something like this:
<%@taglib prefix="my" uri="/WEB-INF/mytags"%>
The prefix chosen specifies how the function
will be referenced within
the EL syntax it can be anything you want, so long as it
doesn't conflict with another tag set.
In this case the function will be prefaced by my:
as in this example:
An example of the usage of these two functions is presented at the
end of the document after the discussion of custom tags. The TLD file
above also contains a tag element which we'll discuss below.
We also note that NetBeans has an menu item to automatically generate
a TLD skeleton, whereas Eclipse does not appear to have one (although
there is probably some way to acquire this functionality).
Custom Tags
The heart of JSTL and other tag systems is, of course, the ability to
create XML-like tags which provide high-level programming functionality.
We'll refer to this table for the Java code needed to create such
a tag:
Tag Methods and Return Values
method
when called
return value
meaning
doStartTag()
Called once when start tag is processed. Used for initializing the
tag, and for complete tag processing.
SKIP_BODY
Body of the tag must be empty.
EVAL_BODY_INCLUDE
Body of the tag must be present and will be evaluated.
EVAL_BODY_BUFFERED
Body of the tag is output to a memory buffer to be processed later.
doInitBody()
Only for tags with body. Called once after doStartTag(), before
the body of tag is processed. Used for additional tag initializations.
void
doAfterBody()
Only for iteration/body tags. Called after body has been processed
before doEndTag().
EVAL_BODY_AGAIN
doAfterBody() will be called again
SKIP_BODY
End of processing of tag body
doEndTag()
Only for body tags. Called once
after body has been processed.
EVAL_PAGE
Evaluate the rest of the page.
SKIP_PAGE
Skip the rest of the page after this tag.
release()
Called when tag processing is finished in order to
release unused resources (which may be cached).
void
Custom tags are created and managed in two places:
A TLD file describing the custom tag and where to locate the
associated Java processing class.
The associated Java processing class which extends one of
the classes in the javax.servlet.jsp.tagext package.
The associated Java class processes the tag by activating
one or more standard methods. Keep in mind:
A tag can be represented by a pair, with start and end tags.
A tag can be complete with no end tag.
A tag can represent iteration of the body, such as the
JSTL c:forEach tag.
A tag can indicate completion of the page processing as in the
case of forward or redirect actions.
The TLD file specifies the tag element with various subelements:
<tag>
<name>XML TAG NAME</name>
<tag-class>ASSOCIATED JAVA CLASS</tag-class>
<body-content>(empty,JSP) WHAT'S IN THE BODY OF THE TAG</body-content>
<attribute>
<name>ATTRIBUTE NAME</name>
<required>(true or false) IS IT REQUIRED?</required>
<rtexprvalue>(true or false) CAN IT BE AN EL-EXPRESSION?</rtexprvalue>
<description>OPTIONAL DESCRIPTION</description>
</attribute>
</tag>
With respect to attributes, only the name element is needed. The
required and rtexprvalue attributes are false
if not present.
Sample tag
We'll create a simple tag which inserts the current timestamp
into a JSP document, possibly colorized by a color choice. The usage will be:
<mytaglib:currenttime color="SOME-COLOR" />
Observe the tag element in the mytags.tld file:
<tag>
<name>currenttime</name>
<tag-class>mytaglib.CurrentTime</tag-class>
<attribute>
<name>color</name>
<required>false</required> <!-- this is the default -->
</attribute>
<body-content>empty</body-content>
</tag>
Here is the Java support class:
mytaglib.CurrentTime
package mytaglib;
import java.io.*;
import java.util.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class CurrentTime extends TagSupport {
private String color;
public void setColor(String color) { this.color = color; }
public void release() { color = null; }
@Override
public int doStartTag() throws JspException {
JspWriter out = pageContext.getOut();
Date today = new Date();
try {
if (color == null) {
out.print(today);
} else {
out.print("<span style='color:" + color + "'>" + today + "</span>");
}
} catch (IOException x) {
throw new JspException(x.getMessage());
}
return SKIP_BODY;
}
}
Sample usage
Finally we illustrate usages of both our custom functions and our
custom tag:
custom-functions-tags.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@taglib prefix="my" uri="/WEB-INF/mytags"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<jsp:useBean id="sample" scope="request" class="bean.Sample" />
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Custom EL Functions and Tags</title>
</head>
<body>
<h1>Custom EL Functions and Tags</h1>
agenames = ${my:keySet(sample.ages)}
<br />
<c:set var="agenames" value="${my:keySet(sample.ages)}" />
agenames contains "john": ${my:contains(agenames,"john")}
<br />
agenames contains "tricia": ${my:contains(agenames,"tricia")}
<br />
<br />
<my:currenttime color="red" />
</body>
</html>