User change does not work, is doubling given in bank

Asked

Viewed 332 times

0

I implemented spring security in my project, I can already register new users and login/logout. Now I’m trying to edit this user’s data, when I click save, it duplicates the data in the database, and as my redirect is to page "My account" it finds two records of the same "username" and returns the error below:

javax.persistence.Nonuniqueresultexception: query Did not Return a Unique result: 2

Follows code:

Repositoryusuario:

public interface RepositoryUsuario extends JpaRepository<Usuario, Long>{

Usuario findByEmail(String email);
Usuario findByUsername(String username);

}

Servicousuario:

@Service
public class ServiceUsuario {

@Autowired
private RepositoryUsuario repUsuario;

@Autowired
private BCryptPasswordEncoder passwordEncoder;

public Usuario encontrarPorUsername(String Username) {
    return repUsuario.findByUsername(Username);
}

public void salvar(Usuario usuario) {
    usuario.setSenha(passwordEncoder.encode(usuario.getSenha()));
    repUsuario.save(usuario);
}

public Usuario getOne(Long id) {
    return repUsuario.getOne(id);
}

User:

@Entity
@Table(name = "usuario")
public class Usuario {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Column(name = "nome", nullable = false, length = 50)
@NotNull(message = "O nome é obrigatório!")
@Length(min = 3, max = 200, message = "O nome deve conter entre 3 a 50 caracteres!")
private String nome;

@Column(name = "sobrenome", nullable = false, length = 100)
@NotNull(message = "O sobrenome é obrigatório!")
@Length(min = 3, max = 100, message = "O sobrenome deve conter entre 3 a 100 caracteres!")
private String sobrenome;

@Column(name = "email", nullable = false, length = 200)
@NotNull(message = "O e-mail é obrigatório!")
@Length(min = 5, max = 200, message = "O e-mail deve conter entre 5 e 200 caracteres!")
private String email;

@Column(name = "senha", nullable = false, length = 20)
@NotNull(message = "A senha é obrigatória!")
private String senha;

@Column(name = "username", nullable = false, length = 20)
@NotNull(message = "O nome de usuário é obrigatório!")
@Length(max = 20, message = "O usuário deve conter entre 5 à 20 
caracteres!")
private String username;

@OneToMany(mappedBy = "usuario")
private List<Receita> receita;

@OneToMany(mappedBy = "usuario")
private List<Comentario> comentario;

//Getters e setters

User controller:

@Controller
@RequestMapping("/usuario")
public class UsuarioController {

@Autowired
private ServiceUsuario serviceUsuario;

@Autowired
private RepositoryUsuario repUsuario;

@GetMapping("/minhaConta")
public ModelAndView minhaConta(HttpServletRequest request) {
    ModelAndView mv = new ModelAndView("usuario/minhaConta");
    String username = request.getUserPrincipal().getName();
    Usuario usuario = serviceUsuario.encontrarPorUsername(username);
    mv.addObject("usuario", usuario);
    return mv;
}

@GetMapping("/alterar/{id}")
public String alterar(@PathVariable("id") Long id, Model model) {
    Usuario usuario = serviceUsuario.getOne(id);
    model.addAttribute("usuario", usuario);
    return "usuario/editarConta";
}

@PostMapping("/alterar")
public ModelAndView alterar(@Valid Usuario usuario, BindingResult result) {
    ModelAndView mv = new ModelAndView();
    if (result.hasErrors()) {
        System.out.println(result.getAllErrors());
        mv.setViewName("usuario/editarConta");
        mv.addObject(usuario);
    } else {
        mv.setViewName("redirect:/usuario/minhaConta");
        repUsuario.save(usuario);
    }

    return mv;
}

Editing form:

<h1 class="tituloRegist">Editar dados da conta:</h1>

            <div class="divRegist">

                <form class="form-horizontal formRegist" action="/usuario/alterar" method="POST" th:object="${usuario}">
                    <input type="hidden" th:field="*{id}">
                    <div class="form-group">
                        <label for="inputNome">Nome</label>
                        <input type="text" class="form-control" id="inputNome" placeholder="Nome" th:field="*{nome}">
                        <label th:if="${#fields.hasErrors('nome')}" th:errors="*{nome}" class="validation-message"></label>
                    </div>

                    <div class="form-group">
                        <label for="inputSobrenome">Sobrenome</label>
                        <input type="text" class="form-control" id="inputSobrenome" placeholder="Sobrenome"  th:field="*{sobrenome}">
                        <label th:if="${#fields.hasErrors('sobrenome')}" th:errors="*{sobrenome}" class="validation-message"></label>
                    </div>

                    <div class="form-group">
                        <label for="inputEmail">Email</label>
                        <input type="text" class="form-control" id="inputEmail" placeholder="Email"  th:field="*{email}">
                        <label th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="validation-message"></label>
                    </div>
                    <input type="hidden" th:field="*{senha}">
                    <input type="hidden" th:field="*{username}">
                    <button type="submit" class="btn btn-primary">Salvar</button>

                </form>
            </div>
  • Post the code of RepositoryUsuario

  • Posted @nullptr

  • Now its entity Usuario

  • Pronto @nullptr

  • one more question, you came to debug and check if the user has the id set when passing the line repUsuario.save(usuario); in your service?

2 answers

0

In case of a change, you need to recover this record in the database first. Create a change method that retrieves the user in the database and then save the change. For example:

@Service
public class ServiceUsuario {

@Autowired
private RepositoryUsuario repUsuario;

@Autowired
private BCryptPasswordEncoder passwordEncoder;

public Usuario encontrarPorUsername(String Username) {
    return repUsuario.findByUsername(Username);
}

public void atualiza(Usuario usuario) {
    // Supondo que vc já tenha buscado o usuário antes de alterar, vc terá o id. 
    // Caso contrário vc pode buscar pelo username acrescentando um método na sua
    // interface (findByUsername)
    Usuario registro= repUsuario.findById(usuario.getId());
    if (Objects.nonNull(registro)) {
        registro.setNome(usuario.getNome());
        registro.setSobrenome(usuario.getSobrenome());
        registro.setEmail(usuario.getEmail());
        registro.setUsername(usuario.getUsername());
        registro.setSenha(usuario.getSenha());
        registro.setReceita(usuario.getReceita());
        registro.setComentario(usuario.getComentario());
        repUsuario.save(registro);
    } else {
        repUsuario.save(usuario);
    }
}

public void salvar(Usuario usuario) {
    usuario.setSenha(passwordEncoder.encode(usuario.getSenha()));
    repUsuario.save(usuario);
}

public Usuario getOne(Long id) {
    return repUsuario.getOne(id);
}

That way when you want to update a record, just pass the User in the update method.

I wanted to leave a tip for you in case you want: from a look at the REST model, which contains fundamental principles and good practices in the construction of Web applications. Your project owes in some parts.

0

I believe the problem is occurring due to your object Usuario no longer in the Hibernate session, so the standard behavior of the JPARepository is applied:

Saving an Entity can be performed via the Crudrepository.save(...)-Method. It will persist or merge the Given Entity using the underlying JPA Entitymanager. If the Entity has not been persisted yet Spring Data JPA will save the Entity via a call to the entityManager.persist(...)-Method, otherwise the entityManager.merge(...)-Method will be called.

I suggest making the following amendment:

@Transactional
public void salvar(Usuario usuarioAlteracao) {
    Usuario usuario = getOne(usuarioAlteracao.getId());
    usuario.setSenha(passwordEncoder.encode(usuarioAlteracao.getSenha()));
    repUsuario.save(usuario);
}

This will put the user in the session, and will perform the merge of the entity.

Link to the Documentation

Browser other questions tagged

You are not signed in. Login or sign up in order to post.