Atividade Cadastro de Informações (EstanteWeb)
Disciplina: Programação para Web 3
Assunto: INSERT, formulários de cadastro e persistência de dados
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 cadastro de informações. É 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
Desde a semana passada, o acervo exibido no site vem de verdade do banco de dados. Mas a dona da EstanteWeb ainda não consegue cadastrar um livro novo: para incluir qualquer título, alguém precisa abrir o terminal do MySQL e escrever um INSERT à mão. Nesta etapa, a dupla vai construir a tela de cadastro do acervo, com validação e gravação real no banco, encerrando a dependência do terminal.
O que já temos
O checkpoint de partida (semana-08-inicio) traz a aplicação Spring Boot das semanas anteriores, já rodando em http://localhost:8080, com:
LivroRepository(@Repository), com@Autowired JdbcTemplatee os métodos de consulta:listarTodos(),contarLivros(),listarAtePreco(double)esomarValorAcervo().Livro, com construtor sem argumentos, getters, setters e o método estáticodeMap(Map).LivroController(@Controller), com as rotas do acervo, entre elas/livros/html, que exibe a listagem pelo templatelivros.ftlh.- Templates
cabecalho.ftlh,livros.ftlh,contato.ftlh,contato-sucesso.ftlhesugestao-nova.ftlh, todos já com<#include>do cabeçalho. - Banco MySQL com a tabela
livropopulada.
Como começar
git clonedo repositório do projeto (pule este passo se sua dupla já clonou nas semanas anteriores).git checkout semana-08-iniciopara partir exatamente do estado descrito acima.- Confirme que o container MySQL está no ar (
docker ps). Se não estiver, suba-o comdocker start estanteweb-mysql. - Rode a aplicação e confirme que
http://localhost:8080/livros/htmlexibe o acervo vindo do banco.
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
| Aula | Foco | Missões |
|---|---|---|
| 1 | O formulário de cadastro | Missão 1 |
| 2 | Gravando no banco com update | Missão 2 |
| 3 | Validação e fluxo de navegação | Missão 3 |
| 4 | Cadastro de sugestões + desafio | Missão 4 |
Missão 1: O formulário de cadastro
Objetivo: criar a tela que coleta os dados de um novo livro, sem ainda gravá-la.
1.1. Crie o template livro-novo.ftlh, com <#include "cabecalho.ftlh"> no topo e um <form method="post" action="/livros"> contendo quatro campos de texto: titulo, autor, ano e preco, além do botão de envio. Use value="${titulo!}" (e equivalentes) em cada campo.
1.2. Em LivroController, crie a rota GET /livros/novo, que apenas retorna "livro-novo".
1.3. Acesse http://localhost:8080/livros/novo e confirme que o formulário aparece. Clique em enviar e observe o erro retornado: ainda não existe nenhuma rota que receba esse POST.
O formulário aponta para
/livrosno atributoaction, mas essa rota já existe comoGET. Por que o envio não caiu na rota de listagem que já estava lá?
Missão 2: Gravando no banco
Objetivo: criar o método que insere um livro e a rota que o utiliza.
2.1. Em LivroRepository, crie o método salvar(Livro livro), que executa INSERT INTO livro (titulo, autor, ano, preco) VALUES (?, ?, ?, ?) com jdbcTemplate.update(...), passando os quatro valores na ordem correta.
2.2. Em LivroController, crie a rota POST /livros, recebendo titulo, autor, ano (tipo int) e preco (tipo double) via @RequestParam. Monte um Livro com os setters, chame repositorio.salvar(livro) e, por enquanto, retorne "redirect:/livros/html".
2.3. Cadastre um livro pelo formulário e confirme que ele aparece na listagem. Confirme também pelo terminal do MySQL, com SELECT * FROM livro;.
O
INSERTnão informa a colunaid, mas o livro cadastrado apareceu com umidpreenchido no banco. Quem atribuiu esse valor, e com base em que definição feita na Semana 6?
Missão 3: Validação e fluxo de navegação
Objetivo: impedir cadastros inválidos e devolver o formulário preenchido quando houver erro.
3.1. No POST /livros, antes de gravar, valide os dados: se titulo ou autor vierem em branco, ou se preco for menor ou igual a zero, adicione ao Model um atributo erro com a mensagem adequada, reenvie os valores digitados (titulo, autor, ano, preco) e retorne "livro-novo".
3.2. Ajuste livro-novo.ftlh para exibir a mensagem de erro apenas quando ela existir, usando <#if erro??>.
3.3. Teste os dois caminhos: envie o formulário com o título em branco (deve voltar com o erro e os demais campos preenchidos) e depois com todos os campos válidos (deve gravar e redirecionar para a listagem).
Por que a validação precisa acontecer antes da chamada a
repositorio.salvar(...), e não depois? O que aconteceria com um dado inválido que chegasse ao banco?
Missão 4: Cadastro de sugestões + desafio
Objetivo: aplicar o mesmo padrão à sugestão de leitura, que até agora só existia em memória.
4.1. Em SugestaoRepository, adicione @Repository à classe e um campo @Autowired JdbcTemplate, mantendo a lista em memória por enquanto, como feito na Semana 7 com o LivroRepository.
4.2. Crie o método salvar(Sugestao sugestao), executando INSERT INTO sugestao (nome_cliente, livro_sugerido) VALUES (?, ?) com jdbcTemplate.update(...). A tabela sugestao já existe desde a Semana 6.
4.3. Em SugestaoController, troque a chamada repositorio.adicionar(...) por repositorio.salvar(...) no POST /sugestoes. Envie uma sugestão pelo formulário e confirme, pelo terminal do MySQL, que a linha foi gravada na tabela.
4.4. Desafio (opcional): faça a listagem de sugestões (GET /sugestoes) passar a ler do banco, criando o método listarTodas() com queryForList e um Sugestao.deMap(Map), no mesmo formato usado no Livro. Remova então a lista em memória de SugestaoRepository. Reinicie a aplicação e confirme que as sugestões enviadas antes do reinício continuam aparecendo.
No desafio, as sugestões passaram a sobreviver ao reinício da aplicação. Compare com o comportamento observado na Semana 3, quando essa mesma listagem foi criada: o que mudou?
Entrega individual
Cada integrante da dupla deve, individualmente, no Moodle:
- Responder o questionário da semana (perguntas de reflexão sobre a atividade).
- Enviar o projeto compactado em
.zip(a pasta do projeto sem a subpastatarget/, que é gerada na compilação e pesa à toa).