Ainda não tem acesso? Estude com a gente! Matricule-se
Ainda não tem acesso? Estude com a gente! Matricule-se

Spring Boot com select usando enums

Oi pessoal, estou fazendo usando CRUD com select + enum, cheguei a um ponto que não estou entendo, estou muita duvida na view, usando o thymeleaf, identifiquei que o erro é por conta de não carregar a variavel status. Segue código:

package br.com.academia.util;

public enum EstadoAlunoEnum {
    ATIVO("ativo"), 
    INATIVO("inativo");  
    private final String status;
    EstadoAlunoEnum(String status){
        this.status = status;
    }
    public String getStatus() {
        return status;
    }
}

@Controller
public class AlunoController {
    @Autowired
    private AlunoServico servico;
    @RequestMapping("/")
    public String paginaIncial() {
        return "index";
    }
    @RequestMapping("listar_alunos")
    public String listarAlunos(Model model) {
        Iterable<Aluno> alunos = servico.obterTodosAlunos(); 
        model.addAttribute("alunos", alunos);
        return "listar_alunos";
    }

    @RequestMapping("incluir_aluno")
    public String incluirAluno() {
        return "incluir_aluno";        
    }

    @RequestMapping("/salvar")
    public String salvar(@RequestParam("nome") String nome, 
 @RequestParam("telefone") int telefone,
                         @RequestParam("status") EstadoAlunoEnum status,
 @RequestParam("observacoes") String observacoes, 
             Model model ) {
     model.addAttribute("status", status.getStatus());
        Aluno aluno = new Aluno(nome, telefone, status, observacoes);
        servico.salvar(aluno);
        Iterable<Aluno> alunos = servico.obterTodosAlunos();
        model.addAttribute("alunos", alunos);
        return "redirect:listar_alunos";
    }
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Academia xXx</title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <ul class="nav nav-tabs">
        <li class="nav-item"><a class="nav-link active" href="/">Pagina inicial</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Sobre nós</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Deixe seu comentário</a></li>
    </ul>
    <div align="center">
        <h1>Incluir Aluno</h1>
    </div>
    <div class="container">
        <div>
            <div class="jumbotron" align="center" style="margin-top: 50px;">
                <form action="/salvar" method="post" >
                    <div class="form-group" align="left">
                        <label th:for=nome >Nome completo do aluno</label> 
                        <input type="text" class="form-control" id=nome_aluno name="nome" placeholder="Nome ou apelido" />
                    </div>
                    <div class="form-group" align="left">    
                         <label th:for=telefone>Telefone</label> 
                         <input type="number" class="form-control" id=telefone_aluno name="telefone" placeholder="999999999" />
                    </div>
                     <div class="form-group" align="left">
                        <label th:for="status">Status</label>
                          <select id="status" th:field="*{status}">
                            <option th:each="status : ${status}"
                                    th:text="${aluno.status.getStatus}"
                                    th:value="${status}">
                            </option>                        
                        </select>
                      </div> 
                    <div class="form-group" align="left">
                        <label for="observacoes">Observações</label>
                        <textarea class="form-control" id="observacoes" rows="3" name="observacoes" placeholder="Escreva aqui">
8 respostas

Segue o erro:

org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/incluir_aluno.html]")

Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringSelectFieldTagProcessor' (template: "incluir_aluno" - line 31, col 32)

Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringSelectFieldTagProcessor' (template: "incluir_aluno" - line 31, col 32)

Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'status' available as request attribute

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'status' available as request attribute

Luis, reparei o seguinte: ao carregar os dados, você chama o status do aluno do seguinte modo:

${aluno.status.getStatus}

Repare que na primeira chamada (aluno.status) você deixa a view resolver o nome do método por reflexão (.status -> .getStatus()). Já na segunda chamada (status.getStatus) você ficou no meio termo. Não chamou o método nem deixou a view resolver por reflexão (.getStatus -> .getGetStatus()).

Tente usar uma das duas alternativas a seguir e deve dar certo:

${aluno.status.status}
${aluno.status.getStatus()}

Outra coisa que pode fazer é delegar: No modelo de aluno, você pode criar um método String getStatusName() { return status.getStatus(); }, e assim chamar na view direto esse método:

${aluno.statusName}
${aluno.getStatusName()}

Acredito que isso deva resolver seu problema! Caso não resolva, a gente ve com mais detalhes onde pode estar o erro.

Então Marcos, primeiramente obrigado pela resposta, tentei dos 2 metodos e não consegui. Eu não estou entendendo e ainda pesquisando pra entender essas funções (se é assim que posso chamar) : th:each, th:text e th:value.

