Search buenodc

Nesta página
  1. Importante
  2. Contextualização
  3. O que já temos
  4. Como começar
  5. Como funciona
  6. Cronograma
  7. Missão 1: Ligando o FreeMarker
  8. Missão 2: Variáveis dinâmicas com Model
  9. Missão 3: Convertendo o acervo para um template
  10. Missão 4: Reaproveitando o padrão
  11. Entrega individual

Atividade Templates com FreeMarker (EstanteWeb)

Disciplina: Programação para Web 3
Assunto: Geração dinâmica de páginas, templates e FreeMarker
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 templates e FreeMarker. É 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

Até agora, toda página HTML da EstanteWeb foi montada por concatenação de String dentro do controller, incluindo a listagem do acervo (/livros/html) e a listagem de sugestões (/sugestoes). Funciona, mas qualquer ajuste visual exige editar texto dentro de código Java, sem destaque de sintaxe e com alto risco de esquecer uma tag. Nesta etapa, a dupla vai substituir essas páginas por templates FreeMarker de verdade, e vai revisitar uma decisão tomada lá na Semana 2: por que os controllers eram @RestController, e o que muda ao usar @Controller.


O que já temos

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

  • PaginaController: rotas /, /sobre (GET, texto simples) e /contato (GET com formulário HTML manual, POST recebendo os dados).
  • Livro (modelo): titulo, autor, ano, preco.
  • LivroRepository: acervo em memória, com listarTodos(), contarLivros() e listarAtePreco(double).
  • LivroController: rotas /livros, /livros/total, /livros/html (HTML montado manualmente), /livros/busca (com ResponseEntity) e /livros/quem-acessa. Todas as rotas de texto/HTML usam @RestController.
  • Sugestao e SugestaoRepository: guardam sugestões de leitura em memória.
  • SugestaoController: rotas /sugestoes/nova (formulário manual), POST /sugestoes e GET /sugestoes (listagem HTML manual). Também @RestController.

Como começar

  1. git clone do repositório do projeto (pule este passo se sua dupla já clonou nas semanas anteriores).
  2. git checkout semana-04-inicio para partir exatamente do estado descrito acima, mesmo que sua dupla não tenha terminado a semana passada.
  3. Rode a aplicação (./mvnw spring-boot:run ou o botão Run da IDE) e confirme que http://localhost:8080/livros/html responde como antes (a lista de livros montada manualmente).

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 antes de seguir.
  • Responda, no caminho, às perguntas em destaque (marcadas com >). Elas voltam no questionário do Moodle.

Cronograma

AulaFocoMissões
1Ligando o FreeMarkerMissão 1
2Variáveis dinâmicas com ModelMissão 2
3Convertendo o acervo para um templateMissão 3
4Reaproveitando o padrão + desafioMissão 4

Missão 1: Ligando o FreeMarker

Objetivo: adicionar a dependência do FreeMarker ao projeto e confirmar que um template estático é renderizado.

1.1. Abra o pom.xml do projeto e adicione, dentro de <dependencies>, a dependência do FreeMarker:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

Salve o arquivo. Se sua IDE perguntar se deseja recarregar o projeto Maven, aceite.

1.2. Crie a pasta src/main/resources/templates/ (se ainda não existir) e, dentro dela, o arquivo ola.ftlh, com um HTML estático simples (sem nenhuma variável), por exemplo um título de boas-vindas.

Dica de VS Code: por padrão, o editor abre .ftlh sem destaque de sintaxe. Com o arquivo aberto, use Ctrl+Shift+P (Cmd+Shift+P no Mac) → Change Language Mode → HTML → Configure File Association for ‘.ftlh’… → HTML de novo. Faça isso agora, uma única vez; vale para todos os .ftlh do projeto daqui em diante.

1.3. Crie a classe TesteController, anotada com @Controller (não @RestController), com uma rota @GetMapping("/ola") que apenas retorna "ola" (o nome do template, sem extensão e sem parênteses de método). Reinicie a aplicação e acesse http://localhost:8080/ola no navegador.

O método de TesteController retornou a String "ola", mas o navegador não exibiu o texto “ola” na tela. Compare com o que acontecia nos controllers @RestController das semanas anteriores: o que o Spring faz com o valor retornado quando o controller é @Controller, em vez de escrever esse valor direto no corpo da resposta?


Missão 2: Variáveis dinâmicas com Model

Objetivo: enviar dados do controller para o template através do Model.

