Search buenodc

Nesta página
  1. Importante
  2. Contextualização
  3. O que já temos
  4. Como funciona
  5. Cronograma
  6. Missão 1: O formulário de contato vira template
  7. Missão 2: Validação com retorno ao formulário
  8. Missão 3: Fluxo de navegação com redirect
  9. Missão 4: Consolidando: sugestão de leitura + desafio
  10. Entrega individual

Atividade Formulários e Fluxo de Navegação (EstanteWeb)

Disciplina: Programação para Web 3
Assunto: Formulários com FreeMarker, validação com retorno ao formulário e fluxo de navegação (redirect)
Professor: Prof. Me. Danilo Bueno
Grupos: duplas
Duração: 4 aulas de 50 minutos (em sala)


Importante

Antes de começar, leia o material de apoio sobre formulários e fluxo de navegação. É imprescindível ler antes de codar: a atividade aplica exatamente os conceitos do material. Se tiver dúvidas, releia, pergunte ao professor ou aos colegas. Você também pode consultar os slides da aula.


Contextualização

Os dois formulários da EstanteWeb (contato e sugestão de leitura) hoje têm dois problemas de experiência: o HTML ainda é montado manualmente dentro do controller (a Semana 4 converteu as listagens para templates, mas deixou os formulários “para depois”), e um envio malsucedido devolve só um texto de erro cru, perdendo tudo o que a pessoa já havia digitado. Um envio bem-sucedido, por sua vez, também mostra só um texto de confirmação solto, sem levar a pessoa a lugar nenhum. Nesta etapa, a dupla vai fechar os dois formulários com templates de verdade, validação que preserva os dados digitados, e navegação real após o envio.


O que já temos

