I'm very new to Spring and have been using Web Flow PR3 to design a fairly straightforward multi-page form based off of the 'sellitem' sample. I have run into two problems, both of which are related:
The first problem is that <spring:bind ....> tags are not being intercepted in my .jsp files, so I cannot see any errors that are generated by Web Flow. For instance the following .jsp:
then becomes the following when output to the web browser:Code:<spring:bind path="user.*"> <c:forEach items="${status.errorMessages}" var="error"> Error code: <c:out value="${error}"/><br/> </c:forEach> </spring:bind>
Code:<spring:bind path="user.*"> </spring:bind>
The second problem is that when I choose a form object that has class members that are not strings, such as a long, when SWF binds to this object, the current state (page) of the flow is returned again if the field is left blank, or un-convertable data is entered (such as a ',' for a long data field). I know that an error is returned because if I enter in a number, the flow continues to the next state (page). However, as i mentioned in my first problem, I can't see this error since <spring:bind ...> tags are not getting interpreted.
The most irritating problem is that if a field is not required, but should be something other than String, then I will have no way of ignoring empty fields! Obviously if a ',' was entered I would like to reply, but otherwise if the field is empty it should be inherently ignored.
Regardless, here's my code:
blah-servlet.xml
order-flow.xmlCode:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="java:comp/env/jdbc/TestDB" /> </bean> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation" value="WEB-INF/sqlmap-config.xml" /> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <bean name="/order/" class="org.springframework.web.flow.mvc.FlowController"> <property name="cacheSeconds" value="0"/> <property name="flow" ref="orderProcess"/> </bean> <bean id="orderProcess" class="org.springframework.web.flow.config.XmlFlowFactoryBean"> <property name="location" value="/WEB-INF/order-flow.xml"/> </bean> <bean id="orderActions" class="com.blah.web.OrderActions"> <property name="validator"> <bean class="com.blah.web.OrderValidator"/> </property> </bean> </beans>
OrderActions.javaCode:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE webflow PUBLIC "-//SPRING//DTD WEBFLOW//EN" "http://www.springframework.org/dtd/spring-webflow.dtd"> <webflow id="orderProcess" start-state="setupForm"> <action-state id="setupForm"> <action bean="orderActions"/> <transition on="success" to="orderLogin"/> </action-state> <view-state id="orderLogin" view="orderLoginForm"> <transition on="submit" to="orderPayment"> <action bean="orderActions" method="bindAndValidate"> <property name="actionState" value="orderLoginProcess"/> <property name="validatorMethod" value="validatePriceAndItemCount"/> </action> </transition> </view-state> <view-state id="orderPayment" view="orderPaymentForm"> <transition on="submit" to="orderPaymentDetail"> <action bean="orderActions" method="bindAndValidate"> <property name="actionState" value="orderPaymentProcess"/> <property name="validatorMethod" value="validatePriceAndItemCount"/> </action> </transition> </view-state> <view-state id="orderPaymentDetail" view="orderPaymentDetailForm"> <transition on="submit" to="orderConfirm"> <action bean="orderActions" method="bindAndValidate"> <property name="actionState" value="orderPaymentDetailProcess"/> <property name="validatorMethod" value="validatePriceAndItemCount"/> </action> </transition> </view-state> <view-state id="orderConfirm" view="orderConfirmForm"> <transition on="submit" to="showTicket"> <action bean="orderActions" method="bindAndValidate"> <property name="actionState" value="orderConfirmProcess"/> <property name="validatorMethod" value="validatePriceAndItemCount"/> </action> </transition> </view-state> <end-state id="showTicket" view="showTicketView"/> </webflow>
OrderValidator.javaCode:package com.blah.web; import org.springframework.web.flow.ScopeType; import org.springframework.web.flow.action.FormAction; import org.springframework.web.flow.RequestContext; import org.springframework.web.bind.RequestUtils; import org.springframework.web.flow.Event; import org.springframework.web.flow.execution.servlet.ServletEvent; public class OrderActions extends FormAction { public OrderActions() { setFormObjectName("query"); setFormObjectClass(com.blah.bus.Testtest.class); setFormObjectScope(ScopeType.FLOW); setErrorsScope(ScopeType.FLOW); } protected boolean validationEnabled(RequestContext context) { return context.getProperties().containsAttribute(VALIDATOR_METHOD_PROPERTY); } }
Code:package com.blah.web; import org.springframework.validation.Errors; import org.springframework.validation.Validator; public class OrderValidator implements Validator { public boolean supports(Class clazz) { return clazz.equals(com.blah.bus.Testtest.class); } public void validate(Object obj, Errors errors) { com.blah.bus.Testtest user = (com.blah.bus.Testtest)obj; validatePriceAndItemCount(user, errors); } public void validatePriceAndItemCount(com.blah.bus.Testtest user, Errors errors) { } }
Testtest.java
Code:package com.blah.bus; import java.io.Serializable; import java.lang.String; public class Testtest implements Serializable { private String email; private String password; private String firstName; private String lastName; private String street; private String street2; private String city; private String province; private String postcode; private String country; private Long phone; private String month; private String year; private String credit; private String paytype; private String accountholder; //private String email public void setEmail(String email) { this.email = email; } public String getEmail() { return email; } //private String password public void setPassword(String password) { this.password = password; } public String getPassword() { return password; } //private String firstName public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } //private String lastName public void setLastName(String lastName) { this.lastName = lastName; } public String getLastName() { return lastName; } //private String street public void setStreet(String street) { this.street = street; } public String getStreet() { return street; } //private String street2 public void setStreet2(String street2) { this.street2 = street2; } public String getStreet2() { return street2; } //private String city public void setCity(String city) { this.city = city; } public String getCity() { return city; } //private String province public void setProvince(String province) { this.province = province; } public String getProvince() { return province; } //private String postcode public void setPostcode(String postcode) { this.postcode = postcode; } public String getPostcode() { return postcode; } //private String country public void setCountry(String country) { this.country = country; } public String getCountry() { return country; } //private String phone public void setPhone(Long phone) { this.phone = phone; } public Long getPhone() { return phone; } //private String month public void setMonth(String month) { this.month = month; } public String getMonth() { return month; } //private String year public void setYear(String year) { this.year = year; } public String getYear() { return year; } //private String credit public void setCredit(String credit) { this.credit = credit; } public String getCredit() { return credit; } //private String paytype public void setPaytype(String paytype) { this.paytype = paytype; } public String getPaytype() { return paytype; } //private String accountholder public void setAccountholder(String accountholder) { this.accountholder = accountholder; } public String getAccountholder() { return accountholder; } }
orderLoginForm.jsp
orderPaymentForm.jspCode:<%@ include file="/WEB-INF/jsp/include.jsp" %><META HTTP-EQUIV="Pragma" CONTENT="no-cache"> <META HTTP-EQUIV="Expires" CONTENT="-1"> <html> <head><title>blah - Login</title></head> <body> <form name="login" action="" method="post"> <input type="hidden" name="_flowExecutionId" value="<c:out value="${flowExecutionId}"/>"/> <input type="hidden" name="_eventId" value="submit"/> <table width="100" border="0"> <tr> <td colspan="2"><h2>Sign In</h2></td> </tr> <tr> <td align="right" nowrap>Enter your e-mail address:</td> <td align="left"><input name="email" type="text" maxlength="64" size="30" value="" /></td> </tr> <tr> <td align="right" valign="top"><input type="radio" name="action" value="new-tmp" checked="checked" /></td> <td align="left" nowrap><b>I am a new customer.</b><br />(You'll create a password later)</td> </tr> <tr> <td align="right" valign="top"><input type="radio" name="action" value="sign-in" /></td> <td align="left"><b>I am a returning customer,<br /> and my password is:</b></td> </tr> <tr> <td align="right"></td> <td align="left"><input name="password" type="password" maxlength="20" size="30" value="" /></td> </tr> <tr> <td align="right"></td> <td align="right"><input type="submit" name="submit" value="Continue" /></td> </tr> </table> </form> </body> </html>
web.xmlCode:<%@ include file="/WEB-INF/jsp/include.jsp" %><META HTTP-EQUIV="Pragma" CONTENT="no-cache"> <META HTTP-EQUIV="Expires" CONTENT="-1"> <html> <head><title>blah - Payment</title></head> <body> <form name="login" action="" method="post"> <input type="hidden" name="_flowExecutionId" value="<c:out value="${flowExecutionId}"/>"/> <input type="hidden" name="_eventId" value="submit"/> <input type="hidden" name="email" value="<c:out value="${query.email}"/>"/> <input type="hidden" name="password" value="<c:out value="${query.password}"/>"/> <spring:bind path="user.*"> <c:forEach items="${status.errorMessages}" var="error"> Error code: <c:out value="${error}"/><br/> </c:forEach> </spring:bind> <table width="100" border="0"> <tr> <td colspan="2"><h2>Payment</h2></td> </tr> <tr> <td align="right" nowrap>Choose a payment method</td> <td align="left"><select name="paytype" size="1"> <option value="creditCard" selected>Credit Card</option> <option value="checkOrMoneyOrder">Check or Money Order</option> <option value="directDeposit">Direct Deposit</option> </select></td> </tr> <tr> <td colspan="2"><br /><br /><b>Enter a billing address for this method</b></td> </tr> <tr> <td align="right">First Name: </td> <td align="left"><input name="firstName" type="text" maxlength="40" size="40" value="" /></td> </tr> <tr> <td align="right">Last Name: </td> <td align="left"><input name="lastName" type="text" maxlength="40" size="40" value="" /></td> </tr> <tr> <td align="right">Address Line1: </td> <td align="left"><input name="street" type="text" maxlength="40" size="40" value="" /></td> </tr> <tr> <td align="right">Address Line2: </td> <td align="left"><input name="street2" type="text" maxlength="40" size="40" value="" /></td> </tr> <tr> <td align="right">City: </td> <td align="left"><input name="city" type="text" maxlength="40" size="25" value="" /></td> </tr> <tr> <td align="right">State/Province/Region: </td> <td align="left"><input name="province" type="text" maxlength="40" size="20" value="" /></td> </tr> <tr> <td align="right">ZIP/Postal Code: </td> <td align="left"><input name="postcode" type="text" maxlength="40" size="23" value="" /></td> </tr> <tr> <td align="right">Country: </td> <td align="left"><input name="country" type="text" maxlength="40" size="30" value="" /></td> </tr> <tr> <td align="right">Phone Number: </td> <td align="left"><input name="phone" type="text" maxlength="20" size="20" value="" /></td> </tr> <tr> <td align="right"></td> <td align="right"><input type="submit" name="submit" value="Continue" /></td> </tr> </table> </form> </body> </html>
Sorry for so much code, but I'd rather provide more than less.Code:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'> <web-app> <servlet> <servlet-name>blah</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>blah</servlet-name> <url-pattern>/order/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>blah</servlet-name> <url-pattern>*.blah</url-pattern> </servlet-mapping> <resource-ref> <res-ref-name>jdbc/TestDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> <welcome-file-list> <welcome-file> index.jsp </welcome-file> </welcome-file-list> <taglib> <taglib-uri>/spring</taglib-uri> <taglib-location>/WEB-INF/spring.tld</taglib-location> </taglib> </web-app>
Thanks for any help!


Reply With Quote