# Spring Boot Flash 属性

> 原文： [http://zetcode.com/springboot/flashattribute/](http://zetcode.com/springboot/flashattribute/)

Spring Boot Flash 属性教程展示了如何在 Spring Boot 应用中创建 Flash 消息。

Spring 是流行的 Java 应用框架，而 Spring Boot 是 Spring 的演进，可以帮助轻松地创建独立的，生产级的基于 Spring 的应用。

Flash 消息是用于用户通知或存储表单输入的临时数据。 它们存储在一个会话中，并且一旦检索就消失。

使用`RedirectAttributes`的`addFlashAttribute()`在 Spring 中将 Flash 消息创建为 Flash 属性。 它们与`RedirectView`结合使用。

## Spring Boot Flash 属性示例

在以下应用中，我们创建用于通知和记住表单输入值的 Flash 属性。 我们有一个带有两个输入的表格。 如果输入值不符合验证标准，则应用将重定向到表单页面并显示错误消息； 这些消息作为 Flash 属性发送。

此外，还可以记住表单的正确值。

```java
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───controller
│   │                   MyController.java
│   │
│   └───resources
│       └───templates
│               index.html
│               showMessage.html
└───test
    └───java  

```

这是 Spring 应用的项目结构。

`pom.xml`

```java
<?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>springflashmessage</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.13.Final</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>   

```

这是 Maven `pom.xml`文件。 我们使用`spring-boot-starter-thymeleaf`与 Thymeleaf 进行模板化，并使用`hibernate-validator`进行表单数据验证。

`com/zetcode/controller/MyController.java`

```java
package com.zetcode.controller;

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 javax.validation.ConstraintViolationException;
import javax.validation.constraints.Size;
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);

        var redirectView = new RedirectView("/");

        return redirectView;
    }
}

```

这是`MyController`。 它响应来自客户端的请求。 它找出当前日期和时间，并将处理过程解析为`showMessage.ftl`模板，并将其传递给数据。

```java
@Controller
@Validated
public class MyController {

```

`@Validated`注解验证带注解的请求参数。 在我们的例子中，我们使用两个`@Size`注解。

```java
@RequestMapping("/")
public String index(Model model) {

    return "index";
}

```

根页面返回索引视图，该视图将表单发送给客户端。

```java
@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);

}

```

此操作响应表单提交。 两个输入参数，名称和职业用`@Size`注解。 如果一切正常，将根据参数构建一条消息，并使用`showMessage`视图将其发送到客户端。

```java
@ExceptionHandler(ConstraintViolationException.class)
public RedirectView handleError(ConstraintViolationException ex,
                                WebRequest request,
                                RedirectAttributes atts) {

```

如果输入参数未能通过验证，则会抛出`ConstraintViolationException`。 我们在提供的异常处理器中对异常做出反应。

```java
var name = request.getParameter("name");
var occupation = request.getParameter("occupation");

```

我们得到了请求参数。 它们用于保留正确的表单输入值。

```java
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);
});

```

我们得到约束违例并建立错误消息列表。 错误消息将显示在表单上方的索引表单页面中。

```java
if (!StringUtils.isEmptyOrWhitespace(name)) {
    atts.addFlashAttribute("name", name);
}

if (!StringUtils.isEmptyOrWhitespace(occupation)) {

    atts.addFlashAttribute("occupation", occupation);
}

```

如果填充的输入参数不为空并且不仅包含空格，则将它们与`addFlashAttribute()`一起存储为 Flash 属性。

```java
atts.addFlashAttribute("messages", errorMessages);

```

错误消息存储为 Flash 属性。

```java
var redirectView = new RedirectView("/");

return redirectView;

```

我们使用`RedirectView`重定向到表单页面。

`templates/index.html`

```java
<!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.3.1/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.3.1/semantic.min.js"></script>
</body>
</html>

```

这是主页模板。 它发送带有两个输入的表单：名称和职业。 样式是使用语义 UI 库完成的。

```java
<ul th:each="message : ${messages}">
    <li th:text="${message}" class="ui error message" />
</ul>

```

如果有任何错误消息，将显示它们。

`templates/showMessage.html`

```java
<!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>

```

成功处理表单后，`showMessage`模板会显示一条消息。

`com/zetcode/Application.java`

```java
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`是设置 Spring Boot 应用的入口。

在本教程中，我们展示了如何在 Spring 应用中使用 flash 属性。 您可能也对相关教程感兴趣： [Spring Boot `@RestController`教程](/sprinboot/restcontroller/)， [Spring Boot `@ExceptionHandler`教程](/springboot/exceptionhandler/)， [Spring Boot 上传文件](/springboot/uploadfile/)， [Spring Boot `@RequestParam`教程](/springboot/requestparam/)， [Java 教程](/lang/java/)。