如何在没有实体键值的情况下发送看跌请求



我正在尝试更新一个用户,并将密码添加到数据库中创建的新列中,因为该密码将被加密。然而,我收到了以下错误,它不是作为行上的更新发送的,而是作为数据库中的新行发送的。我检查了一下,大多数人都使用存储库中的.save(方法(进行更新,但它更新了对象而没有添加新行:

2022-10-26 12:50:37.648  INFO 13732 --- [nio-8080-exec-3] com.ssc.test.cb3.service.UserService     
: Fetching user htorres
Existent user: User(serie=5, username=htorres, name=Herney Torres, password=htorres, 
profile=1, email=, status=false, passwordc=null, roles=[Role(serie=1, name=ROLE_USER)])
2022-10-26 12:50:37.793  INFO 13732 --- [nio-8080-exec-3] com.ssc.test.cb3.service.UserService     
: Saving new user Herney Torres to the database
2022-10-26 12:50:38.064  WARN 13732 --- [nio-8080-exec-3] 
o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 23505
2022-10-26 12:50:38.064 ERROR 13732 --- [nio-8080-exec-3] 
o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: llave duplicada viola restricción de 
unicidad «usuario_login_key»
Detail: Ya existe la llave (login)=(htorres).

Detail中的最后一条消息说:已经有一个密钥(login(=(htorres(。

我如何在没有主键的情况下发送请求;登录";哪个是用户名?我试图不将其包含在poster中的请求中,但它返回错误ERROR 13732 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper:error:列<gt;违反了非null的限制`,我检查了使用列表是否可以使用.remove((不包括以下资源中的主键,但不确定在我的体系结构中如何使用:

带arrayLists 的SpringRest

这是我的课:

package com.ssc.test.cb3.controller;

import com.ssc.test.cb3.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
/**
* Class to handle REST services and APIs for the Customer's class
*
* @author ssc
*/
@RestController
@RequestMapping("/v1/users")
//@CrossOrigin(origins = "http://localhost:3000")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private PasswordEncoder passwordEncoder;

@PutMapping("/updateUser/{id}")
private ResponseEntity<?> updateUser(@PathVariable("id") String username, @RequestBody User user){
User existentUser = userService.getUser(username);
System.out.println("Existent user: " + existentUser);
existentUser.setPasswordc(passwordEncoder.encode(user.getPasswordc()));
return ResponseEntity.ok(userService.createUser(user));   
}
}

服务类别:

包com.ssc.test.cb3.service;

import com.ssc.test.cb3.model.Role;
import com.ssc.test.cb3.model.User;
import com.ssc.test.cb3.repository.RoleRepository;
import com.ssc.test.cb3.repository.UserRepository;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Class to prepare the services to be dispatched upon request regarding Customers. 
* @author ssc
*/
@Service 
@Transactional 
@Slf4j
@RequiredArgsConstructor
public class UserService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Autowired
private final RoleRepository roleRepository;
@Autowired
private final PasswordEncoder passwordEncoder;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);  // details from user loaded by getting the username
if(user == null){
log.error("User not found in the database");
throw new UsernameNotFoundException("User not found in the database");
} else {
log.info("User found in the database: {}", username);
}
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
user.getRoles().forEach(role -> { 
authorities.add(new SimpleGrantedAuthority(role.getName()));
});
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
}
/**
*  Method to get details from a user by the username
* @param username key that helps to identify the user we want to retrieve from the database
* @return the user details. 
* @throws UsernameNotFoundException 
*/
public User getUserDetailsByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);  // details from user loaded by getting the username
if(user == null){
log.error("User not found in the database by that username");
throw new UsernameNotFoundException("User not found in the database by that username");
} else {
log.info("User found in the database: {}", username);
}
return user;
}
/**
* 
* @param id
* @return 
*/
public User getUser(String username){
log.info("Fetching user {}", username);
return userRepository.findByUsername(username);
}

/**
* Functionality to create a new user
* @param user receives an objet User to be saved on the database
* @return the action of saving the user in the database. 
*/
public User createUser(User user){
log.info("Saving new user {} to the database", user.getName());
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setPasswordc(passwordEncoder.encode(user.getPasswordc()));
return userRepository.save(user);
} 
}

我的存储库类:

package com.ssc.test.cb3.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.ssc.test.cb3.model.User;
/**
* Class that extends to the repository for database management queries with table Usuario
* @author ssc
*/
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}

最后是我的用户实体类:

package com.ssc.test.cb3.model;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Class that models the entity User as table of the database
* @author cardo
*/
@Entity
@Table(name = "usuario")
@Data @NoArgsConstructor @AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int serie;
@Column(name = "login")  
private String username;   // Username...
@Column(name = "nombre")
private String name;
private String password;
@Column(name = "perfil")
private int profile;
private String email;
@Column(name = "activo")
private boolean status;
private String passwordc;
@ManyToMany(fetch = FetchType.EAGER)
private Collection<Role> roles = new ArrayList<>();
}

您所做的事情有些可疑。

首先,在控制器中,你正在进行

User existentUser = userService.getUser(username);
System.out.println("Existent user: " + existentUser);
existentUser.setPasswordc(passwordEncoder.encode(user.getPasswordc()));

但是您不保存existingUser,因此更改不会持续。

之后,使用有效载荷创建一个新用户

return ResponseEntity.ok(userService.createUser(user)); 
public User createUser(User user){
log.info("Saving new user {} to the database", user.getName());
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setPasswordc(passwordEncoder.encode(user.getPasswordc()));
return userRepository.save(user);
}   

但是有效载荷似乎包含现有用户的信息。我会做一些类似的事情

public User createOrUpdateUser(User userPayload){
log.info("Saving user {} to the database", user.getName());
User dbUser = getUser(user.getUsername());
if(isNull(dbUser)) {
dbUser = ..logic for creating a new user
} else {
// logic to update the db user properties using the userPayload
dbUser.set
}
return userRepository.save(user);
} 

此外,我会重新考虑您在这里所做的事情,因为这些可以在POST中分割用于创建用户,在PUT中分割用于更新用户。

主要问题是没有将现有的User对象传递给存储库保存方法。数据库中的主键是自动生成的ID,而不是用户名。当您第一次将用户检索到existentUser变量中时,这是具有主键集的附加实体。在数据库事务范围内对此实体进行的任何更新都将自动保留回数据库。问题是,您从初始请求中传递了没有ID的未附加用户对象,因此系统认为您正在尝试创建新用户,但由于现在存在重复登录,因此失败了。我认为要实现这一点,您只需要删除userService.createUser(user)调用并用@Transactional注释updateUser控制器方法。您也应该公开该方法。

话虽如此,ALex提出的制作追加服务方法的建议是一个好主意,然后您可以将@Transactional注释移动到该方法,并将事务边界保留在您的服务中和控制器之外。

最新更新