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

Como alterar dados no SPring Boot

Olá pessoal, já quebrei a cabeça varias vezes e não consigo implementar uma edição de dados no sistema, com base nas aulas fiz um projeto minimo para aprendizado, mas não consigo entender como altear. Segue projeto:

Classe controle no pacote "br.com.contato":

@Controller
public class PessoaController {

    @Autowired
    private PessoaService service;

    @RequestMapping("/")
    private String index() {
        return "index";
    }

    @RequestMapping("listarpessoas")
    private String listarPessoas(Model model) {

        Iterable<Pessoa> pessoas = service.obterTodos();

        model.addAttribute("pessoas", pessoas);

        return "listarpessoas";
    }

    @RequestMapping("incluirpessoa")
    public String incluirPessoa() {
        return "incluirpessoa";
    }

    @RequestMapping(value="salvar", method = RequestMethod.POST)
    public String salvar(@RequestParam("nome") String nome, Model model) {

        Pessoa novaPessoa = new Pessoa(nome);

        //Como foi usado a anotação "autowired" não é necessário instanciar o serviço.
        service.salvar(novaPessoa);

        Iterable<Pessoa> pessoas = service.obterTodos();

        model.addAttribute("pessoas", pessoas);

        return"listarpessoas";
    }

    @RequestMapping("editarpessoa/{id}")
    public String editarpessoa(@PathVariable("id") Long id, Pessoa pessoa, Model model) {
        System.out.println(id);
        model.addAttribute("pessoa", pessoa);
        service.obterId(id);
        service.salvar(pessoa);

        return "listarpessoas";
    }

}

Classe repositório no pacote - "br.com.contato.repository":

@org.springframework.stereotype.Repository
public interface PessoaRepository extends CrudRepository<Pessoa, Long>{

    List<Pessoa> findByNome(String nome);

    Optional<Pessoa> findById(Long id);

}

Classe service no pacote - "br.com.contato.service":

@Service
public class PessoaService {

    @Autowired
    private PessoaRepository repository;

    public Iterable<Pessoa> obterTodos(){

        Iterable<Pessoa> pessoas = repository.findAll();

        return pessoas;
    }

    public Optional<Pessoa> obterId(Long id) {
        return repository.findById(id);
    }

    public void salvar(Pessoa pessoa) {
        repository.save(pessoa);
    }
}

Classe de entidade no pacote - "br.com.contato.model":

@Entity
public class Pessoa {

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

    public Pessoa(String nome) {
        this.nome = nome;
    }

    @Id
    @GeneratedValue
    private Long id;
    private String nome;

    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;
    }
}

Templates na pasta - "resources/templates": listarpessoas.html:

<title>Contatos xXx</title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
</head>
<body>
    <div class="container">
        <div id=listarpessoas>
            <div>
                <div class="jumbotron" align="center" style="margin-top: 50px;">
                    <h1>xXx Contatos (lista) xXx</h1>
                    <table class="table table-hover">
                        <thead>
                            <tr>
                                <th>Identificação</th>
                                <th>Nome</th>
                                <th>Ações</th>
                            </tr>
                        </thead>
                        <tr th:each="pessoa:${pessoas}">
                            <td><span th:text="${pessoa.id}"></span></td>
                            <td><span th:text="${pessoa.nome}"></span></td>
                            <td><a href="editarpessoa">Editar</a></td>
                        </tr>
                    </table>
                </div>
            </div>
        </div>
        <div align="center">
            <a href="incluirpessoa" class="btn btn-primary">Incluir Contato</a>
            <a href="/" id="cancel" class="btn btn-default">Cancel</a>
        </div>
    </div>
    <script
        src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="bootstrap/js/bootstrap.min.js"></script>
</body>
</html>

Templates na pasta - "resources/templates":
editarpessoas.html:
<body>
            <div class="container">
        <div id="incluirpessoa">
            <h1>Alterar Pessoa</h1>
            <div align="left">
                <form action="salvar" method="post">
                    <div class="form-group">
                        <label for="id" >identificação</label>
                         <input type="text"
                            class="form-control" id="id" name="id" placeholder="id" value="${pessoa.id}" />
                    </div>
                    <div class="form-group">
                        <label for="nome" >Nome completo</label> 
                        <input type="text"
                            class="form-control" id="nome" name="nome" placeholder="Nome" value="${pessoa.nome}"/>
                    </div>
                    <div align="right">
                        <button type="submit" class="btn btn-success">Alterar</button>
                        <a href="listarpessoas" id="cancel" class="btn btn-default">Cancel</a>
                    </div>
                </form>
            </div>
        </div>
    </div>

