Quando temos um formulário HTML queremos garantir que os dados fornecidos respeite determinados intervalos e que determinados formatos sejam seguidos. Por exemplo, queremos garantir que o usuário não tenha -345 anos ou que seu endereço de e-mail seja válido.

Em geral, você desejará executar a validação do lado do cliente (HTML5), bem como a validação do lado do servidor. A validação do lado do cliente garante que os dados inválidos nem cheguem ao back-end, enquanto a validação do lado do servidor garante que os dados errados não sejam processados ou salvos no banco de dados.

Neste codelab você continuará o projeto desenvolvido em aula e adicionará a validação de dados de formulário com Spring Boot e Thymeleaf. Faça a clonagem do repositório para iniciar o codelab.

O que você vai aprender

Precisamos adicionar a dependência abaixo no arquivo pom.xml para utilizar a validação:

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

A validação de campos é suportado por restrições na forma de anotações colocadas em uma variável em classes da camada model. Veja exemplo abaixo:

package com.professorangoti.condominio.model;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Proprietario {
    private Long id;

    @NotEmpty
    private String nome;

    @NotEmpty
    @Size(min = 9, max = 11, message = "informe o telefone com apenas dígitos, com o tamanho entre 9 e 11 dígitos")
    private String telefone;
}

Aqui você encontra uma lista completa das anotações de validação.

<html th:include="template :: modelo">
    <div th:fragment="conteudo">
        <form action="/cad_prop" method="post" th:object="${proprietario}">
            <div class="mb-3">
                <label for="nome" class="form-label">Nome</label>
                <input type="text" class="form-control" th:field="*{nome}">
                <div class="alert alert-warning" th:if="${#fields.hasErrors('nome')}" th:errors="*{nome}"></div>
            </div>
            <div class="mb-3">
                <label for="telefone" class="form-label">Telefone</label>
                <input type="text" class="form-control" th:field="*{telefone}">
                <div class="alert alert-warning" th:if="${#fields.hasErrors('telefone')}" th:errors="*{telefone}"></div>
            </div>
            <button type="submit" class="btn btn-primary">Gravar</button>
        </form>
    </div>
</html>

A inha

adiciona dois comandos Thymeleaf:

th:if é um condicional que quando é avaliado como falso não exibe o componente HTML que contem o condicional.

Precisamos mostrar mensagens de validação para informar o usuário sobre os erros que ele cometeu. Thymeleaf oferece algumas ferramentas para isso: algumas funções no objeto #fields e o atributos th:errors.

A função #fields.hasErrors recebe a nome do campo como parâmetro (por exemplo nome), e retorna um booleano informando se existe algum erro de validação para aquele campo.

th:errors exibe as mensagens de erro para o campo informado como valor do atributo.

Agora, vamos alterar o controlador que recebe os dados enviados pelo browser para salvar um proprietário no banco de dados. Como de costume, teremos um @GetMapping para mostrar o formulário e um @PostMapping para lidar com os dados do formulário. Na assinatura do método anotado com @PostMapping, anotaremos o parâmetro que representa os dados do formulário com @Valid. A anotação @Valid aciona um validador para verificar se os campos preenchidos no objeto estão de acordo com as anotações que usamos na definição da classe. O segundo parâmetro é um objeto que retorna o resultado da validação, e é usado para testar se o preenchimento do formulário contém erros:

@GetMapping("cad_prop")
    public String formCadastroProprietario(Model model) {
        model.addAttribute("proprietario", new Proprietario());
        return "form_prop";
}

@PostMapping("cad_prop")
    public String gravaNovoProprietario(@Valid Proprietario proprietario, BindingResult validacao) {
        if (validacao.hasErrors())
            return "form_prop";
        repository.save(proprietario);
        return "redirect:/rel_prop";
}