Handbuch zu Flash-Attributen in einer Spring-Webanwendung

1. Übersicht

Webanwendungen sind häufig auf Benutzereingaben angewiesen, um mehrere ihrer Anwendungsfälle zu erfüllen. Daher ist das Senden von Formularen ein häufig verwendeter Mechanismus zum Sammeln und Verarbeiten von Daten für solche Apps.

In diesem Tutorial erfahren Sie, wie die Flash-Attribute von Spring uns beim sicheren und zuverlässigen Workflow für die Formularübermittlung helfen können.

2. Grundlagen der Flash-Attribute

Bevor wir Flash-Attribute bequem verwenden können, müssen wir ein angemessenes Verständnis des Workflows für die Formularübermittlung und einiger wichtiger Konzepte aufbauen.

2.1. Post / Redirect / Get Pattern

Eine naive Möglichkeit, ein Webformular zu erstellen, besteht darin, eine einzelne HTTP-POST-Anforderung zu verwenden, die sich um die Übermittlung kümmert und durch ihre Antwort eine Bestätigung zurückgibt. Ein solches Design birgt jedoch das Risiko einer doppelten Verarbeitung von POST-Anforderungen, falls der Benutzer die Seite aktualisiert.

Um das Problem der doppelten Verarbeitung zu verringern, können wir den Workflow als eine Folge miteinander verbundener Anforderungen in einer bestimmten Reihenfolge erstellen, nämlich POST, REDIRECT und GET . Kurz gesagt, wir nennen dies das PRG-Muster (Post / Redirect / Get) für die Formularübermittlung.

Beim Empfang der POST-Anforderung verarbeitet der Server diese und überträgt dann die Steuerung, um eine GET-Anforderung zu stellen. Anschließend wird die Bestätigungsseite basierend auf der Antwort der GET-Anforderung angezeigt. Selbst wenn die letzte GET-Anforderung mehrmals versucht wird, sollten im Idealfall keine nachteiligen Nebenwirkungen auftreten.

2.2. Lebenszyklus von Flash-Attributen

Um das Senden des Formulars mithilfe des PRG-Musters abzuschließen, müssen wir nach der Umleitung Informationen von der anfänglichen POST-Anforderung zur endgültigen GET-Anforderung übertragen.

Leider können wir weder die RequestAttributes noch die SessionAttributes verwenden. Dies liegt daran, dass Ersteres eine Umleitung zwischen verschiedenen Controllern nicht überlebt, während Letzteres auch nach Abschluss der Formularübermittlung für die gesamte Sitzung gültig ist.

Wir müssen uns jedoch keine Sorgen machen, da das Webframework von Spring Flash-Attribute bereitstellt, mit denen genau dieses Problem behoben werden kann.

Sehen wir uns die Methoden in der RedirectAttributes- Oberfläche an, mit denen wir Flash-Attribute in unserem Projekt verwenden können:

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

Flash-Attribute sind von kurzer Dauer . Daher werden diese kurz vor der Umleitung vorübergehend in einem zugrunde liegenden Speicher gespeichert. Sie bleiben nach der Umleitung für die nachfolgende Anforderung verfügbar und sind dann verschwunden.

2.3. FlashMap- Datenstruktur

Spring bietet eine abstrakte Datenstruktur namens FlashMap zum Speichern der Flash-Attribute als Schlüssel-Wert-Paare.

Werfen wir einen Blick auf die Definition der FlashMap- Klasse:

public final class FlashMap extends HashMap implements Comparable { @Nullable private String targetRequestPath; private final MultiValueMap targetRequestParams = new LinkedMultiValueMap(4); private long expirationTime = -1; }

Wir können feststellen, dass die FlashMap- Klasse ihr Verhalten von der HashMap- Klasse erbt . Daher kann eine FlashMap- Instanz eine Schlüsselwertzuordnung der Attribute speichern . Außerdem können wir eine FlashMap- Instanz verknüpfen , die nur von einer bestimmten Umleitungs-URL verwendet wird.

Darüber hinaus verfügt jede Anforderung über zwei FlashMap- Instanzen, nämlich Input FlashMap und Output FlashMap, die im PRG-Muster eine wichtige Rolle spielen:

  • Die Ausgabe- FlashMap wird in der POST-Anforderung verwendet, um die Flash-Attribute vorübergehend zu speichern und sie nach der Umleitung an die nächste GET-Anforderung zu senden
  • Input FlashMap wird in der letzten GET-Anforderung verwendet, um auf die schreibgeschützten Flash-Attribute zuzugreifen, die von der vorherigen POST-Anforderung vor der Umleitung gesendet wurden

2.4. FlashMapManager und RequestContextUtils