Coloquei assim:

@Entity
public class Aluno {

    public Aluno(String nome, int telefone, EstadoAlunoEnum status, String observacoes) {
        this.nome = nome;
        this.telefone = telefone;
        this.status = status;
        this.observacoes = observacoes;
    }

    public Aluno() {
        // TODO Auto-generated constructor stub
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String nome;
    private int telefone;
    @Enumerated(EnumType.STRING)
    private EstadoAlunoEnum status;
    private String observacoes;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getNome() {
        return nome;
    }
    public void setNome(String nome) {
        this.nome = nome;
    }
    public int getTelefone() {
        return telefone;
    }
    public void setTelefone(int telefone) {
        this.telefone = telefone;
    }
    public EstadoAlunoEnum getStatus() {
        return status;
    }
    public void setStatus(EstadoAlunoEnum status) {
        this.status = status;
    }
    public String getObservacoes() {
        return observacoes;
    }
    public void setObservacoes(String obervacoes) {
        this.observacoes = obervacoes;
    }

    public String getStatusName() {
        return status.getStatus();
    }
}

<form action="/salvar" method="post" >
                    <div class="form-group" align="left">
                        <label th:for=nome >Nome completo do aluno</label> 
                        <input type="text" class="form-control" id=nome_aluno name="nome" placeholder="Nome ou apelido" />
                    </div>
                    <div class="form-group" align="left">    
                         <label th:for=telefone>Telefone</label> 
                         <input type="number" class="form-control" id=telefone_aluno name="telefone" placeholder="999999999" />
                    </div>
                     <div class="form-group" align="left">
                        <label th:for="aluno.status">Status</label>
                          <select id="status" th:field="aluno.statusName">
                            <option th:each="aluno : ${aluno.statusName}"
                                    th:text="${aluno.statusName}"
                                    th:value="${aluno.status.getStatusName}">
                            </option>                        
                        </select>
                    </div>
                    <div class="form-group" align="left">
                        <label for="observacoes">Observações</label>
                        <textarea class="form-control" id="observacoes" rows="3" name="observacoes" placeholder="Escreva aqui">
<div class="form-group" align="left">
                        <label th:for="aluno.status">Status</label>
                          <select id="status" th:field="aluno.statusName">
                            <option th:each="aluno : ${aluno.statusName}"
                                    th:text="${aluno.statusName}"
                                    th:value="${aluno.status.getStatusName}">
                            </option>                        
                        </select>
                    </div>

Não estou conseguindo postar o código.

Luis, primeiro, ao postar código, faça o seguinte:

  1. Clique no botão <> inserir código acima do campo do post.
  2. Vai aparecer um pedaço de texto mais ou menos assim:
    ` ``
    insira seu código aqui
    ` ``
  3. Selecione o texto insira seu código aqui e cole seu código por cima desse trecho. Mantenha o seu código ENTRE os dois conjuntos de crases!
  4. Submeta seu post.

Segundo, Luis, olha só o pedaço de código que você compartilhou:

<option th:each="aluno : ${aluno.statusName}"
        th:text="${aluno.statusName}"
        th:value="${aluno.status.getStatusName}">
</option>

Repare que você novamente ficou no meio do caminho entre chamar o método e deixar que a view resolva o caminho:

th:value="${aluno.status.getStatusName}"

Isso deve estar causando novamente o mesmo erro!

Parando pra olhar um pouco mais de perto o código, percebi que você quer fazer um SELECT com todos os status possíveis. Acho que começar do começo pode ajudar, vamos lá!

Olhando seu select original:

<label th:for="status">Status</label>
<select id="status" th:field="*{status}">
    <option th:each="status : ${status}"
        th:text="${aluno.status.getStatus}"
        th:value="${status}">
    </option>
</select>

Está quase tudo certo: para corrigir, basta fazer duas correções.

  1. Corrigir a chamada do nome do status:
     <option th:each="status : ${status}"
         th:text="${status.getStatus()}"
         th:value="${status}">
     </option>
  2. Se for usar um código semelhante no formulário de edição, marcar como selecionado o status do aluno:
     <option th:each="status : ${status}"
         th:text="${status.getStatus()}"
         th:value="${status}"
         ${status == aluno.status ? 'selected' : ''}>
     </option>

Não sei se o código final acima está correto, mas acredito que funcione. Fiz algumas buscas no google e cheguei à conclusão de que deve estar, mas qualquer coisa eu faço uma busca melhor ou pergunto pra algum especialista.