Preciso de um direcionamento no que fazer. :(

5 respostas

Oi higinodf, tudo bem?

A alteração, é bem parecida com o cadastro, com alguns detalhes diferentes. Normalmente envolve dois passos:

  1. Exibir um formulário com os dados atuais
  2. Receber os novos dados no servidor e fazer o update

Podemos criar uma URL para editar a partir do Id, por exemplo. Onde o usuário acessaria algo como /editarpessoa/1. Que foi o que você já fez. :)

Com o id, podemos busar o registro no banco, e mandar pra página utilizando o Model. No Controller, temos o seguinte:

   @RequestMapping("editarpessoa/{id}")
    public String editarpessoa(@PathVariable("id") Long id, Model model) {
        System.out.println(id);
        Pessoa pessoa = service.obterId(id);
        model.addAttribute("pessoa", pessoa);

        return "listarpessoas";
    }

Então pegamos o retorno do Service, que usou o Repositório pra pegar o registro no banco, e em seguida adicionamos este objeto no Model.

A página listarpessoas precisa agora exibir esses dados que vieram da ação editarpessoa. Podemos fazer isso utilizando o th:value. Uma forma bem simples seria algo como:

<form>
    <input type="text" th:name="nome" th:value="${pessoa.nome}">
</form>

Ele exibe o formulário preenchido com os valores atuais. Você pode ou não alterar, depois precisamos enviar os valores novamente para o servidor.

Como se trata de uma alteração, precisamos também enviar o id do objeto, podemos fazer isso por meio de um campo hidden:

<form>
    <input type="hidden" th:name="id" th:value="${pessoa.id}" >
    <input type="text" th:name="nome" th:value="${pessoa.nome}">
</form>

Por fim precisamos definir para onde os dados serão enviados, isso irá envolver mais uma ação no controller:

<form action="atualizar">
    <input type="hidden" th:name="id" th:value="${pessoa.id}" >
    <input type="text" th:name="nome" th:value="${pessoa.nome}">
<input type="submit">
</form>

E no Controller, um novo método para receber esse objeto:

@RequestMapping("/atualizar")
public String atualiza(Pessoa pessoa) {
    service.salvaI(pessoa);
    return "redirect:listarpessoas";
}

Se ficar alguma dúvida é só avisar. :)

Abraço!

Otima explicação Lucas-Felix, o mais importante que entendi o porque de não ter conseguido. Não indiquei o id no template e assim ele não pegava esse id para levar ao meu controle, estou certo? Então agora "paquei" nessa parte:

    @RequestMapping("editarpessoa/{id}")
    public String editarpessoa(@PathVariable("id") Long id, Model model) {
        Optional<Pessoa> pessoa = service.obterId(id);
        model.addAttribute("pessoa", pessoa);
        return "editarpessoa";
    }

Eu sei que o problema esta no retorno, mas quando coloco como [return "editarpessoa"] o sistema não encontra esse template. Imaginei que esse mapeamento traria o ID para o controle que atribui a um model e retorna para a view editarpessoa, mas ele gera o erro:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Tue Jul 17 22:11:48 BRT 2018
There was an unexpected error (type=Internal Server Error, status=500).
An error happened during template parsing (template: "class path resource [templates/editarpessoa.html]")

Se não é pra retornar para editar pessoa é porque tenho que mudar o tipo de retorno do meu método? Tentei mudar para retornar uma pessoa, sem pensar que é impossível, já que preciso retornar para uma view e não para um objeto. Crio um novo @Request? mas mando o que para esse request?

solução!

Oi higinodf!

O retorno do método pode ser String mesmo, que representa o nome da página para onde você vai.

O método obterId retorna um Optional. Pode ser que por isso está dando erro ao renderizar o template. Tenta usar o get() do Optional para pegar o objeto e adicionar no Model? Algo como:

Pessoa pessoa = service.obterId(id).get(); // usando o get()
model.addAttribute("pessoa", pessoa);

Avisa no que deu?

Abraço!

Olá Lucas, desculpe a demora, ainda tive mais alguns problemas, estava usando o método GET e não estava usando barra, que alias vou rever esse conceito, que achei confuso. Rs. Mas muito obrigado pela ajuda, já estou alterando certinho, agora é passar para delete... Obrigado mesmo! :)

Opa Luis, que bom que funcionou! Se surgirem mais dúvidas na parte de Deletar, é só abrir um novo tópico.

Bons estudos!