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: A ficha de um livro
  8. Missão 2: Endereços que não levam a lugar nenhum
  9. Missão 3: Navegação de ida e volta
  10. Missão 4: Caminho ou query string + desafio
  11. Entrega individual

Atividade Navegação entre Recursos (EstanteWeb)

Disciplina: Programação para Web 3
Assunto: URLs parametrizadas, Path Variables e páginas de detalhes
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 navegação entre recursos. É 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

O site da EstanteWeb já lista o acervo e permite cadastrar títulos novos, mas a listagem é um beco sem saída: o cliente vê os livros em uma única tela corrida e não consegue abrir nenhum deles. Não há como ver a ficha de um título, nem como mandar o link de um livro para um amigo, porque o livro não tem endereço. Nesta etapa, a dupla vai dar a cada livro do acervo uma página própria, tratar corretamente os endereços que não levam a lugar nenhum e ligar a listagem às fichas.


O que já temos

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

  • LivroRepository (@Repository), com @Autowired JdbcTemplate, os métodos de consulta (listarTodos(), contarLivros(), listarAtePreco(double), somarValorAcervo()) e o método salvar(Livro), que executa o INSERT.
  • Livro, com construtor sem argumentos, getters, setters e o método estático deMap(Map).
  • LivroController (@Controller), com /livros/html exibindo a listagem pelo template livros.ftlh, GET /livros/novo exibindo o formulário e POST /livros gravando com validação.
  • SugestaoRepository e SugestaoController, já gravando sugestões no banco.
  • Templates cabecalho.ftlh, livros.ftlh, livro-novo.ftlh, contato.ftlh, contato-sucesso.ftlh e sugestao-nova.ftlh.
  • Banco MySQL com as tabelas livro e sugestao populadas.

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-09-inicio para partir exatamente do estado descrito acima.
  3. Confirme que o container MySQL está no ar (docker ps). Se não estiver, suba-o com docker start estanteweb-mysql.
  4. Rode a aplicação e confirme que http://localhost:8080/livros/html exibe o acervo vindo do banco.
  5. No terminal do MySQL, rode SELECT id, titulo FROM livro; e anote dois identificadores que existem e um que não existe. Você vai usá-los nos testes.

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
1A ficha de um livroMissão 1
2Endereços que não levam a lugar nenhumMissão 2
3Navegação de ida e voltaMissão 3
4Caminho ou query string + desafioMissão 4

Missão 1: A ficha de um livro

Objetivo: fazer com que cada livro do acervo tenha um endereço próprio e uma página que o exiba.

1.1. Em LivroRepository, crie o método buscarPorId(Long id), que executa SELECT * FROM livro WHERE id = ? com queryForList, devolve null quando a consulta não trouxer nenhuma linha e, caso contrário, converte a primeira linha com Livro.deMap(...).

1.2. Crie o template livro.ftlh, com <#include "cabecalho.ftlh"> no topo, exibindo título, autor, ano e preço do livro recebido. Lembre-se de que esta página recebe um objeto, não uma lista.

1.3. Em LivroController, crie a rota GET /livros/{id}, recebendo o identificador com @PathVariable Long id, buscando o livro no repositório, enviando-o ao Model e retornando "livro".

1.4. Acesse no navegador o endereço de um dos identificadores que você anotou (por exemplo, http://localhost:8080/livros/1) e confirme que a ficha aparece com os dados corretos.

Por que o identificador do livro foi colocado no caminho da URL, e não na query string? Cite uma vantagem concreta dessa escolha para o cliente da loja.


Missão 2: Endereços que não levam a lugar nenhum

Objetivo: fazer a aplicação responder corretamente quando o endereço é válido na forma, mas não corresponde a nenhum livro.

2.1. Acesse o endereço do identificador que não existe (por exemplo, http://localhost:8080/livros/999) e observe o que acontece. Anote a mensagem de erro e o código de status exibido na aba Network do DevTools.

2.2. No GET /livros/{id}, verifique se o livro devolvido pelo repositório é null e, nesse caso, lance new ResponseStatusException(HttpStatus.NOT_FOUND) antes de usar o objeto. Teste novamente o endereço inexistente e confirme, no DevTools, que o status agora é 404.

2.3. Acesse http://localhost:8080/livros/abc e observe o status devolvido no DevTools. Anote qual é e em que momento ele acontece: antes ou depois de o corpo do método executar.

Os endereços /livros/999 e /livros/abc devolvem códigos de status diferentes. Explique o que cada código informa ao navegador e por que não faria sentido usar o mesmo nos dois casos.


Missão 3: Navegação de ida e volta

Objetivo: ligar a listagem às fichas, de modo que o cliente navegue pelo acervo sem digitar endereços.

3.1. Em livros.ftlh, transforme o título de cada livro em um link para a ficha correspondente, montando o endereço a partir do identificador do próprio registro.

3.2. Clique em um dos links e confirme que a ficha correta abre. Se o endereço aparecer com vírgula (algo como /livros/1,998), ajuste a impressão do número no template.

3.3. Em livro.ftlh, acrescente um link “Voltar para o acervo”, apontando para a listagem.

3.4. Percorra o fluxo completo: abra a listagem, entre em uma ficha, volte, entre em outra. Use também o botão voltar do navegador e confirme que ele se comporta como esperado.

O que acontece com o endereço gerado no link quando o identificador do livro é impresso sem o tratamento de formatação de número? Explique por que o problema só aparece a partir de certos valores.


Missão 4: Caminho ou query string + desafio

Objetivo: usar as duas formas de passar valor pela URL na mesma tela e perceber a diferença entre elas na prática.

4.1. Em LivroController, altere a rota GET /livros/html para aceitar um parâmetro opcional de ordenação pela query string, recebido com @RequestParam(required = false) String ordem.

4.2. Em LivroRepository, crie o método listarOrdenadoPor(String coluna), que monta o SELECT * FROM livro ORDER BY ... apenas quando a coluna recebida for uma das permitidas (titulo, autor, ano ou preco), e cai na listagem padrão em qualquer outro caso. Use a listagem sem ordenação quando o parâmetro não vier.

4.3. Teste http://localhost:8080/livros/html?ordem=preco e http://localhost:8080/livros/html?ordem=titulo. Confirme que a listagem muda de ordem e que os links das fichas continuam funcionando. Teste também sem o parâmetro.

4.4. Desafio (opcional): na ficha de um livro, exiba também os outros títulos do mesmo autor. Crie em LivroRepository o método listarDoMesmoAutor(String autor, Long idAtual), usando SELECT * FROM livro WHERE autor = ? AND id <> ?, e liste os resultados em livro.ftlh como links para as respectivas fichas. Se não houver outros títulos, a seção não deve aparecer.

Na Missão 4 o valor da ordenação foi para a query string, enquanto na Missão 1 o identificador do livro foi para o caminho. Justifique por que cada valor foi parar onde foi, usando a diferença entre identificar um recurso e ajustar a forma de exibi-lo.


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