|
Tag
libraries
JSP
1.1 introduces a method of extending JSP tags, called "tag
libraries". These libraries allow addition of tags similar
to jsp:include or jsp:forward, but with different prefixes other
than jsp: and with additional features.
To
introduce you to tag libraries, in this tutorial we use the Blazix
tag library as an example. This tag library comes bundled with the
Blazix server, which you can download free for learning and evaluation.
(The material you learn about using tag libraries will work with
any other tag libraries also.)
Each
tag-library will have its own tag-library specific documentation.
In order to use the tag library, you use the "taglib"
directive to specify where your tag library's "description"
resides. For the Blazix tag library, the (recommended) directive
is as follows
<%@
taglib prefix="blx" uri="/blx.tld" %>
The
"uri" specifies where to find the tag library description.
The "prefix" is unique for the tag library. This directive
is saying that we will be using the tags in this library by starting
them with blx:
The
Blazix tag library provides a blx:getProperty tag. This tag can
be used to allow the user to edit form data. In our GetName.jsp
file, we will now add a jsp:useBean and place the form inside blx:getProperty.
The
new GetName.jsp is
<%@
taglib prefix="blx" uri="/blx.tld" %>
<jsp:useBean id="user" class="UserData"
scope="session"/>
<HTML>
<BODY>
<blx:getProperty name="user" property="*">
<FORM METHOD=POST ACTION="SaveName.jsp">
What's your name? <INPUT TYPE=TEXT NAME=username SIZE=20><BR>
What's your e-mail address? <INPUT TYPE=TEXT NAME=email SIZE=20><BR>
What's your age? <INPUT TYPE=TEXT NAME=age SIZE=4>
<P><INPUT TYPE=SUBMIT>
</FORM>
</blx:getProperty>
</BODY>
</HTML>
Note
that the blx:getProperty doesn't end with /> but is instead terminated
by a separate </blx:getProperty> line. This puts all the form
input fields inside the blx:getProperty so they can be appropriately
modified by the tag library.
Try
putting a link to GetName.jsp from the NextPage.jsp, and you will
see that the bean's data shows up automatically in the input fields.
The
user can now edit the data.
We
still have a couple of problems. The user cannot clear out the name
field. Moreover, if the user enters a bad item in the "age"
field, something which is not a valid integer, a Java exception
occurs.
We
will use another tag from the Blazix tag library to take care of
this. Blazix offers a blx:setProperty tag that can be used to take
care of these problems. blx:setProperty allows us to define an exception
handler method. If an exception occurs, we can collect an error
message for the user and continue processing.
Following
is a version of SaveName.jsp that processes any errors, and either
shows the user GetName.jsp again to user can enter the data correctly,
or automatically forwards to NextPage.jsp.
<%@
taglib prefix="blx" uri="/blx.tld" %>
<%!
boolean haveError;
StringBuffer errors;
public void errorHandler( String field,
String value,
Exception ex )
{
haveError = true;
if ( errors == null )
errors = new StringBuffer();
else
errors.append( "<P>" );
errors.append( "<P>Value for field \"" +
field + "\" is invalid." );
if ( ex instanceof java.lang.NumberFormatException )
errors.append( " The value must be a number." );
}
%>
<%
// Variables must be initialized outside declaration!
haveError = false;
errors = null;
%>
<HTML>
<BODY>
<jsp:useBean id="user" class="UserData"
scope="session"/>
<blx:setProperty name="user"
property="*"
onError="errorHandler"/>
<%
if ( haveError ) {
out.println( errors.toString());
pageContext.include( "GetName.jsp" );
} else
pageContext.forward( "NextPage.jsp" );
%>
</BODY>
</HTML>
Note
that haveError and errors must be re-initialized each time, therefore
they are being initialized outside of the declaration.
[Also
notice the use of pageContext.include and pageContext.forward. These
are like jsp:include and jsp:forward, but are more convenient to
use from within Java blocks. pageContext is another pre-defined
variable that makes it easy to do certain operations from within
Java blocks.]
Here,
if an error occurs during the processing of blx:setProperty, we
display the error and then include the GetName.jsp again so user
can correct the error. If no errors occur, we automatically forward
the user to NextPage.jsp.
There
is still a problem with the forms, the "age" shows up
as zero initially rather than being empty. This can be fixed by
adding "emptyInt=0" to both the blx:getProperty and blx:setProperty
tags (bean fields should be initialized to 0.) It happens that "0"
is not a valid value for age, so we can use "0" to mark
empty strings. If "0" were a valid value for age, we could
have added "emptyInt=-1" (and made sure to initialize
the bean fields to -1.)
Another
small problem is that the "<HTML>" tag gets doubled
if there is an error and we end up including "GetName.jsp".
A more elegant solution is to remove the out.println, and pass back
the error as shown
<%
if ( haveError ) {
request.setAttribute( "errors",
errors.toString());
pageContext.forward( "GetName.jsp" );
} else
pageContext.forward( "NextPage.jsp" );
%>
We
can then do a "request.getAttribute" in the GetName.jsp,
and if the returned value is non-null, display the error. This is
left as an exercise.
Exercise:
Read the documentation on Blazix or another tag library, and use
some tags from this library.
Next
Tutorial: Editing forms without a
tag library
|