Thursday, August 22, 2013

Basic lesson 12:-Tag Libraries in jsp

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. If you are not using the Blazix Server, you may just want to review the material to get familiar with the syntax, and continue on to the next page.
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="user.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:setPropertyallows 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="user.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 andblx: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.  

No comments:

Post a Comment