ZetCode

Spring Boot Flash 属性

最后修改于 2023 年 7 月 24 日

在本文中,我们将展示如何在 Spring Boot 应用程序中创建 Flash 消息。

Spring 是一个流行的 Java 应用程序框架,而 Spring Boot 是 Spring 的一个演进,它有助于轻松创建独立的、生产级的基于 Spring 的应用程序。

Flash 消息是用于用户通知或存储表单输入的临时数据。它们存储在会话中,并在检索后立即消失。

Spring 中的 Flash 消息使用 RedirectAttributesaddFlashAttribute 创建为 Flash 属性。它们与 RedirectView 结合使用。

Spring Boot Flash 属性示例

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

此外,还会记住表单的正确值。

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

这是 Spring 应用程序的项目结构。

build.gradle
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'
}

这是 Gradle 构建文件。我们使用 spring-boot-starter-thymeleaf 进行 Thymeleaf 模板处理,并使用 hibernate-validator 进行表单数据验证。

com/zetcode/controller/MyController.java
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("/");
    }
}

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

@Controller
@Validated
public class MyController {

@Validated 注解验证已注解的请求参数。在我们的例子中,我们使用了两个 @Size 注解。

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

    return "index";
}

根页面返回 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);
}

此操作响应表单提交。两个输入参数 name 和 occupation 都使用 @Size 进行注解。如果一切正常,将从参数构建一条消息,并通过 showMessage 视图发送给客户端。

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

如果输入参数验证失败,则会抛出 ConstraintViolationException。我们会在提供的异常处理程序中对异常做出反应。

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

我们获取约束违规并构建一个错误消息列表。错误消息将显示在 index 表单页面中表单的上方。

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

if (!StringUtils.isEmptyOrWhitespace(occupation)) {

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

如果填充的输入参数不为空且不只包含空格,则使用 addFlashAttribute 将它们存储为 Flash 属性。

atts.addFlashAttribute("messages", errorMessages);

错误消息将作为 Flash 属性存储。

return new RedirectView("/");

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

templates/index.html
<!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>

这是主页模板。它发送一个带有两个输入的表单:name 和 occupation。样式使用 Semantic UI 库完成。

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

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

templates/showMessage.html
<!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
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 Boot 中的 Flash 属性进行操作。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 Spring Boot 教程