├── .gitignore ├── README.md ├── build.gradle └── src └── main ├── java └── com │ └── codetutr │ ├── controller │ └── FormController.java │ ├── form │ └── Subscriber.java │ ├── springconfig │ └── WebConfig.java │ └── validator │ ├── Phone.java │ ├── PhoneConstraintValidator.java │ ├── Year.java │ └── YearConstraintValidator.java ├── resources └── messages.properties └── webapp └── WEB-INF ├── view └── formPage.jsp └── web.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | bin 3 | build 4 | .settings 5 | .gradle 6 | .classpath 7 | .project -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Spring MVC Validation 2 | ===================== 3 | 4 | Spring MVC validation example using JSR-303 annotations and custom validation annotations 5 | 6 | This repo is a companion to my [Spring MVC Form Validation Tutorial](http://codetutr.com/2013/05/28/spring-mvc-form-validation/) 7 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'war' 2 | apply plugin: 'jetty' 3 | apply plugin: 'eclipse-wtp' 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | providedCompile 'javax.servlet:servlet-api:2.5' 11 | compile 'org.springframework:spring-webmvc:3.2.2.RELEASE' 12 | compile 'javax.validation:validation-api:1.1.0.Final' 13 | compile 'org.hibernate:hibernate-validator:5.0.1.Final' 14 | compile 'org.slf4j:slf4j-api:1.7.5' 15 | runtime 'javax.servlet:jstl:1.2' 16 | } 17 | 18 | /* Change context path (base url). otherwise defaults to name of project */ 19 | // eclipse.wtp.component.contextPath = '' 20 | jettyRunWar.contextPath = '' -------------------------------------------------------------------------------- /src/main/java/com/codetutr/controller/FormController.java: -------------------------------------------------------------------------------- 1 | package com.codetutr.controller; 2 | 3 | import javax.validation.Valid; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.validation.BindingResult; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestMethod; 10 | 11 | import com.codetutr.form.Subscriber; 12 | 13 | @Controller 14 | public class FormController { 15 | 16 | 17 | @RequestMapping(value="/", method=RequestMethod.GET) 18 | public String loadFormPage(Model m) { 19 | m.addAttribute("subscriber", new Subscriber()); 20 | return "formPage"; 21 | } 22 | 23 | @RequestMapping(value="/", method=RequestMethod.POST) 24 | public String submitForm(@Valid Subscriber subscriber, BindingResult result, Model m) { 25 | if(result.hasErrors()) { 26 | return "formPage"; 27 | } 28 | 29 | m.addAttribute("message", "Successfully saved person: " + subscriber.toString()); 30 | return "formPage"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/codetutr/form/Subscriber.java: -------------------------------------------------------------------------------- 1 | package com.codetutr.form; 2 | 3 | import java.util.Date; 4 | 5 | import javax.validation.constraints.Max; 6 | import javax.validation.constraints.Min; 7 | import javax.validation.constraints.NotNull; 8 | import javax.validation.constraints.Past; 9 | import javax.validation.constraints.Size; 10 | 11 | import org.hibernate.validator.constraints.Email; 12 | import org.hibernate.validator.constraints.NotEmpty; 13 | import org.springframework.format.annotation.DateTimeFormat; 14 | 15 | import com.codetutr.validator.Phone; 16 | import com.codetutr.validator.Year; 17 | 18 | public class Subscriber { 19 | 20 | @Size(min=2, max=30) 21 | private String name; 22 | 23 | @NotEmpty @Email 24 | private String email; 25 | 26 | @NotNull @Min(13) @Max(110) 27 | private Integer age; 28 | 29 | @Size(min=10) @Phone 30 | private String phone; 31 | 32 | @NotNull 33 | private Gender gender; 34 | 35 | @DateTimeFormat(pattern="MM/dd/yyyy") 36 | @NotNull @Past @Year(1989) 37 | private Date birthday; 38 | 39 | private Boolean receiveNewsletter; 40 | 41 | public enum Gender { 42 | MALE, FEMALE 43 | } 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | 53 | public String getEmail() { 54 | return email; 55 | } 56 | 57 | public void setEmail(String email) { 58 | this.email = email; 59 | } 60 | 61 | public Integer getAge() { 62 | return age; 63 | } 64 | 65 | public void setAge(Integer age) { 66 | this.age = age; 67 | } 68 | 69 | public String getPhone() { 70 | return phone; 71 | } 72 | 73 | public void setPhone(String phone) { 74 | this.phone = phone; 75 | } 76 | 77 | public Gender getGender() { 78 | return gender; 79 | } 80 | 81 | public void setGender(Gender gender) { 82 | this.gender = gender; 83 | } 84 | 85 | public Date getBirthday() { 86 | return birthday; 87 | } 88 | 89 | public void setBirthday(Date birthday) { 90 | this.birthday = birthday; 91 | } 92 | 93 | public Boolean getReceiveNewsletter() { 94 | return receiveNewsletter; 95 | } 96 | 97 | public void setReceiveNewsletter(Boolean receiveNewsletter) { 98 | this.receiveNewsletter = receiveNewsletter; 99 | } 100 | 101 | @Override 102 | public String toString() { 103 | return "Subscriber [name=" + name + ", email=" + email + ", age=" + age 104 | + ", phone=" + phone + ", gender=" + gender + ", birthday=" 105 | + birthday + ", receiveNewsletter=" + receiveNewsletter + "]"; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/codetutr/springconfig/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.codetutr.springconfig; 2 | 3 | import org.springframework.context.MessageSource; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.support.ResourceBundleMessageSource; 8 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 9 | import org.springframework.web.servlet.view.InternalResourceViewResolver; 10 | 11 | @Configuration 12 | @EnableWebMvc 13 | @ComponentScan(basePackages="com.codetutr") 14 | public class WebConfig { 15 | 16 | @Bean 17 | public InternalResourceViewResolver viewResolver() { 18 | InternalResourceViewResolver resolver = new InternalResourceViewResolver(); 19 | resolver.setPrefix("/WEB-INF/view/"); 20 | resolver.setSuffix(".jsp"); 21 | return resolver; 22 | } 23 | 24 | @Bean 25 | public MessageSource messageSource() { 26 | ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); 27 | messageSource.setBasename("messages"); 28 | return messageSource; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/codetutr/validator/Phone.java: -------------------------------------------------------------------------------- 1 | package com.codetutr.validator; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import javax.validation.Constraint; 10 | import javax.validation.Payload; 11 | 12 | @Documented 13 | @Constraint(validatedBy = PhoneConstraintValidator.class) 14 | @Target( { ElementType.METHOD, ElementType.FIELD }) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Phone { 17 | 18 | 19 | String message() default "{Phone}"; 20 | 21 | Class[] groups() default {}; 22 | 23 | Class[] payload() default {}; 24 | 25 | } -------------------------------------------------------------------------------- /src/main/java/com/codetutr/validator/PhoneConstraintValidator.java: -------------------------------------------------------------------------------- 1 | package com.codetutr.validator; 2 | 3 | import javax.validation.ConstraintValidator; 4 | import javax.validation.ConstraintValidatorContext; 5 | 6 | public class PhoneConstraintValidator implements ConstraintValidator { 7 | 8 | 9 | @Override 10 | public void initialize(Phone String) { } 11 | 12 | @Override 13 | public boolean isValid(String phoneField, ConstraintValidatorContext cxt) { 14 | if(phoneField == null) { 15 | return false; 16 | } 17 | return phoneField.matches("[0-9()-]*"); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/codetutr/validator/Year.java: -------------------------------------------------------------------------------- 1 | package com.codetutr.validator; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import javax.validation.Constraint; 10 | import javax.validation.Payload; 11 | 12 | import com.codetutr.validator.YearConstraintValidator; 13 | 14 | @Documented 15 | @Constraint(validatedBy = YearConstraintValidator.class) 16 | @Target( { ElementType.METHOD, ElementType.FIELD }) 17 | @Retention(RetentionPolicy.RUNTIME) 18 | public @interface Year { 19 | 20 | int value(); 21 | 22 | String message() default "{Year}"; 23 | 24 | Class[] groups() default {}; 25 | 26 | Class[] payload() default {}; 27 | 28 | } -------------------------------------------------------------------------------- /src/main/java/com/codetutr/validator/YearConstraintValidator.java: -------------------------------------------------------------------------------- 1 | package com.codetutr.validator; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | import javax.validation.ConstraintValidator; 7 | import javax.validation.ConstraintValidatorContext; 8 | 9 | import com.codetutr.validator.Year; 10 | 11 | public class YearConstraintValidator implements ConstraintValidator { 12 | 13 | private int annotationYear; 14 | 15 | @Override 16 | public void initialize(Year year) { 17 | this.annotationYear = year.value(); 18 | } 19 | 20 | @Override 21 | public boolean isValid(Date target, ConstraintValidatorContext cxt) { 22 | if(target == null) { 23 | return true; 24 | } 25 | Calendar c = Calendar.getInstance(); 26 | c.setTime(target); 27 | int fieldYear = c.get(Calendar.YEAR); 28 | return fieldYear == annotationYear; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | Size=the {0} field must be between {2} and {1} characters long 2 | Size.subscriber.name=Name must be between {2} and {1} characters 3 | Size.subscriber.phone=Phone must be at least {2} characters 4 | 5 | Min.subscriber.age=You must be older than {1} 6 | Max.subscriber.age= Sorry, you have to be younger than {1} 7 | 8 | Email=Email address not valid 9 | Past=Date must be in the past 10 | 11 | Year=Year must be 1989 12 | Phone=Invalid characters in phone number 13 | NotEmpty=Field cannot be left blank 14 | NotNull=Field cannot be left blank 15 | 16 | typeMismatch=Invalid format 17 | methodInvocation.myRequest.amount=Invalid format -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/view/formPage.jsp: -------------------------------------------------------------------------------- 1 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> 3 | 4 | 5 | 6 | 7 | Sample Form 8 | 9 | 20 | 21 | 22 | 23 |
24 | 25 |

Subscribe to The Newsletter!

26 |
${message}
27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 | 56 | Select Gender 57 | Male 58 | Female 59 | 60 | 61 |
62 | 63 | 64 | 65 | 66 |
67 | 68 | 69 |
70 | 71 |
72 |
73 | 74 | 75 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | sample 8 | 9 | org.springframework.web.servlet.DispatcherServlet 10 | 11 | 12 | contextClass 13 | org.springframework.web.context.support.AnnotationConfigWebApplicationContext 14 | 15 | 16 | contextConfigLocation 17 | com.codetutr.springconfig 18 | 19 | 20 | 21 | 22 | sample 23 | / 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------