当前位置:首页 > 今天的世界杯

Spring Web 应用程序中的 Flash 属性指南

admin 2025-08-20 23:28:00 980

1. 概述

Web 应用程序通常依赖于用户输入来满足其多个用例。因此,表单提交是一种大量使用的机制,用于收集和处理此类应用的数据。

在本教程中,我们将了解 Spring 的 flash 属性如何帮助我们安全可靠地完成表单提交工作流程。

2. 闪光属性基础知识

在我们可以轻松使用 flash 属性之前,我们需要对表单提交工作流程和一些关键相关概念有很好的理解。

2.1. 发布/重定向/获取模式

设计 Web 表单的一种天真方法是使用单个 HTTP POST 请求来处理提交并通过其响应返回确认。但是,这种设计暴露了重复处理 POST 请求的风险,以防用户最终刷新页面。

为了减少重复处理的问题,我们可以将工作流创建为按特定顺序(即 POST、重定向和 GET)的互连请求序列。简而言之,我们称之为表单提交的发布/重定向/获取 (PRG) 模式。

收到 POST 请求后,服务器会处理它,然后转移控制权以发出 GET 请求。随后,根据 GET 请求的响应显示确认页面。理想情况下,即使最后一个GET请求被多次尝试,也不应该有任何不利的副作用。

2.2. 闪存属性的生命周期

要使用 PRG 模式完成表单提交,我们需要在重定向后将信息从初始 POST 请求传输到最终 GET 请求。

不幸的是,我们既不能使用 RequestAttributes,也不能使用 SessionAttributes。 这是因为前者不会在不同的控制器之间重定向后幸存下来,而后者即使在表单提交结束后也会持续整个会话。

但是,我们不需要担心,因为Spring的Web框架提供了可以解决这个确切问题的flash属性。

让我们看看 RedirectAttributes 接口中可以帮助我们在项目中使用 flash 属性的方法:

RedirectAttributes addFlashAttribute(String attributeName, @Nullable Object attributeValue);

RedirectAttributes addFlashAttribute(Object attributeValue);

Map getFlashAttributes();

闪存属性的生存期很短。因此,它们在重定向之前临时存储在某个基础存储中。重定向后,它们仍可用于后续请求,然后它们就消失了。

2.3. 闪图数据结构

Spring 提供了一个名为 FlashMap 的抽象数据结构,用于将 flash 属性存储为键值对。

让我们看一下 FlashMap 类的定义:

public final class FlashMap extends HashMap implements Comparable {

@Nullable

private String targetRequestPath;

private final MultiValueMap targetRequestParams

= new LinkedMultiValueMap<>(4);

private long expirationTime = -1;

}

我们可以注意到,FlashMap 类从 HashMap 类继承了它的行为。因此,FlashMap 实例可以存储属性的键值映射。此外,我们可以绑定一个 FlashMap 实例,使其仅由特定的重定向 URL 使用。

此外,每个请求都有两个 FlashMap 实例,即输入 FlashMap 和 Output FlashMap,它们在 PRG 模式中起着重要作用:

输出闪光图在 POST 请求中用于临时保存闪光属性,并在重定向后将它们发送到下一个 GET 请求输入闪光图在最终的GET请求中用于访问重定向前上一个POST请求发送的只读闪存属性

2.4. FlashMapManager 和 RequestContextUtils

顾名思义,我们可以使用FlashMapManager来管理FlashMap实例。

首先,我们来看看这个策略接口的定义:

public interface FlashMapManager {

@Nullable

FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);

void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);

}

简而言之,我们可以说FlashMapManager允许我们读取,更新和保存FlashMap实例在某些底层存储中。

接下来,让我们熟悉 RequestContextUtils 抽象实用程序类中可用的一些静态方法。

为了将重点保持在本教程的范围内,我们将介绍与 flash 属性相关的方法:

public static Map getInputFlashMap(HttpServletRequest request);

public static FlashMap getOutputFlashMap(HttpServletRequest request);

public static FlashMapManager getFlashMapManager(HttpServletRequest request);

public static void saveOutputFlashMap(String location,

HttpServletRequest request, HttpServletResponse response);

