Following example shows how to use Spring native validation (check out related core tutorial) in a MVC application. We need to implement Validator interface and perform validation programmatically. This is an alternative to Jakarta Bean annotation based validations (last example).
Example
A Java Bean
public class User {
private Long id;
private String name;
private String password;
private String emailAddress;
.............
}
Implementing Validator
package com.logicbig.example;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import java.util.regex.Pattern;
@Component
public class UserValidator implements Validator {
private static final Pattern EMAIL_REGEX =
Pattern.compile("^[\\w\\d._-]+@[\\w\\d.-]+\\.[\\w\\d]{2,6}$");
@Override
public boolean supports(Class<?> clazz) {
return clazz == User.class;
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "name", "user.name.empty");
ValidationUtils.rejectIfEmpty(errors, "password", "user.password.empty");
ValidationUtils.rejectIfEmpty(errors, "emailAddress", "user.email.empty");
User user = (User) target;
if (user.getName() != null && user.getName().length() < 5 || user.getName().length() > 20) {
errors.rejectValue("name", "user.name.size");
}
if (user.getPassword() != null && user.getPassword().contains(" ")) {
errors.rejectValue("password", "user.password.space");
}
if (user.getPassword() != null
&& user.getPassword().length() < 5
&& user.getPassword().length() > 15) {
errors.rejectValue("password", "user.password.size");
}
if (user.getEmailAddress() != null && !EMAIL_REGEX.matcher(user.getEmailAddress()).matches()) {
errors.rejectValue("emailAddress", "user.email.invalid");
}
}
}
Message Source
src/main/resources/ValidationMessages_en.propertiesuser.name.empty=User Name cannot be empty.
user.name.size=User Name must be of more than 5 and less than 20 characters.
user.password.empty=User Password cannot be empty.
user.password.size=User Password length must be between 6 and 15.
user.password.space=Password must not have spaces.
user.email.empty=User Email cannot be empty.
user.email.invalid=Email is not valid.
Spring Controller
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
@RequestMapping("/register")
public class UserRegistrationController {
@Autowired private UserService userService;
@Autowired private UserValidator userValidator;
@GetMapping
public String handleGetRequest(Model model) {
model.addAttribute("user", new User());
return "user-registration";
}
@PostMapping
public String handlePostRequest(
@ModelAttribute("user") User user, BindingResult bindingResult, Model model) {
userValidator.validate(user, bindingResult);
if (bindingResult.hasErrors()) {
return "user-registration";
}
userService.saveUser(user);
return "registration-done";
}
}
JSP Form
src/main/webapp/WEB-INF/views/user-registration.jsp<%@taglib uri="http://www.springframework.org/tags/form" prefix="frm"%>
<html>
<head>
<style>
span.error {
color: red;
display: inline-block;
}
</style>
</head>
<body>
<h3> Registration Form <h3>
<br/>
<frm:form action="register" method="post" modelAttribute="user">
<pre>
Name <frm:input path="name" />
<frm:errors path="name" cssClass="error" />
Email address <frm:input path="emailAddress" />
<frm:errors path="emailAddress" cssClass="error" />
Password <frm:password path="password" />
<frm:errors path="password" cssClass="error" />
<input type="submit" value="Submit" />
</pre>
</frm:form>
</body>
</html>
Java Config
package com.logicbig.example;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
@EnableWebMvc
@Configuration
@ComponentScan
public class MyWebConfig implements WebMvcConfigurer {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("ValidationMessages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
}
To try examples, run embedded Jetty (configured in pom.xml of example project below):
mvn jetty:run
Output
Submitting invalid values:
$ curl -s http://localhost:8080/register -d "name=Joe&emailAddress=joe@example.com&password=abc"
<html> <head> <style> span.error { color: red; display: inline-block; } </style> </head> <body>
<h3> Registration Form <h3> <br/> <form id="user" action="register" method="post"> <pre> Name <input id="name" name="name" type="text" value="Joe"/> <span id="name.errors" class="error">User Name must be of more than 5 and less than 20 characters.</span>
Email address <input id="emailAddress" name="emailAddress" type="text" value="joe@example.com"/>
Password <input id="password" name="password" type="password" value=""/>
<input type="submit" value="Submit" /> </pre> </form> </body> </html>
Example ProjectDependencies and Technologies Used: - spring-webmvc 7.0.6 (Spring Web MVC)
Version Compatibility: 3.2.9.RELEASE - 7.0.6 Version compatibilities of spring-webmvc with this example: Versions in green have been tested.
- spring-test 7.0.6 (Spring TestContext Framework)
- jakarta.servlet-api 6.1.0 (Jakarta Servlet API documentation)
- junit-jupiter-engine 6.0.3 (Module "junit-jupiter-engine" of JUnit)
- hamcrest 3.0 (Core API and libraries of hamcrest matcher framework)
- jakarta.el 4.0.0 (Jakarta Expression Language Implementation)
- assertj-core 3.26.3 (Rich and fluent assertions for testing in Java)
- JDK 25
- Maven 3.9.11
|