Spring BindingResult
last modified October 18, 2023
Spring BindingResult tutorial shows how to use BindingResult to get the result of a validation.
Spring is a popular Java application framework for creating enterprise applications.
BindingResult
BindingResult
holds the result of a validation and binding
and contains errors that may have occurred. The BindingResult
must
come right after the model object that is validated or else Spring fails to
validate the object and throws an exception.
Spring BindingResult example
The following application validates a user form and uses BindingResult to store the validation results.
pom.xml src ├───main │ ├───java │ │ └───com │ │ └───zetcode │ │ ├───config │ │ │ MyWebInitializer.java │ │ │ WebConfig.java │ │ ├───controller │ │ │ MyController.java │ │ └───form │ │ UserForm.java │ └───resources │ └───templates │ form.html │ showInfo.html └───test └───java
This is the project structure.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zetcode</groupId> <artifactId>bindingresultex</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <spring-version>5.3.23</spring-version> <thymeleaf-version>3.0.15.RELEASE</thymeleaf-version> </properties> <dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.5.Final</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>${thymeleaf-version}</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>${thymeleaf-version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.49.v20220914</version> </plugin> </plugins> </build> </project>
In the pom.xml
file, we have the project dependencies.
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.5.Final</version> </dependency>
We use hibernate-validator
for validation.
package com.zetcode.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.FrameworkServlet; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; @Configuration public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return null; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
MyWebInitializer
initializes the Spring web application. It contains one
configuration class: WebConfig
.
package com.zetcode.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.thymeleaf.spring5.SpringTemplateEngine; import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; import org.thymeleaf.spring5.view.ThymeleafViewResolver; @Configuration @EnableWebMvc @ComponentScan(basePackages = {"com.zetcode"}) public class WebConfig implements WebMvcConfigurer { @Autowired private ApplicationContext applicationContext; @Bean public SpringResourceTemplateResolver templateResolver() { var templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(applicationContext); templateResolver.setPrefix("classpath:/templates/"); templateResolver.setSuffix(".html"); return templateResolver; } @Bean public SpringTemplateEngine templateEngine() { var templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); templateEngine.setEnableSpringELCompiler(true); return templateEngine; } @Bean public ViewResolver viewResolver() { var resolver = new ThymeleafViewResolver(); var registry = new ViewResolverRegistry(null, applicationContext); resolver.setTemplateEngine(templateEngine()); registry.viewResolver(resolver); return resolver; } }
The WebConfig
configures the Thymeleaf template engine. The Thymeleaf
template files are located in the templates
subdirectory on the classpath.
package com.zetcode.form; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; public class UserForm { @NotBlank @Size(min = 2) private String name; @NotBlank @Email private String email; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
This is a form bean. It contains some validation annotations.
@NotBlank @Size(min = 2) private String name;
The name attribute must not be blank and must have at least 2 characters.
@NotBlank @Email private String email;
The email attribute must not be blank and must be a well-formed email.
package com.zetcode.controller; import com.zetcode.form.UserForm; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.validation.Valid; @Controller public class MyController { @GetMapping(value = "/") public String form(UserForm userForm) { return "form"; } @PostMapping("/") public String checkForm(@Valid UserForm userForm, BindingResult bindingResult, RedirectAttributes atts) { if (bindingResult.hasErrors()) { return "form"; } atts.addAttribute("name", userForm.getName()); atts.addAttribute("email", userForm.getEmail()); return "redirect:/showInfo"; } @GetMapping("/showInfo") public String showInfo(@ModelAttribute("name") String name, @ModelAttribute("email") String email) { return "showInfo"; } }
MyController
contains mappings of request paths to handler methods.
@GetMapping(value = "/") public String form(UserForm userForm) { return "form"; }
The home page returns a view that contains a form. The UserForm
bean is backing a form. It is going to be populated with data from the form.
@PostMapping("/") public String checkForm(@Valid UserForm userForm, BindingResult bindingResult, RedirectAttributes atts) { ...
We validate the UserForm
bean with @Valid
. The validation
results are stored in BindingResult
.
if (bindingResult.hasErrors()) { return "form"; }
If the binding result contains errors, we return to the form.
atts.addAttribute("name", userForm.getName()); atts.addAttribute("email", userForm.getEmail()); return "redirect:/showInfo";
Adhering to the redirect after post pattern, we redirect to the
showInfo
view after successful validation. In order not to lose the
inputs, we store them in RedirectAttributes
.
@GetMapping("/showInfo") public String showInfo(@ModelAttribute("name") String name, @ModelAttribute("email") String email) { return "showInfo"; }
The @ModelAttribute
takes the request attributes nad puts them into
the model object, which is then sent to the showInfo
view.
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>User form</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"> </head> <body> <section class="ui container"> <form action="#" class="ui form" th:action="@{/}" th:object="${userForm}" method="post"> <div class="field"> <label>Name:</label> <input type="text" th:field="*{name}"> <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</span> </div> <div class="field"> <label>Email:</label> <input type="text" th:field="*{email}"> <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email Error</span> </div> <button class="ui button" type="submit">Submit</button> </form> </section> </body> </html>
The root page contains the form.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
The form is styled using Semantic UI.
<form action="#" class="ui form" th:action="@{/}" th:object="${userForm}" method="post">
The th:object
refers to the user form bean. This is not a class name,
but a Spring bean name; therefore it is in lowercase.
<input type="text" th:field="*{name}">
The input is mapped to the name
attribute of the userForm
.
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</span>
This line displays possible validation errors.
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Show info</title> </head> <body> <p> Successfully added user <span th:text="${name}" th:remove="tag"></span> with email <span th:text="${email}" th:remove="tag"></span> </p> </body> </html>
This view shows the entered information.
In this article we have used BindingResult
when validating a form.
Author
List all Spring tutorials.