|
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. |