Guida agli attributi Flash in un'applicazione Web Spring

1. Panoramica

Le applicazioni Web dipendono spesso dall'input dell'utente per soddisfare molti dei loro casi d'uso. Di conseguenza, l'invio di moduli è un meccanismo ampiamente utilizzato per raccogliere ed elaborare i dati per tali app.

In questo tutorial, impareremo come gli attributi flash di Spring possono aiutarci con il flusso di lavoro di invio dei moduli in modo sicuro e affidabile.

2. Nozioni di base sugli attributi Flash

Prima di poter utilizzare comodamente gli attributi flash, è necessario acquisire un livello di comprensione accettabile del flusso di lavoro di invio del modulo e alcuni concetti chiave correlati.

2.1. Pubblica / Reindirizza / Ottieni pattern

Un modo ingenuo per progettare un modulo Web sarebbe utilizzare una singola richiesta HTTP POST che si occupa dell'invio e restituisce una conferma attraverso la sua risposta. Tuttavia, tale progettazione espone al rischio di elaborazione duplicata delle richieste POST, nel caso in cui l'utente finisca per aggiornare la pagina.

Per mitigare il problema dell'elaborazione dei duplicati, possiamo creare il flusso di lavoro come una sequenza di richieste interconnesse in un ordine specifico, ovvero POST, REDIRECT e GET . In breve, lo chiamiamo il pattern Post / Redirect / Get (PRG) per l'invio del modulo.

Alla ricezione della richiesta POST, il server la elabora e quindi trasferisce il controllo per effettuare una richiesta GET. Successivamente, viene visualizzata la pagina di conferma in base alla risposta alla richiesta GET. Idealmente, anche se l'ultima richiesta GET viene tentata più di una volta, non dovrebbero esserci effetti collaterali negativi.

2.2. Ciclo di vita degli attributi Flash

Per completare l'invio del modulo utilizzando il modello PRG, avremo bisogno di trasferire le informazioni dalla richiesta POST iniziale alla richiesta GET finale dopo il reindirizzamento.

Sfortunatamente, non possiamo usare né RequestAttributesSessionAttributes. Questo perché il primo non sopravviverà a un reindirizzamento su controller diversi, mentre il secondo durerà per l'intera sessione anche dopo che l'invio del modulo è terminato.

Ma non dobbiamo preoccuparci poiché il framework web di Spring fornisce attributi flash che possono risolvere questo problema esatto.

Vediamo i metodi nell'interfaccia RedirectAttributes che possono aiutarci a utilizzare gli attributi flash nel nostro progetto:

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

Gli attributi Flash sono di breve durata . In quanto tali, vengono archiviati temporaneamente in uno spazio di archiviazione sottostante, appena prima del reindirizzamento. Rimangono disponibili per la richiesta successiva dopo il reindirizzamento e poi scompaiono.

2.3. Struttura dati FlashMap

Spring fornisce una struttura dati astratta chiamata FlashMap per memorizzare gli attributi flash come coppie chiave-valore.

Diamo uno sguardo alla definizione della classe FlashMap :

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

Possiamo notare che la classe FlashMap eredita il suo comportamento dalla classe HashMap . Pertanto, un'istanza FlashMap può memorizzare una mappatura valore-chiave degli attributi . Inoltre, possiamo collegare un'istanza FlashMap in modo che venga utilizzata solo da uno specifico URL di reindirizzamento.

Inoltre, ogni richiesta ha due istanze FlashMap , ovvero Input FlashMap e Output FlashMap, che svolgono un ruolo importante nel pattern PRG:

  • Output FlashMap viene utilizzato nella richiesta POST per salvare temporaneamente gli attributi flash e inviarli alla successiva richiesta GET dopo il reindirizzamento
  • Input FlashMap viene utilizzato nella richiesta GET finale per accedere agli attributi flash di sola lettura che erano stati inviati dalla precedente richiesta POST prima del reindirizzamento

2.4. FlashMapManager e RequestContextUtils

Come suggerisce il nome, possiamo utilizzare FlashMapManager per gestire le istanze di FlashMap .

Per prima cosa, diamo un'occhiata alla definizione di questa interfaccia strategica:

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

In poche parole, possiamo dire che FlashMapManager ci consente di leggere, aggiornare e salvare istanze di FlashMap in alcuni archivi sottostanti.

Successivamente, familiarizziamo con alcuni metodi statici disponibili nella classe di utilità astratta RequestContextUtils .

Per mantenere la nostra attenzione nell'ambito di questo tutorial, limiteremo la nostra copertura ai metodi rilevanti per gli attributi 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);

È possibile utilizzare questi metodi per recuperare le istanze FlashMap di input / output , ottenere FlashMapManager per una richiesta e salvare un'istanza FlashMap .

3. Caso d'uso per invio di moduli

A questo punto, abbiamo stabilito una comprensione di base dei diversi concetti sugli attributi flash. Quindi, andiamo oltre e usiamoli in un'applicazione web per un concorso di poesia.

La nostra app del concorso di poesia ha un semplice caso d'uso per accettare voci di poesie da diversi poeti attraverso l'invio di un modulo. Inoltre, un contributo al concorso avrà le informazioni necessarie relative a una poesia, come un titolo, un corpo e il nome dell'autore.

3.1. Configurazione Thymeleaf

Useremo Thymeleaf, che è un motore di modelli Java per la creazione di pagine web dinamiche attraverso semplici modelli HTML.

In primo luogo, abbiamo bisogno di aggiungere la primavera-boot-starter-thymeleaf dipendenza del nostro progetto pom.xml :

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

Successivamente, possiamo definire alcune delle proprietà specifiche di Thymeleaf nel nostro file a pplication.properties situato nella directory src / main / resources :

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

Dopo aver definito queste proprietà, ora possiamo creare tutte le nostre viste nella directory / src / main / resources / templates . A sua volta, Spring aggiungerà il suffisso .html a tutte le viste denominate all'interno del nostro controller.

3.2. Modello di dominio

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

È importante notare qui che dobbiamo convalidare FlashMap prima di decidere di reindirizzare alla pagina di successo .

Infine, utilizziamo l'attributo flash poem all'interno della nostra pagina di successo per mostrare il titolo della poesia inviata dall'utente:

Click here to submit more.

4. Conclusione

In questo tutorial, abbiamo imparato alcuni concetti sul pattern Post / Redirect / Get e sugli attributi flash. Inoltre, abbiamo anche visto gli attributi flash in azione con un semplice invio di moduli in un'applicazione Web Spring Boot.

Come sempre, il codice sorgente completo del tutorial è disponibile su GitHub.