Guia de atributos do Flash em um aplicativo Web Spring

Guia de atributos do Flash em um aplicativo Web Spring

1. Visão geral

Os aplicativos da Web geralmente dependem da entrada do usuário para atender a vários de seus casos de uso. Como resultado, o envio de formulários é um mecanismo muito usado para coletar e processar dados para esses aplicativos.

Neste tutorial, aprenderemos comoSpring’s flash attributes can help us with the form submission workflow com segurança e confiabilidade.

2. Noções básicas de atributos do Flash

Antes de podermos usar confortavelmente atributos de flash, precisamos criar um nível decente de entendimento do fluxo de trabalho de envio de formulários e alguns conceitos-chave relacionados.

2.1. Post/Redirect/Get Pattern

Uma maneira ingênua de criar um formulário da web seria usar uma única solicitaçãoHTTP POST que cuida do envio e dá uma confirmação por meio de sua resposta. No entanto, esse design expõe o risco de processamento duplicado de solicitações POST, caso o usuário acabe atualizando a página.

To mitigate the issue of duplicate processing, we can create the workflow as a sequence of interconnected requests in a specific order — namely, POST, REDIRECT, and GET. Resumindo, chamamos isso de padrãoPost/Redirect/Get (PRG) para envio de formulário.

Ao receber a solicitação POST, o servidor a processa e depois transfere o controle para fazer uma solicitação GET. Posteriormente, a página de confirmação é exibida com base na resposta da solicitação GET. Idealmente, mesmo que a última solicitação GET seja tentada mais de uma vez, não deve haver nenhum efeito colateral adverso.

2.2. Ciclo de vida dos atributos do Flash

Para concluir o envio do formulário usando o padrãoPRG, precisaremos transferir as informações da solicitação POST inicial para a solicitação GET final após o redirecionamento.

Infelizmente, não podemos usar oRequestAttributes nem oSessionAttributes.. Isso porque o primeiro não sobreviverá a um redirecionamento entre controladores diferentes, enquanto o último durará por toda a sessão, mesmo depois que o envio do formulário terminar.

Mas não precisamos nos preocupar, pois a estrutura da web do Spring fornece atributos de flash que podem corrigir esse problema exato.

Vamos ver os métodos na interfaceRedirectAttributes que podem nos ajudar a usar atributos Flash em nosso projeto:

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

RedirectAttributes addFlashAttribute(Object attributeValue);

Map getFlashAttributes();

Flash attributes are short-lived. Como tal, eles são armazenados temporariamente em algum armazenamento subjacente, imediatamente antes do redirecionamento. Eles permanecem disponíveis para a solicitação subsequente após o redirecionamento e, em seguida, desaparecem.

2.3. Estrutura de dadosFlashMap

Spring fornece uma estrutura de dados abstrata chamadaFlashMap para armazenar os atributos de flash como pares chave-valor.

Vamos dar uma olhada na definição da classeFlashMap:

public final class FlashMap extends HashMap implements Comparable {

    @Nullable
    private String targetRequestPath;

    private final MultiValueMap targetRequestParams = new LinkedMultiValueMap<>(4);

    private long expirationTime = -1;
}

Podemos notar que a classeFlashMap herda seu comportamento da classeHashMap. Como tal, aFlashMap instance can store a key-value mapping of the attributes. Além disso, podemos vincular uma instânciaFlashMap para ser usada apenas por um URL de redirecionamento específico.

Além disso, cada solicitação tem duas instâncias deFlashMap, ou seja, InputFlashMap e OutputFlashMap, que desempenham um papel importante no padrão PRG:

  • A saídaFlashMap é usada na solicitação POST para salvar temporariamente os atributos do flash e enviá-los para a próxima solicitação GET após o redirecionamento

  • A entradaFlashMap é usada na solicitação GET final para acessar os atributos flash somente leitura que foram enviados pela solicitação POST anterior antes do redirecionamento

2.4. FlashMapManager eRequestContextUtils

Como o nome sugere, podemos usarFlashMapManager para gerenciar as instânciasFlashMap.

Primeiro, vamos dar uma olhada na definição desta interface de estratégia:

public interface FlashMapManager {

    @Nullable
    FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);

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

Simplificando, podemos dizer queFlashMapManager nos permite ler, atualizar e salvar instâncias deFlashMap em algum armazenamento subjacente.

A seguir, vamos nos familiarizar com algunsstatic methods available in the RequestContextUtils abstract utility class.

Para manter nosso foco dentro do escopo deste tutorial, limitaremos nossa cobertura aos métodos que são relevantes para os atributos de 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);

Podemos usar esses métodos para recuperar as instâncias de entrada / saídaFlashMap, obterFlashMapManager para uma solicitação e salvar uma instânciaFlashMap.

3. Caso de uso de envio de formulário

Até agora, estabelecemos um entendimento básico de diferentes conceitos em torno de atributos de flash. Então, vamos avançar e usá-los em um aplicativo da web de concurso de poesia.

Nosso aplicativo de concurso de poesia tem um caso de uso simples de aceitar entradas de poemas de diferentes poetas através do envio de um formulário. Além disso, a inscrição no concurso terá as informações necessárias relacionadas a um poema, como um título, um corpo e o nome do autor.

3.1. Configuração do Thymeleaf

Estaremos usandoThymeleaf, which is a Java template engine for creating dynamic web pages por meio de modelos HTML simples.

Primeiro, precisamos adicionar a dependênciaspring-boot-starter-thymeleaf aopom.xml do nosso projeto:


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

A seguir, podemos definir algumas das propriedades específicas do Thymeleaf em nosso arquivo application.properties localizado no diretóriosrc/main/resources:

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

Tendo definido essas propriedades, podemos agora criar todas as nossas visualizações no diretório/src/main/resources/templates. Por sua vez, o Spring acrescentará o sufixo.html a todas as visualizações nomeadas dentro de nosso controlador.

3.2. Modelo de domínio

A seguir, vamosdefine our domain model em uma classePoem:

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

Além disso, podemos adicionar o método estáticoisValidPoem() em nossa classePoem para nos ajudar a validar que os campos não permitem strings vazias:

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

3.3. Criar formulário

Agora, estamos prontos para criar nosso formulário de inscrição. Para isso,we need an endpoint /poem/submit that will serve a GET request to show the form para o usuário:

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

Aqui, usamos um modelo como um contêiner para armazenar os dados específicos do poema fornecidos pelo usuário. Além disso, o métodosubmitGet retorna uma visão servida pela visãosubmit.

Além disso, queremos vincular o formulário POST ao atributo de modelopoem:

3.4. Post/Redirect/Get Submission Flow

Agora, vamos habilitar a ação POST para o formulário. Para fazer isso, vamos criar o/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);
    }
}

Podemos notar que ponto finalif the submission is successful, then control transfers to the /poem/success. Além disso, adicionamos os dados do poema como um atributo flash antes de iniciar o redirecionamento.

Agora, precisamos mostrar uma página de confirmação ao usuário, então vamos implementar a funcionalidade para o endpoint/poem/success que atenderá à solicitação GET:

@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 notar aqui que nósneed to validate the FlashMap before we decide to redirect to the success page.

Finalmente, vamos usar o atributo flashpoem inside nossa página de sucesso para mostrar o título do poema enviado pelo usuário:

Click here to submit more.

4. Conclusão

Neste tutorial, aprendemos alguns conceitos sobre os atributos Padrão e Flash / Redirecionar / Obter. E também vimos atributos em flash em ação com um simples envio de formulário em um aplicativo da Web Spring Boot.

Como sempre, o código-fonte completo do tutorial está disponívelover on GitHub.