| [ Team LiB ] |
|
12.2 Validating Complex Input Without a BeanBefore we look at the two remaining database sections, let's go back and take a look at the two application pages we skipped earlier, namely the enter.jsp and validate.jsp pages used for input to the employee registration. In Chapter 8, I introduced you to validation of user input using the JSTL <c:if> action as well as using an application-specific bean. The bean contains all validation code and can therefore validate the format of complex data, such as date strings, email addresses, and credit-card numbers. This is the approach I recommend, but if you're developing a JSP-based application without access to a Java programmer to develop the beans you need, I'll show you a trick you can use to validate dates and a custom action for email-address validation. The validate.jsp page uses the JSTL <c:if> action and the custom action to validate all user input. If an input parameter isn't valid, an error message is saved in a variable, and the request is forwarded back to the enter.jsp page. The enter.jsp page adds all the error messages to the response, so to the user, the result is identical to the bean-based validation approach you saw in Chapter 8. Let's look at validate.jsp first, shown in Example 12-8. Example 12-8. Validation with application beans (validate.jsp)<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="ora" uri="orataglib" %> <c:set var="isValid" value="true" /> <c:if test="${empty param.userName}"> <c:set var="userNameError" scope="request" value="User Name missing" /> <c:set var="isValid" value="false" /> </c:if> <c:if test="${empty param.password}"> <c:set var="passwordError" scope="request" value="Password missing" /> <c:set var="isValid" value="false" /> </c:if> <c:if test="${empty param.firstName}"> <c:set var="firstNameError" scope="request" value="First Name missing" /> <c:set var="isValid" value="false" /> </c:if> <c:if test="${empty param.lastName}"> <c:set var="lastNameError" scope="request" value="Last Name missing" /> <c:set var="isValid" value="false" /> </c:if> <c:if test="${empty param.dept}"> <c:set var="deptError" scope="request" value="Department missing" /> <c:set var="isValid" value="false" /> </c:if> <%-- Validate date by catching a possible exception --%> <c:catch var="invalidDate"> <fmt:parseDate value="${param.empDate}" pattern="yyyy-MM-dd" var="ignore" /> </c:catch> <c:choose> <c:when test="${empty param.empDate}"> <c:set var="empDateError" scope="request" value="Employment Date missing" /> <c:set var="isValid" value="false" /> </c:when> <c:when test="${invalidDate != null}"> <c:set var="empDateError" scope="request" value="Invalid Employment Date" /> <c:set var="isValid" value="false" /> </c:when> </c:choose> <%-- Validate email address format using custom action --%> <ora:ifValidEmailAddr value="${param.emailAddr}" var="isValidEmailAddr" /> <c:choose> <c:when test="${empty param.emailAddr}"> <c:set var="emailAddrError" scope="request" value="Email Address missing" /> <c:set var="isValid" value="false" /> </c:when> <c:when test="${!isValidEmailAddr}"> <c:set var="emailAddrError" scope="request" value="Invalid Email Address" /> <c:set var="isValid" value="false" /> </c:when> </c:choose> <c:choose> <c:when test="${isValid}"> <jsp:forward page="store.jsp" /> </c:when> <c:otherwise> <jsp:forward page="enter.jsp" /> </c:otherwise> </c:choose> At the top of Example 12-8, a <c:set> action creates a variable named isValid with the value true. The rest of the page validates each parameter value and sets this variable to false if any value is found to be invalid. This makes it easy to decide which page to forward to at the end of the page. In addition, if any value is invalid, another parameter-specific variable is created in the request scope to hold the error message. As you will see later, these error messages are added to the input page to tell the user what's wrong. For most parameters, a simple <c:if> action that tests that some value is submitted is all that's needed. But for the empDate and emailAddr parameters, any old value isn't enough. Verifying that a parameter value represents a real date is tricky, since there are so many different ways to write a date. In addition, you need to keep track of leap years and, as you will see in Chapter 14, possibly deal with dates written in different languages as well. Luckily, there's a JSTL action that knows all these rules: the <fmt:parseDate> used in Example 12-1. If it's passed a date string that doesn't check out, it throws an exception. Combined with the <c:catch> action introduced in Chapter 9, this is all we need to validate a date. The <fmt:parseDate> action is placed within a <c:catch> action element, catching and saving a possible exception in a variable named invalidDate. A <c:choose> action then uses one <c: when> action to test if a date string is supplied at all and, if it is, tests if the <fmt:parseDate> action threw an exception with a second <c:when> action. I could have used just a <c:if> action to test if an exception was thrown, but the approach used here lets me provide different error messages for no value and an invalid value. The email address is validated with a custom action named <ora:ifValidEmailAddr>, described in Table 12-8.
The action can be used with a body that's evaluated only if the value has a valid email-address format (contains only one at sign and at least one dot, e.g., "hans@gefionsoftware.com"), just like the <c:if> action. Here the result is saved in a variable instead and used in a <c:choose> block to test for both no value and invalid value, the same as is done for the date value. If the request is forwarded back to the enter.jsp page due to invalid input, the values the user entered are used as the default values for the form fields and the error messages are displayed next to each field. Example 12-9 shows a part of the page for the User Name field. Example 12-9. Displaying error messages (enter.jsp)...
<tr>
<td>User Name:</td>
<td><input type="text" name="userName"
value="${fn:escapeXml(param.userName)}">
</td>
<td>${fn:escapeXml(userNameError)}</td>
</tr>
...
The first EL expression sets the value of the input field to the corresponding parameter value. The second EL expression uses the userNameError variable created by the validate.jsp page if the userName parameter value is invalid and adds the message to the page. The results are shown in Figure 12-8. Figure 12-8. The input page with error messages![]() This is very similar to the examples in Chapter 8. The difference is that a separate page does the validation, creating all error messages as request scope variables that are then used in the input page if they exist, instead of conditionally adding error messages defined in the input page. Which approach is best is a matter of preference. |
| [ Team LiB ] |
|