Wie der Name schon sagt, können wir FlashMapManager verwenden , um die FlashMap- Instanzen zu verwalten .

Schauen wir uns zunächst die Definition dieser Strategie-Schnittstelle an:

public interface FlashMapManager { @Nullable FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response); void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response); }

Kurz gesagt, mit FlashMapManager können wir FlashMap- Instanzen in einem zugrunde liegenden Speicher lesen, aktualisieren und speichern .

Machen Sie sich als Nächstes mit einigen statischen Methoden vertraut , die in der abstrakten Dienstprogrammklasse RequestContextUtils verfügbar sind .

Um unseren Fokus im Rahmen dieses Tutorials zu halten, beschränken wir uns auf die Methoden, die für Flash-Attribute relevant sind:

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

Mit diesen Methoden können wir die FlashMap- Instanzen für die Eingabe / Ausgabe abrufen , den FlashMapManager für eine Anforderung abrufen und eine FlashMap- Instanz speichern .

3. Anwendungsfall für die Formularübermittlung

Inzwischen haben wir ein grundlegendes Verständnis für verschiedene Konzepte rund um Flash-Attribute entwickelt. Gehen wir also weiter und verwenden sie in einer Webanwendung für Gedichtwettbewerbe.

Unsere Poesie-Wettbewerbs-App bietet einen einfachen Anwendungsfall für das Akzeptieren von Gedichteinträgen verschiedener Dichter durch Einreichen eines Formulars. Darüber hinaus enthält ein Wettbewerbsbeitrag die erforderlichen Informationen zu einem Gedicht, z. B. einen Titel, einen Text und den Namen des Autors.

3.1. Thymeleaf-Konfiguration

Wir werden Thymeleaf verwenden, eine Java-Vorlagen-Engine zum Erstellen dynamischer Webseiten mit einfachen HTML-Vorlagen.

Zuerst müssen wir die Abhängigkeit von Spring-Boot-Starter-Thymeleaf zur pom.xml unseres Projekts hinzufügen :

 org.springframework.boot spring-boot-starter-thymeleaf 2.2.1.RELEASE 

Als Nächstes können wir einige der Thymeleaf-spezifischen Eigenschaften in unserer Datei pplication.properties definieren , die sich im Verzeichnis src / main / resources befindet :

spring.thymeleaf.cache=false spring.thymeleaf.enabled=true spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html

Nachdem wir diese Eigenschaften definiert haben, können wir jetzt alle unsere Ansichten im Verzeichnis / src / main / resources / templates erstellen . Im Gegenzug hängt Spring das Suffix .html an alle in unserem Controller genannten Ansichten an.

3.2. Domänenmodell

Up next, let's define our domain model in a Poem class:

public class Poem { private String title; private String author; private String body; }

Further, we can add the isValidPoem() static method in our Poem class to help us validate that the fields don't allow empty strings:

public static boolean isValidPoem(Poem poem) { return poem != null && Strings.isNotBlank(poem.getAuthor()) && Strings.isNotBlank(poem.getBody()) && Strings.isNotBlank(poem.getTitle()); }

3.3. Create Form

Now, we're ready to create our submission form. For that, we need an endpoint /poem/submit that will serve a GET request to show the form to the user:

@GetMapping("/poem/submit") public String submitGet(Model model) { model.addAttribute("poem", new Poem()); return "submit"; }

Here, we've used a model as a container to hold the poem-specific data provided by the user. Moreover, the submitGet method returns a view served by the submit view.

Additionally, we want to bind the POST form with the model attribute poem:

3.4. Post/Redirect/Get Submission Flow

Now, let's enable the POST action for the form. To do that, we'll create the /poem/submit endpoint in the PoemSubmission controller to serve the POST request:

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

We can notice that if the submission is successful, then control transfers to the /poem/success endpoint. Also, we added the poem data as a flash attribute before initiating the redirect.

Now, we need to show a confirmation page to the user, so let's implement the functionality for the /poem/success endpoint that'll serve the GET request:

@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"; } }

Hierbei ist zu beachten, dass wir die FlashMap validieren müssen, bevor wir zur Erfolgsseite umleiten können .

Verwenden wir zum Schluss das Flash-Attribut Gedicht auf unserer Erfolgsseite, um den Titel des vom Benutzer eingereichten Gedichts anzuzeigen:

Click here to submit more.

4. Fazit

In diesem Tutorial haben wir einige Konzepte zu den Post- / Redirect- / Get-Pattern- und Flash-Attributen kennengelernt. Außerdem haben wir Flash-Attribute mit einer einfachen Formularübermittlung in einer Spring Boot-Webanwendung in Aktion gesehen.

Wie immer ist der vollständige Quellcode für das Tutorial auf GitHub verfügbar.