O checkpoint de partida (semana-05-inicio) traz a aplicação Spring Boot das semanas anteriores, já rodando em http://localhost:8080, com:

  • PaginaController (@RestController): rotas /, /sobre (texto simples), /contato (GET, formulário HTML montado manualmente) e POST /contato (ResponseEntity, valida mensagem em branco com 400).
  • LivroController/LivroRepository: acervo com /livros, /livros/total, /livros/busca, /livros/quem-acessa e /livros/html (este último já usa livros.ftlh, com <#include> do cabeçalho e <#if> para acervo vazio).
  • SugestaoController (@Controller): /sugestoes/nova (GET, formulário HTML ainda montado manualmente, com @ResponseBody), POST /sugestoes (ResponseEntity, sem validação) e GET /sugestoes (já usa sugestoes.ftlh).
  • Templates existentes: cabecalho.ftlh, livros.ftlh, sugestoes.ftlh, ola.ftlh (este último, de teste, sem uso real).

Como funciona

  • A atividade é feita em dupla, mas as entregas no Moodle são individuais.
  • As missões são incrementais: cada uma constrói sobre a anterior, siga na ordem.
  • Ao final de cada missão, teste no navegador (e no DevTools, quando indicado) antes de seguir.
  • Responda, no caminho, às perguntas em destaque (marcadas com >). Elas voltam no questionário do Moodle.

Cronograma

AulaFocoMissões
1O formulário de contato vira templateMissão 1
2Validação com retorno ao formulárioMissão 2
3Fluxo de navegação com redirectMissão 3
4Consolidando: sugestão de leitura + desafioMissão 4

Missão 1: O formulário de contato vira template

Objetivo: trocar o HTML montado manualmente em /contato por um template FreeMarker de verdade.

1.1. Em PaginaController, troque @RestController por @Controller; adicione @ResponseBody aos métodos das rotas / e /sobre, para que continuem devolvendo texto cru como antes (POST /contato, que usa ResponseEntity, não precisa de ajuste).

1.2. Crie o template contato.ftlh, com o mesmo formulário que já existia (campos nome e mensagem, método POST para /contato), reaproveitando <#include "cabecalho.ftlh"> no topo, igual às páginas da Semana 4.

1.3. Reescreva o método da rota GET /contato: remova produces = "text/html" e a montagem manual de String, adicione um parâmetro Model model e troque o retorno para "contato". Por enquanto deixe os dois retornos para a view contato. Teste no navegador: o formulário deve continuar com a mesma aparência de antes.

Compare o método de antes (retornando a String toda montada) com o de agora (retornando só "contato"). O que mudou na responsabilidade desse método, revisitando a separação de camadas estudada na Semana 4?


Missão 2: Validação com retorno ao formulário

Objetivo: quando a mensagem vier em branco, devolver o próprio formulário preenchido, com o erro indicado, em vez de um texto de erro cru.

2.1. No POST /contato, troque o retorno ResponseEntity do caso de erro: quando mensagem estiver em branco, adicione ao Model um atributo erro (com uma frase explicando o problema) e um atributo nome (com o valor já digitado), e retorne "contato" (o nome do template, não mais um ResponseEntity).

2.2. Ajuste contato.ftlh para exibir a mensagem de erro apenas quando ela existir, usando <#if erro??>, e para preencher o campo nome automaticamente com value="${nome!}" no <input> correspondente.

2.3. Teste enviando o formulário com o campo de mensagem vazio, mas com um nome preenchido: confirme que a página volta mostrando o erro e com o nome já preenchido no campo.

Sem o operador ! no ${nome!}, o que aconteceria ao acessar /contato pela primeira vez, antes de qualquer envio (quando o controller nunca adicionou "nome" ao Model)? Relembre o comportamento do FreeMarker diante de uma variável ausente, estudado na Semana 4.


Missão 3: Fluxo de navegação com redirect

Objetivo: ao concluir o envio com sucesso, levar o usuário a uma página própria de confirmação, em vez de devolver um texto solto.

3.1. Crie a rota GET /contato/sucesso, retornando o template contato-sucesso.ftlh (reaproveitando <#include "cabecalho.ftlh">), com uma mensagem simples de agradecimento.

3.2. No POST /contato, no caminho de sucesso (mensagem preenchida), troque o retorno ResponseEntity por "redirect:/contato/sucesso".

3.3. Teste no navegador: envie o formulário com os dois campos preenchidos e confirme que a URL muda para /contato/sucesso. Abra o DevTools (aba Network) antes de enviar, marque Preserve log, envie de novo e observe as duas requisições geradas: o POST para /contato e o GET que veio em seguida.

No DevTools, qual foi o status da resposta do POST? O que esse código, da família 3xx (estudada na Semana 1), tem a ver com o navegador ter disparado sozinho a segunda requisição?


Missão 4: Consolidando: sugestão de leitura + desafio

Objetivo: repetir, em SugestaoController, o mesmo padrão aplicado em PaginaController: template, validação com retorno ao formulário e redirecionamento.

4.1. Converta o método de /sugestoes/nova: crie o template sugestao-nova.ftlh (com <#include> do cabeçalho) e altere o método para usar Model e retornar "sugestao-nova", no lugar da montagem manual de String.

4.2. Adicione validação em POST /sugestoes: se nomeCliente ou livroSugerido vierem em branco, devolva o mesmo template ("sugestao-nova") com uma mensagem de erro e os campos já preenchidos reenviados ao Model, seguindo o mesmo padrão da Missão 2.

4.3. No caminho de sucesso, troque o retorno de POST /sugestoes por "redirect:/sugestoes" (a listagem já existente), no lugar do ResponseEntity com status 201.

4.4. Desafio (opcional): faça o redirecionamento de sucesso levar um parâmetro ("redirect:/sugestoes?enviada=true"); na rota GET /sugestoes, receba esse parâmetro como @RequestParam(required = false) Boolean enviada e, quando ele for true, exiba um aviso de sucesso no topo da listagem, usando <#if> no template sugestoes.ftlh.

No desafio, o parâmetro enviada=true aparece na URL da página de listagem, mas os dados da sugestão em si (nome e livro) não aparecem lá. Por que só o enviada atravessou o redirecionamento?


Entrega individual

Cada integrante da dupla deve, individualmente, no Moodle:

  1. Responder o questionário da semana (perguntas de reflexão sobre a atividade).
  2. Enviar o projeto compactado em .zip (a pasta do projeto sem a subpasta target/, que é gerada na compilação e pesa à toa).