我们可以使用这些方法来检索输入/输出的 FlashMap 实例,获取请求的 FlashMapManager,并保存 FlashMap 实例。

3. 表单提交用例

到目前为止,我们已经对围绕闪光属性的不同概念有了基本的了解。因此,让我们进一步,在诗歌比赛 Web 应用程序中使用它们。

我们的诗歌比赛应用程序有一个简单的用例,通过提交表格接受来自不同诗人的诗歌作品。此外,参赛作品将具有与诗歌相关的必要信息,例如标题、正文和作者姓名。

3.1. 百里香叶配置

我们将使用Thymeleaf,这是一个Java模板引擎,用于通过简单的HTML模板创建动态网页。

首先,我们需要将 spring-boot-starter-thymeleaf 依赖项添加到项目的 pom 中.xml:

org.springframework.boot

spring-boot-starter-thymeleaf

2.2.1.RELEASE

接下来,我们可以在位于 src/main/resources 目录中的pplication.properties 文件中定义一些特定于 Thymeleaf 的属性:

spring.thymeleaf.cache=false

spring.thymeleaf.enabled=true

spring.thymeleaf.prefix=classpath:/templates/

spring.thymeleaf.suffix=.html

定义这些属性后,我们现在可以在 /src/main/resources/templates 目录下创建所有视图。反过来,Spring 会将.html后缀附加到控制器内命名的所有视图中。

3.2. 域模型

接下来,让我们在 Poem 类中定义我们的领域模型:

public class Poem {

private String title;

private String author;

private String body;

}

此外,我们可以在 Poem 类中添加 isValidPoem() 静态方法,以帮助我们验证字段是否不允许空字符串:

public static boolean isValidPoem(Poem poem) {

return poem != null && Strings.isNotBlank(poem.getAuthor())

&& Strings.isNotBlank(poem.getBody())

&& Strings.isNotBlank(poem.getTitle());

}

3.3. 创建表单

现在,我们已准备好创建提交表单。为此,我们需要一个端点 /poem/submit 来提供 GET 请求以向用户显示表单:

@GetMapping("/poem/submit")

public String submitGet(Model model) {

model.addAttribute("poem", new Poem());

return "submit";

}

在这里,我们使用一个模型作为容器来保存用户提供的特定于诗歌的数据。此外,提交获取方法返回由提交视图提供的视图。

此外,我们希望将 POST 表单与模型属性诗绑定:

3.4. 发布/重定向/获取提交流程

现在,让我们为表单启用 POST 操作。为此,我们将在 PoemSubmit 控制器中创建 /poem/submit 端点来为 POST 请求提供服务:

@PostMapping("/poem/submit")

public RedirectView submitPost(

HttpServletRequest request,

@ModelAttribute Poem poem,

RedirectAttributes redirectAttributes) {

if (Poem.isValidPoem(poem)) {

redirectAttributes.addFlashAttribute("poem", poem);

return new RedirectView("/poem/success", true);

} else {

return new RedirectView("/poem/submit", true);

}

}

我们可以注意到,如果提交成功,则控制权将转移到 /poem/success 端点。此外,我们在启动重定向之前将诗歌数据添加为 flash 属性。

现在,我们需要向用户显示一个确认页面,因此让我们实现将为 GET 请求提供服务的 /poem/success 端点的功能:

@GetMapping("/poem/success")

public String getSuccess(HttpServletRequest request) {

Map inputFlashMap = RequestContextUtils.getInputFlashMap(request);

if (inputFlashMap != null) {

Poem poem = (Poem) inputFlashMap.get("poem");

return "success";

} else {

return "redirect:/poem/submit";

}

}

这里需要注意的是,在我们决定重定向到成功页面之前,我们需要验证闪光图。

最后,让我们使用成功页面中的 flash 属性诗来显示用户提交的诗的标题:

Click here to submit more.

4. 结论

在本教程中,我们学习了有关发布/重定向/获取模式和闪存属性的一些概念。而且,我们还看到了 flash 属性在 Spring Boot Web 应用程序中通过简单的表单提交而起作用。

与往常一样,本教程的完整源代码可在 GitHub 上找到。