pelas páginas: o CRUD completo no navegador
Vamos continuar no mesmo projeto series. Ele já tem duas páginas geradas pelo Thymeleaf, a lista e o formulário de cadastro:
Agora a lista ganha as duas operações do CRUD que ainda não existem nas páginas: editar e remover.
A validação responde: "este valor pode ser aceito?". Mesmo assim, um valor aceito pode não ser o valor correto: alguém cadastra Arcane com o gênero Fantasia e depois percebe que queria Animação.
| Nome | Plataforma | Ano | Gênero |
|---|---|---|---|
| Stranger Things | Netflix | 2016 | Ficção científica |
| Round 6 | Netflix | 2021 | Suspense |
| Arcane | Netflix | 2021 | Fantasia |
Pelas páginas, ainda não há como corrigir. A única saída é a rota
do SerieController, pelo Postman, que é exatamente o que as páginas vieram substituir.
Editar pelas páginas exige duas rotas novas no SeriePaginaController, como no cadastro:
O que muda em relação ao cadastro é que a página de edição precisa saber qual série está sendo editada.
Cada linha da tabela ganha um link para a edição daquela série. Como o endereço muda de uma linha para outra, ele não pode ser escrito fixo no href: quem monta o endereço é o Thymeleaf, com o id da série da linha.
A tabela também ganha uma coluna Ações no cabeçalho.
| Nome | Plataforma | Ano | Gênero | Ações |
|---|---|---|---|---|
| Stranger Things | Netflix | 2016 | Ficção científica | Editar |
| Round 6 | Netflix | 2021 | Suspense | Editar |
| Arcane | Netflix | 2021 | Fantasia | Editar |
monta o endereço de um link com dados da página.
Ou seja, para a série de id 3, o navegador recebe href="/paginas/series/3/editar".
Esta rota é parecida com a que mostra o formulário de cadastro, com uma diferença: em vez de uma Serie vazia, criada com new, ela entrega à página a Serie que já está no banco, buscada pelo id do caminho.
@PathVariable é a mesma anotação do encontro 9: lê o {id} do endereço e entrega como parâmetro do método.
A página de edição é uma cópia de formulario.html, salva como templates/series/edicao.html, em que mudam o título, o action e o texto do botão.
Como a Serie entregue pelo controller já tem dados, o th:field preenche cada campo com o valor atual, e a pessoa altera só o que precisa.
O POST da edição recebe uma nova Serie montada com os pares enviados pelo formulário, como no cadastro.
Depois, chama o atualizar do SerieDAO, que usa o merge do EntityManager, e redireciona.
| Nome | Plataforma | Ano | Gênero | Ações |
|---|---|---|---|---|
| Stranger Things | Netflix | 2016 | Ficção científica | Editar |
| Round 6 | Netflix | 2021 | Suspense | Editar |
| Arcane | Netflix | 2021 | Fantasia | Editar |
| Arcane | Netflix | 2021 | Animação | Editar |
Ao salvar a edição, a lista mostra a série antiga e, logo abaixo, uma série nova com os dados alterados.
Isso acontece pois o formulário enviou nome, plataforma, ano e gênero, mas não enviou o id. O @ModelAttribute montou uma Serie com id nulo, e o merge de um objeto sem id não tem linha para atualizar.
Ele grava uma linha nova, e o banco executa um INSERT no lugar do UPDATE.
Para que o id seja enviado, o formulário precisa de um campo com ele. Usamos um input do tipo hidden, que vai na requisição como qualquer outro campo, mas não aparece na página.
Com o par id=1 no corpo, o @ModelAttribute chama setId(1), e o merge encontra a linha e atualiza.
A edição passa pela mesma conferência do cadastro: as regras são as mesmas anotações da Serie, e só muda a página devolvida quando há erro, que agora é series/edicao.
Como o id também voltou no formulário, a página de edição reaparece com as mensagens e com o id preservado no campo oculto.
A loja percebeu que alguns jogos foram cadastrados com o ano errado e quer corrigir pela página.
Para remover, basta o id da série: não há formulário para preencher. Mesmo assim, a remoção não pode ser um link, porque um link faz um GET, e um GET serve para buscar dados, não para alterá-los.
Logo, cada linha da lista ganha um pequeno formulário com method="post" e um único botão, que envia o pedido de remoção daquela série.
O formulário não tem nenhum campo, porque o id já vai no endereço. Para montar esse endereço, usamos th:action, que funciona como o th:href, mas gera o action do formulário.
Ao clicar no botão, o navegador envia um POST para o endereço da própria linha.
| Nome | Plataforma | Ano | Gênero | Ações |
|---|---|---|---|---|
| Stranger Things | Netflix | 2016 | Ficção científica | EditarRemover |
| Round 6 | Netflix | 2021 | Suspense | EditarRemover |
O método lê o id do caminho com @PathVariable e chama o remover do SerieDAO, o mesmo usado pela rota DELETE /series/{id}, que busca a série com find e a apaga com remove.
Depois, redireciona para a lista, que já aparece sem a série.
A loja quer tirar da lista os jogos que já foram vendidos.

Quer trocar mais uma ideia? Me chama!