Spring Boot Flash attributes
last modified July 24, 2023
In this article we show how to create flash messages in Spring Boot applications.
Spring is a popular Java application framework and Spring Boot is an evolution of Spring that helps create stand-alone, production-grade Spring based applications easily.
Flash messages are temporary data used for user notifications or storing form input. They are stored in a session and vanish as soon as they are retrieved.
Flash messages in Spring are created as flash attributes using RedirectAttributes's
addFlashAttribute
. They are used in conjunction with RedirectView
.
Spring Boot Flash attributes example
In the following application, we create flash attributes for notifications and for remembering form input values. We have a form with two inputs. If the input values do not meet the validation criteria, the application redirects to the form page and shows error messages; these messages are sent as flash attributes.
In addition, the correct values of a form are remembered.
build.gradle ... src ├───main │ ├───java │ │ └───com │ │ └───zetcode │ │ │ Application.java │ │ └───controller │ │ MyController.java │ │ │ └───resources │ └───templates │ index.html │ showMessage.html └───test └───java
This is the project structure of the Spring application.
plugins { id 'org.springframework.boot' version '3.1.1' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final' }
This is the Gradle build file. We use spring-boot-starter-thymeleaf
for templating with Thymeleaf and hibernate-validator
for
validation of form data.
package com.zetcode.controller; import jakarta.validation.ConstraintViolationException; import jakarta.validation.constraints.Size; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.view.RedirectView; import org.thymeleaf.util.StringUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @Controller @Validated public class MyController { @RequestMapping("/") public String index(Model model) { return "index"; } @RequestMapping("/message") public ModelAndView message(@RequestParam @Size(min = 2, max = 255) String name, @RequestParam @Size(min = 2, max = 255) String occupation) { var msg = String.format("%s is a %s", name, occupation); Map<String, Object> params = new HashMap<>(); params.put("message", msg); return new ModelAndView("showMessage", params); } @ExceptionHandler(ConstraintViolationException.class) public RedirectView handleError(ConstraintViolationException ex, WebRequest request, RedirectAttributes atts) { var name = request.getParameter("name"); var occupation = request.getParameter("occupation"); var errorMessages = new ArrayList<String>(); var violations = ex.getConstraintViolations(); violations.forEach(violation -> { var error = String.format("%s: %s", violation.getPropertyPath(), violation.getMessage()); errorMessages.add(error); }); if (!StringUtils.isEmptyOrWhitespace(name)) { atts.addFlashAttribute("name", name); } if (!StringUtils.isEmptyOrWhitespace(occupation)) { atts.addFlashAttribute("occupation", occupation); } atts.addFlashAttribute("messages", errorMessages); return new RedirectView("/"); } }
This is MyController
. It responds to the request from the client.
It finds out the current date and time and resolves the processing to the
showMessage.ftl
template, passing it data.
@Controller @Validated public class MyController {
The @Validated
annotation validates annotated request parameters.
In our case, we use two @Size
annotations.
@RequestMapping("/") public String index(Model model) { return "index"; }
The root page returns the index view, which sends a form to the client.
@RequestMapping("/message") public ModelAndView message(@RequestParam @Size(min = 2, max = 255) String name, @RequestParam @Size(min = 2, max = 255) String occupation) { var msg = String.format("%s is a %s", name, occupation); Map<String, Object> params = new HashMap<>(); params.put("message", msg); return new ModelAndView("showMessage", params); }
This action responds to the form submission. The two input parameters, name and occupation,
are annotated with @Size
. If all goes OK, a message is built from the parameters
and is sent to the client with the showMessage
view.
@ExceptionHandler(ConstraintViolationException.class) public RedirectView handleError(ConstraintViolationException ex, WebRequest request, RedirectAttributes atts) {
If the input parameters fail to validate, a ConstraintViolationException
is thrown. We react to the exception in the provided exception handler.
var name = request.getParameter("name"); var occupation = request.getParameter("occupation");
We get the request parameters. They are used to keep the correct form input values.
var errorMessages = new ArrayList<String>(); var violations = ex.getConstraintViolations(); violations.forEach(violation -> { var error = String.format("%s: %s", violation.getPropertyPath(), violation.getMessage()); errorMessages.add(error); });
We get the constraint violations and build a list of error messages. The error messages are going to be shown in the index form page above the form.
if (!StringUtils.isEmptyOrWhitespace(name)) { atts.addFlashAttribute("name", name); } if (!StringUtils.isEmptyOrWhitespace(occupation)) { atts.addFlashAttribute("occupation", occupation); }
We store the filled input parameters as flash attributes with
addFlashAttribute
if they are not empty and do not contain only
blank spaces.
atts.addFlashAttribute("messages", errorMessages);
The error messages are stored as a flash attribute.
return new RedirectView("/");
We redirect to the form page with RedirectView
.
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Home page</title> <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.5.0/semantic.min.css" rel="stylesheet"> </head> <body> <section class="ui container"> <ul th:each="message : ${messages}"> <li th:text="${message}" class="ui error message" /> </ul> <form class="ui form" action="message" method="post"> <div class="field"> <label>Name:</label> <input type="text" name="name" th:value="${name}"> </div> <div class="field"> <label>Occupation:</label> <input type="text" name="occupation" th:value="${occupation}"> </div> <button class="ui button" type="submit">Send</button> </form> </section> <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.5.0/semantic.min.js"></script> </body> </html>
This is the home page template. It sends a form with two inputs: name and occupation. The styling is done with Semantic UI library.
<ul th:each="message : ${messages}"> <li th:text="${message}" class="ui error message" /> </ul>
If there are any error messages, they are displayed.
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Message</title> </head> <body> <p th:text="${message}"/> </body> </html>
The showMessage
template shows a message when the form was
successfully processed.
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Application
is the entry point which sets up Spring Boot
application.
In this article we have worked with flash attributes in Spring Boot.