From e7e6326a0034fd40a5bc43ac5d35a00d5371cab7 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Mar 2017 13:57:34 -0400 Subject: [PATCH 1/2] Spring MVC Custom Validator --- spring-mvc-java/pom.xml | 23 ++++++++++- .../ContactNumberConstraint.java | 22 ++++++++++ .../ContactNumberValidator.java | 19 +++++++++ .../com/baeldung/model/ValidatedPhone.java | 18 ++++++++ .../controller/ValidatedPhoneController.java | 35 ++++++++++++++++ .../src/main/webapp/WEB-INF/mvc-servlet.xml | 16 ++++++-- .../main/webapp/WEB-INF/view/phoneHome.jsp | 38 +++++++++++++++++ .../controller/CustomMVCValidatorTest.java | 41 +++++++++++++++++++ 8 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java create mode 100644 spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java create mode 100644 spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java create mode 100644 spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java create mode 100644 spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp create mode 100644 spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index ef18cef3e0..0f6dbfbd98 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -166,7 +166,28 @@ poi-ooxml ${poi.version} - + + + + javax.validation + validation-api + 1.1.0.Final + + + org.hibernate + hibernate-validator + 5.1.2.Final + + + javax.el + javax.el-api + 2.2.4 + + + org.glassfish.web + javax.el + 2.2.4 + diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java new file mode 100644 index 0000000000..2fba2720c3 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java @@ -0,0 +1,22 @@ +package com.baeldung.customvalidator; + +import java.lang.annotation.Documented; +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; + +@Documented +@Constraint(validatedBy = ContactNumberValidator.class) +@Target( { ElementType.METHOD, ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ContactNumberConstraint { + + String message() default "Invalid phone number"; + Class[] groups() default {}; + Class[] payload() default {}; + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java new file mode 100644 index 0000000000..a7eb7a9df4 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java @@ -0,0 +1,19 @@ +package com.baeldung.customvalidator; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class ContactNumberValidator implements ConstraintValidator { + + @Override + public void initialize(ContactNumberConstraint contactNumber) {} + + @Override + public boolean isValid(String contactField, ConstraintValidatorContext cxt) { + if(contactField == null) { + return false; + } + return contactField.matches("[0-9]+") && (contactField.length() > 8) && (contactField.length() < 14); + } + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java new file mode 100644 index 0000000000..f860394707 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java @@ -0,0 +1,18 @@ +package com.baeldung.model; + +import com.baeldung.customvalidator.ContactNumberConstraint; + +public class ValidatedPhone { + + @ContactNumberConstraint + private String phone; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java new file mode 100644 index 0000000000..70b151e066 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java @@ -0,0 +1,35 @@ +package com.baeldung.web.controller; + +import javax.validation.Valid; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import com.baeldung.model.ValidatedPhone; + +@Controller +@EnableWebMvc +public class ValidatedPhoneController { + + @RequestMapping(value="/validatePhone", method=RequestMethod.GET) + public String loadFormPage(Model m) { + m.addAttribute("validatedPhone", new ValidatedPhone()); + return "phoneHome"; + } + + @RequestMapping(value="/addValidatePhone", method=RequestMethod.POST) + public String submitForm(@Valid ValidatedPhone validatedPhone, BindingResult result, Model m) { + if(result.hasErrors()) { + return "phoneHome"; + } + + m.addAttribute("message", "Successfully saved phone: " + validatedPhone.toString()); + return "phoneHome"; + } + + +} diff --git a/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml b/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml index 4ba9642448..b0a4d4892a 100644 --- a/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml +++ b/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml @@ -1,6 +1,14 @@ - - + + + \ No newline at end of file diff --git a/spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp b/spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp new file mode 100644 index 0000000000..b873e9bc5f --- /dev/null +++ b/spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp @@ -0,0 +1,38 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> + + + + + Sample Form + + + + +
+ +

Phone Number

+
${message}
+ + + + + + +
+ + +
+
+ + diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java new file mode 100644 index 0000000000..069cc8e141 --- /dev/null +++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java @@ -0,0 +1,41 @@ +package com.baeldung.web.controller; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +public class CustomMVCValidatorTest { + + private MockMvc mockMvc; + + @Before + public void setup(){ + this.mockMvc = MockMvcBuilders.standaloneSetup(new ValidatedPhoneController()).build(); + } + + @Test + public void givenPhonePageUri_whenMockMvc_thenReturnsPhonePage() throws Exception{ + this.mockMvc.perform(get("/validatePhone")).andExpect(view().name("phoneHome")); + } + + @Test + public void givenPhoneURIWithPostAndFormData_whenMockMVC_thenVerifyErrorResponse() throws Exception { + this.mockMvc.perform(MockMvcRequestBuilders.post("/addValidatePhone"). + accept(MediaType.TEXT_HTML). + param("phoneInput", "123")). + andExpect(model().attributeHasFieldErrorCode("validatedPhone", "phone","ContactNumberConstraint")). + andExpect(view().name("phoneHome")). + andExpect(status().isOk()). + andDo(print()); + } + +} From 42f1ef0bf38782db75a00cfb5a7af678b490407a Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Sat, 18 Mar 2017 09:20:33 +0000 Subject: [PATCH 2/2] BAEL-112 - custom validator - format fixes --- .../ContactNumberConstraint.java | 6 +++-- .../ContactNumberValidator.java | 7 +++--- .../com/baeldung/model/ValidatedPhone.java | 6 ++++- .../controller/ValidatedPhoneController.java | 24 +++++++++---------- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java index 2fba2720c3..dbd38c1122 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java @@ -11,12 +11,14 @@ import javax.validation.Payload; @Documented @Constraint(validatedBy = ContactNumberValidator.class) -@Target( { ElementType.METHOD, ElementType.FIELD }) +@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface ContactNumberConstraint { String message() default "Invalid phone number"; + Class[] groups() default {}; + Class[] payload() default {}; - + } diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java index a7eb7a9df4..713b7429cf 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java @@ -6,14 +6,15 @@ import javax.validation.ConstraintValidatorContext; public class ContactNumberValidator implements ConstraintValidator { @Override - public void initialize(ContactNumberConstraint contactNumber) {} + public void initialize(ContactNumberConstraint contactNumber) { + } @Override public boolean isValid(String contactField, ConstraintValidatorContext cxt) { - if(contactField == null) { + if (contactField == null) { return false; } - return contactField.matches("[0-9]+") && (contactField.length() > 8) && (contactField.length() < 14); + return contactField.matches("[0-9]+") && (contactField.length() > 8) && (contactField.length() < 14); } } diff --git a/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java index f860394707..be702a8517 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java +++ b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java @@ -3,7 +3,7 @@ package com.baeldung.model; import com.baeldung.customvalidator.ContactNumberConstraint; public class ValidatedPhone { - + @ContactNumberConstraint private String phone; @@ -15,4 +15,8 @@ public class ValidatedPhone { this.phone = phone; } + @Override + public String toString() { + return phone; + } } diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java index 70b151e066..54b0e19e60 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java +++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java @@ -15,21 +15,21 @@ import com.baeldung.model.ValidatedPhone; @EnableWebMvc public class ValidatedPhoneController { - @RequestMapping(value="/validatePhone", method=RequestMethod.GET) + @RequestMapping(value = "/validatePhone", method = RequestMethod.GET) public String loadFormPage(Model m) { - m.addAttribute("validatedPhone", new ValidatedPhone()); - return "phoneHome"; + m.addAttribute("validatedPhone", new ValidatedPhone()); + return "phoneHome"; } - - @RequestMapping(value="/addValidatePhone", method=RequestMethod.POST) + + @RequestMapping(value = "/addValidatePhone", method = RequestMethod.POST) public String submitForm(@Valid ValidatedPhone validatedPhone, BindingResult result, Model m) { - if(result.hasErrors()) { - return "phoneHome"; - } - - m.addAttribute("message", "Successfully saved phone: " + validatedPhone.toString()); + if (result.hasErrors()) { return "phoneHome"; + } + + m.addAttribute("message", "Successfully saved phone: " + validatedPhone.toString()); + return "phoneHome"; } - - + + }