SWF-1419 Add ability to plug in custom Spring Validator via FlowBuilderServices to support JSR-303 validation

This commit is contained in:
Rossen Stoyanchev
2010-12-02 13:54:00 +00:00
parent 8928b6d7ff
commit df7f3406a0
57 changed files with 981 additions and 142 deletions

View File

@@ -21,12 +21,12 @@
<dependencies>
<!-- core dependencies -->
<dependency org="javax.xml.bind" name="com.springsource.javax.xml.bind" rev="2.2.0" conf="compile->runtime" />
<dependency org="com.sun.xml" name="com.springsource.com.sun.xml.bind" rev="2.2.0" conf="compile->runtime" />
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="compile->runtime"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet" rev="2.4.0" conf="provided->runtime"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp.jstl" rev="1.2.0" conf="compile->runtime"/>
<dependency org="javax.transaction" name="com.springsource.javax.transaction" rev="1.1.0" conf="compile->runtime"/>
<dependency org="javax.xml.bind" name="com.springsource.javax.xml.bind" rev="2.2.0" conf="compile->runtime" />
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="compile->runtime"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.2.6.ga" conf="compile->runtime"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations" rev="3.3.0.ga" conf="compile->runtime"/>

View File

@@ -38,17 +38,12 @@ public class Booking implements Serializable {
private Hotel hotel;
@NotNull
private Date checkinDate;
@Future
@NotNull
private Date checkoutDate;
@Pattern(regexp = "[0-9]{16}", message = "is not a 16 digit card number")
private String creditCard;
@NotEmpty
private String creditCardName;
private int creditCardExpiryMonth;
@@ -68,6 +63,7 @@ public class Booking implements Serializable {
this.hotel = hotel;
this.user = user;
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, 1);
setCheckinDate(calendar.getTime());
calendar.add(Calendar.DAY_OF_MONTH, 1);
setCheckoutDate(calendar.getTime());
@@ -99,6 +95,8 @@ public class Booking implements Serializable {
@Basic
@Temporal(TemporalType.DATE)
@Future
@NotNull
public Date getCheckinDate() {
return checkinDate;
}
@@ -127,6 +125,8 @@ public class Booking implements Serializable {
@Basic
@Temporal(TemporalType.DATE)
@Future
@NotNull
public Date getCheckoutDate() {
return checkoutDate;
}
@@ -135,6 +135,7 @@ public class Booking implements Serializable {
this.checkoutDate = checkoutDate;
}
@Pattern(regexp = "[0-9]{16}", message = "{invalidCreditCardPattern}")
public String getCreditCard() {
return creditCard;
}
@@ -166,6 +167,7 @@ public class Booking implements Serializable {
this.beds = beds;
}
@NotEmpty
public String getCreditCardName() {
return creditCardName;
}
@@ -202,11 +204,11 @@ public class Booking implements Serializable {
public void validateEnterBookingDetails(ValidationContext context) {
MessageContext messages = context.getMessageContext();
if (checkinDate.before(today())) {
messages.addMessage(new MessageBuilder().error().source("checkinDate").code(
"booking.checkinDate.beforeToday").build());
messages.addMessage(new MessageBuilder().error().source("checkinDate")
.code("booking.checkinDate.beforeToday").build());
} else if (checkoutDate.before(checkinDate)) {
messages.addMessage(new MessageBuilder().error().source("checkoutDate").code(
"booking.checkoutDate.beforeCheckinDate").build());
messages.addMessage(new MessageBuilder().error().source("checkoutDate")
.code("booking.checkoutDate.beforeCheckinDate").build());
}
}

View File

@@ -0,0 +1,2 @@
# Custom messages for JSR-303 validation
invalidCreditCardPattern=is not a valid 16 digit card number.

View File

@@ -4,9 +4,9 @@
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- Instructs Spring to perfrom declarative transaction management on annotated classes -->
<tx:annotation-driven />

View File

@@ -4,9 +4,9 @@
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- Configure Spring Security -->
<security:http auto-config="true" use-expressions="true">

View File

@@ -4,9 +4,9 @@
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Scans for application @Components to deploy -->
<context:component-scan base-package="org.springframework.webflow.samples.booking" />

View File

@@ -4,12 +4,12 @@
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns:faces="http://www.springframework.org/schema/faces"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces-2.0.xsd">
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd
http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces.xsd">
<!-- Executes flows: the central entry point into the Spring Web Flow system -->
<webflow:flow-executor id="flowExecutor">
<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="facesContextListener"/>
<webflow:listener ref="jpaFlowExecutionListener" />

View File

@@ -3,8 +3,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:faces="http://www.springframework.org/schema/faces"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces-2.0.xsd">
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces.xsd">
<faces:resources />

View File

@@ -27,7 +27,7 @@
<h:selectOneMenu id="pageSize" value="#{searchCriteria.pageSize}">
<f:selectItems value="#{referenceData.pageSizeOptions}" />
</h:selectOneMenu>
<p:commandButton id="findHotels" value="Find Hotels" action="search" update="@form" />
<p:commandButton id="findHotels" value="Find Hotels" action="search" update="@form" ajax="false" />
</h:panelGrid>
<p:tooltip for="searchString" targetPosition="topRight" position="bottomLeft"
value="Search hotels by name, address, city, or zip." style="cream" />

View File

@@ -26,6 +26,7 @@
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp" rev="2.1.0" conf="provided->runtime"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp.jstl" rev="1.1.2" conf="compile->runtime"/>
<dependency org="javax.transaction" name="com.springsource.javax.transaction" rev="1.1.0" conf="compile->runtime"/>
<dependency org="javax.xml.bind" name="com.springsource.javax.xml.bind" rev="2.2.0" conf="compile->runtime" />
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="compile->runtime"/>
<dependency org="org.apache.taglibs" name="com.springsource.org.apache.taglibs.standard" rev="1.1.2" conf="compile->runtime"/>
<dependency org="org.apache.tiles" name="com.springsource.org.apache.tiles" rev="2.1.2.osgi" conf="compile->runtime"/>
@@ -35,8 +36,10 @@
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.2.6.ga" conf="compile->runtime"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations" rev="3.3.0.ga" conf="compile->runtime"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.ejb" rev="3.3.1.ga" conf="compile->runtime"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.validator" rev="4.1.0.GA" conf="compile->runtime" />
<dependency org="org.hsqldb" name="com.springsource.org.hsqldb" rev="1.8.0.9" conf="compile->runtime"/>
<dependency org="org.joda" name="com.springsource.org.joda.time" rev="1.6.0" conf="compile->runtime"/>
<dependency org="org.slf4j" name="com.springsource.slf4j.log4j" rev="1.5.6" />
<dependency org="org.springframework" name="org.springframework.aop" rev="3.0.4.RELEASE" conf="compile->runtime"/>
<dependency org="org.springframework" name="org.springframework.beans" rev="3.0.4.RELEASE" conf="compile->runtime"/>
<dependency org="org.springframework" name="org.springframework.context" rev="3.0.4.RELEASE" conf="compile->runtime"/>

View File

@@ -157,6 +157,27 @@
<artifactId>org.springframework.webflow</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Bean Validation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>com.springsource.org.hibernate.validator</artifactId>
<version>4.1.0.GA</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>com.springsource.slf4j.log4j</artifactId>
<version>1.5.6</version>
</dependency>
<!--
JAXB is needed when running on Java 5. In this environment these dependencies have to be added
(unless xml configuration is explicitly disabled via Configuration.ignoreXmlConfiguration)
On Java 6 jaxb is part of the runtime environment.
-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>com.springsource.javax.xml.bind</artifactId>
<version>2.2.0</version>
</dependency>
<!-- Build time only dependencies -->
<dependency>
<groupId>javax.servlet</groupId>

View File

@@ -16,17 +16,19 @@ import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotNull;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.binding.validation.ValidationContext;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
/**
* A Hotel Booking made by a User.
*/
@Entity
@BookingDateRange
public class Booking implements Serializable {
private Long id;
private User user;
@@ -55,6 +57,7 @@ public class Booking implements Serializable {
public Booking() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, 1);
setCheckinDate(calendar.getTime());
calendar.add(Calendar.DAY_OF_MONTH, 1);
setCheckoutDate(calendar.getTime());
@@ -92,6 +95,8 @@ public class Booking implements Serializable {
@Basic
@Temporal(TemporalType.DATE)
@NotNull
@Future
public Date getCheckinDate() {
return checkinDate;
}
@@ -120,6 +125,8 @@ public class Booking implements Serializable {
@Basic
@Temporal(TemporalType.DATE)
@NotNull
@Future
public Date getCheckoutDate() {
return checkoutDate;
}
@@ -128,6 +135,7 @@ public class Booking implements Serializable {
this.checkoutDate = checkoutDate;
}
@NotEmpty
public String getCreditCard() {
return creditCard;
}
@@ -159,6 +167,7 @@ public class Booking implements Serializable {
this.beds = beds;
}
@NotEmpty
public String getCreditCardName() {
return creditCardName;
}
@@ -192,17 +201,6 @@ public class Booking implements Serializable {
this.amenities = amenities;
}
public void validateEnterBookingDetails(ValidationContext context) {
MessageContext messages = context.getMessageContext();
if (checkinDate.before(today())) {
messages.addMessage(new MessageBuilder().error().source("checkinDate").code(
"booking.checkinDate.beforeToday").build());
} else if (checkoutDate.before(checkinDate)) {
messages.addMessage(new MessageBuilder().error().source("checkoutDate").code(
"booking.checkoutDate.beforeCheckinDate").build());
}
}
private Date today() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, -1);

View File

@@ -0,0 +1,22 @@
package org.springframework.webflow.samples.booking;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Constraint(validatedBy = BookingDateRangeValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface BookingDateRange {
String message() default "Invalid check-in and check-out date range";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,19 @@
package org.springframework.webflow.samples.booking;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class BookingDateRangeValidator implements ConstraintValidator<BookingDateRange, Booking> {
public void initialize(BookingDateRange bookingDateRange) {
}
public boolean isValid(Booking booking, ConstraintValidatorContext context) {
if ((booking.getCheckinDate() != null) && (booking.getCheckoutDate() != null)
&& booking.getCheckoutDate().before(booking.getCheckinDate())) {
return false;
}
return true;
}
}

View File

@@ -21,9 +21,14 @@
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<value>
hibernate.session_factory_name=mySessionFactory
</value>
</property>
</bean>
</bean>
<!-- Deploys a in-memory "booking" datasource populated -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />

View File

@@ -4,9 +4,9 @@
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd">
<!-- Executes flows: the entry point into the Spring Web Flow system -->
<webflow:flow-executor id="flowExecutor">
@@ -22,7 +22,8 @@
</webflow:flow-registry>
<!-- Plugs in a custom creator for Web Flow views -->
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" development="true" />
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"
development="true" validator="validator" />
<!-- Configures Web Flow to use Tiles to create views for rendering; Tiles allows for applying consistent layouts to your views -->
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
@@ -38,5 +39,8 @@
<!-- Installs a listener to apply Spring Security authorities -->
<bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
<!-- Bootstraps JSR-303 validation and adapts it to Spring's Validator interface -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</beans>

View File

@@ -15,15 +15,15 @@
<view-state id="enterBookingDetails" model="booking">
<binder>
<binding property="checkinDate" required="true" />
<binding property="checkoutDate" required="true" />
<binding property="beds" required="true" />
<binding property="smoking" required="true" />
<binding property="creditCard" required="true" />
<binding property="creditCardName" required="true" />
<binding property="creditCardExpiryMonth" required="true" />
<binding property="creditCardExpiryYear" required="true" />
<binding property="amenities" required="false" />
<binding property="checkinDate" />
<binding property="checkoutDate" />
<binding property="beds" />
<binding property="smoking" />
<binding property="creditCard" />
<binding property="creditCardName" />
<binding property="creditCardExpiryMonth" />
<binding property="creditCardExpiryYear" />
<binding property="amenities" />
</binder>
<transition on="proceed" to="reviewBooking" />
<transition on="cancel" to="cancel" bind="false" />

View File

@@ -22,7 +22,7 @@
<div class="error">
<spring:bind path="booking.*">
<c:forEach items="${status.errorMessages}" var="error">
<c:out value="${error}"/><br>
<span><c:out value="${error}"/></span><br>
</c:forEach>
</spring:bind>
</div>

View File

@@ -1,12 +1,16 @@
booking.checkinDate.required=The check in date is required
booking.checkinDate.typeMismatch=The check in date must be in the format mm-dd-yyyy
booking.checkinDate.NotNull=The check in date is required
booking.checkinDate.Future=The check in date must be in the future
booking.checkinDate.beforeToday=The check in date must be a future date
booking.checkinDate.typeMismatch=The check in date must be in the format mm-dd-yyyy
booking.checkoutDate.required=The check out date is required
booking.checkoutDate.Future=The check out date must be in the future
booking.checkoutDate.NotNull=The check out date is required
booking.checkoutDate.typeMismatch=The check out date must be in the format mm-dd-yyyy
booking.checkoutDate.beforeCheckinDate=The check out date must be later than the check in date
booking.BookingDateRange=The check out date must be later than the check in date
booking.creditCard.required=The credit card must be a valid 16 digit number
booking.creditCardName.required=The name on the credit card is required
booking.creditCard.NotEmpty=The credit card must be a valid 16 digit number
booking.creditCardName.NotEmpty=The name on the credit card is required
required=The {0} field is required
NotEmpty=The {0} field is required
NotNull=The {0} field is required
Future=The {0} date must be in the future

View File

@@ -5,11 +5,11 @@
xmlns:faces="http://www.springframework.org/schema/faces"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd
http://www.springframework.org/schema/faces
http://www.springframework.org/schema/faces/spring-faces-2.0.xsd">
http://www.springframework.org/schema/faces/spring-faces.xsd">
<!-- Maps portlet modes to handlers -->
<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">

View File

@@ -26,14 +26,17 @@
<dependency org="javax.servlet" name="com.springsource.javax.servlet" rev="2.4.0" conf="provided->compile"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp.jstl" rev="1.1.2" conf="compile->compile"/>
<dependency org="javax.transaction" name="com.springsource.javax.transaction" rev="1.1.0" conf="compile->compile"/>
<dependency org="javax.xml.bind" name="com.springsource.javax.xml.bind" rev="2.2.0" conf="compile->runtime" />
<dependency org="org.aopalliance" name="com.springsource.org.aopalliance" rev="1.0.0" conf="compile->compile"/>
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="compile->compile"/>
<dependency org="org.apache.taglibs" name="com.springsource.org.apache.taglibs.standard" rev="1.1.2" conf="compile->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.2.6.ga" conf="compile->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations" rev="3.3.0.ga" conf="compile->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.ejb" rev="3.3.1.ga" conf="compile->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.validator" rev="4.1.0.GA" conf="compile->runtime" />
<dependency org="org.hsqldb" name="com.springsource.org.hsqldb" rev="1.8.0.9" conf="compile->compile"/>
<dependency org="org.joda" name="com.springsource.org.joda.time" rev="1.6.0" conf="compile->runtime"/>
<dependency org="org.slf4j" name="com.springsource.slf4j.log4j" rev="1.5.6" />
<dependency org="org.springframework" name="org.springframework.aop" rev="3.0.4.RELEASE" conf="compile->compile"/>
<dependency org="org.springframework" name="org.springframework.beans" rev="3.0.4.RELEASE" conf="compile->compile"/>
<dependency org="org.springframework" name="org.springframework.context" rev="3.0.4.RELEASE" conf="compile->compile"/>

View File

@@ -117,6 +117,27 @@
<artifactId>org.springframework.webflow</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Bean Validation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>com.springsource.org.hibernate.validator</artifactId>
<version>4.1.0.GA</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>com.springsource.slf4j.log4j</artifactId>
<version>1.5.6</version>
</dependency>
<!--
JAXB is needed when running on Java 5. In this environment these dependencies have to be added
(unless xml configuration is explicitly disabled via Configuration.ignoreXmlConfiguration)
On Java 6 jaxb is part of the runtime environment.
-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>com.springsource.javax.xml.bind</artifactId>
<version>2.2.0</version>
</dependency>
<!-- build time only dependencies -->
<dependency>
<groupId>javax.portlet</groupId>

View File

@@ -15,13 +15,17 @@ import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
/**
* A Hotel Booking made by a User.
*/
@Entity
@BookingDateRange
public class Booking implements Serializable {
private Long id;
@@ -49,6 +53,7 @@ public class Booking implements Serializable {
public Booking() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, 1);
setCheckinDate(calendar.getTime());
calendar.add(Calendar.DAY_OF_MONTH, 1);
setCheckoutDate(calendar.getTime());
@@ -82,6 +87,8 @@ public class Booking implements Serializable {
@Basic
@Temporal(TemporalType.DATE)
@NotNull
@Future
public Date getCheckinDate() {
return checkinDate;
}
@@ -110,6 +117,8 @@ public class Booking implements Serializable {
@Basic
@Temporal(TemporalType.DATE)
@NotNull
@Future
public Date getCheckoutDate() {
return checkoutDate;
}
@@ -118,6 +127,7 @@ public class Booking implements Serializable {
this.checkoutDate = checkoutDate;
}
@NotEmpty
public String getCreditCard() {
return creditCard;
}
@@ -149,6 +159,7 @@ public class Booking implements Serializable {
this.beds = beds;
}
@NotEmpty
public String getCreditCardName() {
return creditCardName;
}

View File

@@ -0,0 +1,22 @@
package org.springframework.webflow.samples.booking;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Constraint(validatedBy = BookingDateRangeValidator.class)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface BookingDateRange {
String message() default "Invalid check-in and check-out date range";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,19 @@
package org.springframework.webflow.samples.booking;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class BookingDateRangeValidator implements ConstraintValidator<BookingDateRange, Booking> {
public void initialize(BookingDateRange bookingDateRange) {
}
public boolean isValid(Booking booking, ConstraintValidatorContext context) {
if ((booking.getCheckinDate() != null) && (booking.getCheckoutDate() != null)
&& booking.getCheckoutDate().before(booking.getCheckinDate())) {
return false;
}
return true;
}
}

View File

@@ -5,11 +5,11 @@
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- Activates annotation-based bean configuration -->
<context:annotation-config />

View File

@@ -4,9 +4,9 @@
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd">
<!-- Maps portlet modes to handlers -->
<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
@@ -38,11 +38,14 @@
</webflow:flow-executor>
<!-- The registry of executable flow definitions -->
<webflow:flow-registry id="flowRegistry">
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<webflow:flow-location path="/WEB-INF/flows/view/view.xml" />
<webflow:flow-location path="/WEB-INF/flows/main/main.xml" />
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>
<!-- Plugs in Spring's JSR-303 validator adapter -->
<webflow:flow-builder-services id="flowBuilderServices" development="true" validator="validator" />
<!-- Installs a listener that manages JPA persistence contexts for flows that require them -->
<bean id="jpaFlowExecutionListener" class="org.springframework.webflow.persistence.JpaFlowExecutionListener">
@@ -50,4 +53,7 @@
<constructor-arg ref="transactionManager" />
</bean>
<!-- Bootstraps JSR-303 validation and adapts it to Spring's Validator interface -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</beans>

View File

@@ -9,8 +9,16 @@
<portlet:param name="execution" value="${flowExecutionKey}" />
</portlet:actionURL>
<form:form id="booking" modelAttribute="booking" action="${actionUrl}">
<form:errors path="*" cssClass="errors" />
<fieldset>
<spring:hasBindErrors name="booking">
<div class="error">
<spring:bind path="booking.*">
<c:forEach items="${status.errorMessages}" var="error">
<span><c:out value="${error}"/></span><br>
</c:forEach>
</spring:bind>
</div>
</spring:hasBindErrors>
<fieldset>
<table>
<tr class="field">
<td class="label">Name:</td>

View File

@@ -0,0 +1,16 @@
booking.checkinDate.NotNull=The check in date is required
booking.checkinDate.Future=The check in date must be in the future
booking.checkinDate.beforeToday=The check in date must be a future date
booking.checkinDate.typeMismatch=The check in date must be in the format mm-dd-yyyy
booking.checkoutDate.Future=The check out date must be in the future
booking.checkoutDate.NotNull=The check out date is required
booking.checkoutDate.typeMismatch=The check out date must be in the format mm-dd-yyyy
booking.BookingDateRange=The check out date must be later than the check in date
booking.creditCard.NotEmpty=The credit card must be a valid 16 digit number
booking.creditCardName.NotEmpty=The name on the credit card is required
NotEmpty=The {0} field is required
NotNull=The {0} field is required
Future=The {0} date must be in the future