2.1. Em ola.ftlh, acrescente uma variável no meio do texto, por exemplo ${nomeLoja}, dentro de uma frase de boas-vindas.

2.2. Altere o método de TesteController para receber um parâmetro Model model, chamar model.addAttribute("nomeLoja", "EstanteWeb") antes do return, e mantenha o retorno "ola". Reinicie e recarregue /ola: confirme que o nome aparece na página.

2.3. Adicione uma segunda variável ao template e ao Model, desta vez numérica (por exemplo, um ${anoFundacao} com o valor 1998). Recarregue a página e observe com atenção como o número aparece.

O número apareceu como 1,998, com uma vírgula que você não escreveu em lugar nenhum. Releia, no material de apoio, a explicação sobre formatação de números do FreeMarker (seção 4) e ajuste o template usando o built-in indicado lá, até o número aparecer como 1998.

2.4. Confirme que, após o ajuste, tanto ${nomeLoja} quanto o ano aparecem corretamente na página, sem vírgula.

Remova temporariamente a linha model.addAttribute("nomeLoja", ...) do controller, sem remover ${nomeLoja} do template, e recarregue a página. O que acontece? Depois, devolva a linha removida.


Missão 3: Convertendo o acervo para um template

Objetivo: substituir a listagem manual de /livros/html por um template FreeMarker de verdade, ajustando o controller para conviver com as rotas que continuam devolvendo texto cru.

3.1. Crie o template livros.ftlh, com um título e uma lista <ul>, usando <#list livros as livro> para percorrer o acervo e exibir ${livro.titulo}, ${livro.autor} e ${livro.preco?c} em cada <li> (o ?c que você usou na Missão 2 evita que o preço ganhe separador de milhar, mantendo o mesmo formato da rota /livros).

3.2. Em LivroController, troque @RestController por @Controller. Isso muda o comportamento de todos os métodos da classe que retornam String: adicione @ResponseBody aos métodos listar(), total() e quemAcessa(), para que continuem devolvendo o texto cru como antes (o método buscar(), que já usa ResponseEntity, não precisa de nenhum ajuste).

3.3. Reescreva o método da rota /livros/html: remova o produces = "text/html" e a montagem manual da String, adicione um parâmetro Model model, preencha model.addAttribute("livros", repositorio.listarTodos()) e troque o retorno para "livros". Reinicie a aplicação e acesse /livros/html: confirme que a lista aparece igual a antes, agora gerada pelo template.

O acervo tem um livro cujo título contém a tag <b>Grande</b> (adicionado na Semana 2, para mostrar a diferença de Content-Type). Como esse título aparece agora, renderizado por ${livro.titulo} num arquivo .ftlh, comparado a como aparecia na versão antiga, montada por concatenação de String? O que explica a diferença?


Missão 4: Reaproveitando o padrão

Objetivo: tratar o caso de acervo vazio com <#if> e repetir a conversão em SugestaoController, consolidando o padrão aprendido.

4.1. Em livros.ftlh, envolva a lista num <#if livros?size == 0>, exibindo uma mensagem alternativa (por exemplo, “Nenhum livro no acervo no momento”) quando não houver livros, e a lista normal no <#else>. Não é preciso esvaziar o acervo de verdade para conferir a lógica; basta ler o código e garantir que ele cobre os dois casos.

4.2. Repita a conversão em SugestaoController: troque @RestController por @Controller; adicione @ResponseBody ao método de /sugestoes/nova (o formulário, que continua sendo montado manualmente por enquanto) para preservar seu comportamento (o método de POST /sugestoes, que usa ResponseEntity, não precisa de ajuste); crie o template sugestoes.ftlh com <#list> e converta o método de GET /sugestoes para usar Model e retornar o nome do template.

4.3. Confirme, testando as duas rotas convertidas (/livros/html e /sugestoes) no navegador, que o resultado visual é idêntico ao da versão anterior, mesmo com o HTML agora vindo de arquivos .ftlh separados.

4.4. Desafio (opcional): crie o template cabecalho.ftlh, com um cabeçalho simples (nome da loja e um link de volta para /), e insira-o com <#include "cabecalho.ftlh"> no início de livros.ftlh e de sugestoes.ftlh. Confirme que o cabeçalho aparece nas duas páginas.

Antes do <#include>, se a dupla quisesse adicionar um link de navegação em todas as páginas HTML da EstanteWeb, seria preciso editar quantos arquivos? E depois de extrair o cabeçalho compartilhado?


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