Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

Problema no uso do thymeleaf

Estou criando um projeto pra ficar treinando enquanto não sai o resto da formação, mas estou tendo duvidas quando vou usar o thymeleaf sempre da algum erro. Vou deixar o código abaixo, se alguém identificar o erro e poder dar uma dica.

Classe Vaga:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name = "tb_vagas")
public class Vaga {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String nomeDaVaga;
    private String descricaoDaVaga;
    private LocalDate dataDaAberturaDaVaga;
    private LocalDate dataDeFechamentoDaVaga;
    @Enumerated(EnumType.STRING)
    private FormacaoAcademica formacaoAcademicaNecessaria;
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private List<Candidato> candidatoList;
    private Boolean vagaAtiva;

    public Vaga(DadosCadastroVagasDTO dados) {
        this.setNomeDaVaga(dados.nomeDaVaga());
        this.setDescricaoDaVaga(dados.descricaoDaVaga());
        this.setDataDaAberturaDaVaga(dados.dataDeAberturaDaVaga());
        this.setDataDeFechamentoDaVaga(dados.dataDeFechamentoDaVaga());
        this.setFormacaoAcademicaNecessaria(dados.formacaoAcademica());
        this.setCandidatoList(dados.candidatoList());
        this.setVagaAtiva(true);
    }

}

Record:


public record DadosCadastroVagasDTO(
        @NotBlank
        String nomeDaVaga,
        @NotBlank
        String descricaoDaVaga,
        @NotNull
        LocalDate dataDeAberturaDaVaga,
        @NotNull
        LocalDate dataDeFechamentoDaVaga,
        @NotNull
        FormacaoAcademica formacaoAcademica,
        List<Candidato> candidatoList
) {
}

VagaService:

@Service
public class VagaService {

    @Autowired
    private VagaRepository repository;
    
    @Transactional
    public Vaga cadastrarVaga(DadosCadastroVagasDTO dados) {
        var vaga = new Vaga(dados);
        return repository.save(vaga);
    }
}

VagaController:

@Controller
@RequestMapping("vagas")
public class VagaController {
    @Autowired
    private VagaService service;
    @Autowired
    private VagaRepository repository;
    @GetMapping("/formVagas")
    public String carregarFormulario(Long id, Model model) {
        if (id != null) {
            var vaga = repository.getReferenceById(id);
            model.addAttribute("vaga",vaga);
        }
        return "vagas/formVagas";
    }
    @PostMapping
    public String cadastrarVagas(@Valid DadosCadastroVagasDTO dados) {
        service.cadastrarVaga(dados);
        return "redirect:/vagas/formVagas";
    }
}
8 respostas

POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>br.com</groupId>
    <artifactId>JobLinkr</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>JobLinkr</name>
    <description>JobLinkr</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-mysql</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

A parte do HTML:

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">>
<head>
    <meta charset="UTF-8">
</head>
<body>
<div layout:fragment="conteudo"></div>
</body>
</html>
<!DOCTYPE html>
<html lang="en" layout:decorate="~{template.html}"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      xmlns:th="http://thymeleaf.org">
<head>
    <title>Cadastro de Vagas</title>
</head>
<body>
<div layout:fragment="conteudo" id="form">
    <form method="post" action="/vagas">
        <h2 class="titulo">Cadastrar Vagas</h2>
        <label for="nomeDaVaga">Nome da Vaga</label>
        <div class="input">
            <input id="nomeDaVaga" name="nomeDaVaga" placeholder="Nome" type="text"
                   th:value="${vaga?.nomeDaVaga}">
        </div>
        <label for="descricaoDaVaga">Descrição da vaga</label>
        <div class="input">
            <input id="descricaoDaVaga" name="descricaoDaVaga" placeholder="Descrição da vaga" type="text"
                   th:value="${vaga?.descricaoDaVaga}">
        </div>
        <label for="dataDeAberturaDaVaga">Data de abertura</label>
        <div class="input">
            <input id="dataDeAberturaDaVaga" name="dataDeAberturaDaVaga" placeholder="Data de abertura da vaga" type="date"
                   th:value="${vaga?.dataDaAberturaDaVaga}">
        </div>
        <label for="dataDeFechamentoDaVaga">Data de fechamento da vaga</label>
        <div class="input">
            <input id="dataDeFechamentoDaVaga" name="dataDeFechamentoDaVaga" placeholder="Data de fechamento da vaga" type="date"
                   th:value="${vaga?.dataDeFechamentoDaVaga}">
        </div>
        <label for="formacaoAcademicaNecessaria">Formação acadêmica</label>
        <div class="input">
            <select id="formacaoAcademicaNecessaria" name="formacaoAcademicaNecessaria" th:field="${vaga.formacaoAcademicaNecessaria}">
                <option value="FUNDAMENTAL" th:selected="${vaga?.formacaoAcademicaNecessaria == 'FUNDAMENTAL'}">Ensino Fundamental</option>
                <option value="MEDIO" th:selected="${vaga?.formacaoAcademicaNecessaria == 'MEDIO'}">Ensino Médio</option>
                <option value="TECNICO" th:selected="${vaga?.formacaoAcademicaNecessaria == 'TECNICO'}">Ensino Técnico</option>
                <option value="GRADUACAO" th:selected="${vaga?.formacaoAcademicaNecessaria == 'GRADUACAO'}">Graduação</option>
            </select>
        </div>
        <input type="submit" value="Cadastrar">
    </form>
</div>
</body>
</html>

O erro:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Como está as pastas:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Oi!

Veja na stacktrace da exception no console o trecho que indica a causa do erro e mande aqui.

Insira aqui a descrição dessa imagem para ajudar na acessibilidade Insira aqui a descrição dessa imagem para ajudar na acessibilidade Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Acho que o problema é na sua combobox de formação acadêmica, que você utilizou o atributo th:field.

A sugestão é você enviar a lista de formações pelo controller, adicionando no model, e fazer um loop nessa lista no html.

solução!

Consegui resolver dessa forma:

 <label for="formacaoAcademica">Formação acadêmica</label>
        <div class="input">
            <select id="formacaoAcademica" name="formacaoAcademica" required>
                <option value="FUNDAMENTAL" th:selected="${vaga?.formacaoAcademicaNecessaria == 'FUNDAMENTAL'}">Fundamental</option>
                <option value="MEDIO" th:selected="${vaga?.formacaoAcademicaNecessaria == 'MEDIO'}">Médio</option>
                <option value="TECNICO" th:selected="${vaga?.formacaoAcademicaNecessaria == 'TECNICO'}">Técnico</option>
                <option value="GRADUACAO" th:selected="${vaga?.formacaoAcademicaNecessaria == 'GRADUACAO'}">Graduação</option>
            </select>
        </div>