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.