Ръководство за Flash атрибути в пролетно уеб приложение

1. Общ преглед

Уеб приложенията често зависят от въвеждането от потребителя, за да отговорят на няколко от техните случаи на използване. В резултат на това подаването на формуляр е силно използван механизъм за събиране и обработка на данни за такива приложения.

В този урок ще научим как флаш атрибутите на Spring могат да ни помогнат с работния процес на подаване на формуляри сигурно и надеждно.

2. Основи на Flash атрибутите

Преди да можем удобно да използваме флаш атрибути, трябва да изградим прилично ниво на разбиране на работния процес за подаване на формуляри и няколко ключови свързани понятия.

2.1. Публикуване / пренасочване / Вземете шаблон

Наивен начин за проектиране на уеб формуляр би бил използването на единична HTTP POST заявка, която се грижи за подаването и връща потвърждение чрез своя отговор. Такъв дизайн обаче излага риска от дублирана обработка на POST заявки, в случай че потребителят завърши опресняването на страницата.

За да смекчим проблема с дублиращата обработка, можем да създадем работния поток като последователност от взаимно свързани заявки в определен ред - а именно POST, REDIRECT и GET . Накратко, ние наричаме този модел Post / Redirect / Get (PRG) за подаване на формуляр.

При получаване на POST заявката сървърът я обработва и след това прехвърля контрола, за да направи GET заявка. Впоследствие се показва страницата за потвърждение въз основа на отговора на GET заявката. В идеалния случай, дори ако последната заявка за GET бъде опитана повече от веднъж, не трябва да има нежелани странични ефекти.

2.2. Жизнен цикъл на Flash атрибути

За да завършим подаването на формуляра, използвайки шаблона PRG, ще трябва да прехвърлим информация от първоначалната заявка POST към крайната заявка GET след пренасочване.

За съжаление не можем нито да използваме RequestAttributes, нито SessionAttributes. Това е така, защото първият няма да оцелее при пренасочване през различни контролери, докато вторият ще продължи през цялата сесия, дори след като подаването на формуляра приключи.

Но не е нужно да се притесняваме, тъй като уеб рамката на Spring предоставя атрибути flash, които могат да решат този точно проблем.

Нека да видим методите в интерфейса RedirectAttributes, които могат да ни помогнат да използваме flash атрибути в нашия проект:

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

Атрибутите на Flash са краткотрайни . Като такива те се съхраняват временно в някакво основно хранилище, точно преди пренасочването. Те остават достъпни за следващата заявка след пренасочване и след това ги няма.

2.3. Структура на данните на FlashMap

Spring предоставя абстрактна структура от данни, наречена FlashMap за съхраняване на флаш атрибутите като двойки ключ-стойност.

Нека да разгледаме дефиницията на класа 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 екземпляра, а именно Input FlashMap и Output FlashMap, които играят важна роля в PRG модела:

  • Изходната FlashMap се използва в заявката POST за временно запазване на флаш атрибутите и изпращането им до следващата GET заявка след пренасочването
  • Входната FlashMap се използва в окончателната 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. Случай за използване на формуляра за подаване

Към момента установихме основно разбиране на различни концепции около флаш атрибутите. Така че, нека да продължим по-нататък и да ги използваме в уеб приложение за поетични състезания.

Нашето приложение за поетични състезания има прост случай на приемане на стихотворения от различни поети чрез подаване на формуляр. Освен това, в конкурса ще има необходимата информация, свързана със стихотворение, като заглавие, тяло и име на автора.

3.1. Конфигурация на мащерка

Ще използваме Thymeleaf, който е механизъм на Java шаблони за създаване на динамични уеб страници чрез прости HTML шаблони.

Първо, ние трябва да добавите пролетно-обувка стартер thymeleaf зависимостта към нашия проект pom.xml :

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

След това можем да дефинираме някои от специфичните за Thymeleaf свойства в нашия файл pplication.properties, разположен в директорията src / main / resources :

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. Модел на домейн

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

Тук е важно да отбележим, че трябва да проверим FlashMap, преди да решим да пренасочим към страницата за успех .

И накрая, нека използваме стихотворението flash flash в нашата страница за успех, за да покажем заглавието на стихотворението, изпратено от потребителя:

Click here to submit more.

4. Заключение

В този урок научихме няколко концепции около атрибутите Post / Redirect / Get pattern и flash. И също така видяхме флаш атрибути в действие с просто подаване на формуляр в уеб приложение Spring Boot.

Както винаги, пълният изходен код за урока е достъпен в GitHub.