Java 在Spring Security中添加新用户时获取异常
我有一个用户类、角色类和用户角色类。现在,每次我尝试添加一个新用户,其中包含一组已经存在的角色,它都会抛出一个唯一的错误,这是正确的。但理想情况下,如果新角色已经存在,它不应该试图保存它。下面我添加了我所有的表和保存方法Java 在Spring Security中添加新用户时获取异常,java,spring-boot,spring-security,spring-data-jpa,spring-data,Java,Spring Boot,Spring Security,Spring Data Jpa,Spring Data,我有一个用户类、角色类和用户角色类。现在,每次我尝试添加一个新用户,其中包含一组已经存在的角色,它都会抛出一个唯一的错误,这是正确的。但理想情况下,如果新角色已经存在,它不应该试图保存它。下面我添加了我所有的表和保存方法 @Table(name = "t_user") @Data public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(na
@Table(name = "t_user")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "mobile_number")
private String mobileNumber;
@Column(name = "email")
private String email;
@Column(name = "first_name")
private String firstName;
@Size(max = 100)
@NotBlank(message = "Last name can not be empty")
@Column(name = "last_name")
private String lastName;
@Column(name = "is_archived")
private Boolean isArchived = false;
@Column(name = "qualification")
private String qualification;
@JsonIgnore
@Column(name="password")
private String password;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "t_user_role", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {
@JoinColumn(name = "role_id", referencedColumnName = "id")})
private Set<Role> roles = new HashSet<>();
}
保存用户的方法:
User newUser = new User();
newUser.setFirstName(user.getFirstName());
newUser.setLastName(user.getLastName());
newUser.setEmail(user.getEmail());
newUser.setMobileNumber(user.getPassword());
newUser.setPassword(bcryptEncoder.encode(user.getPassword()));
newUser.setRoles(user.getRoles());
return userRepository.save(newUser);
}
{
"firstName":"first",
"lastName":"name",
"email":"email@gmail.com",
"mobileNumber":"1110122223",
"password":"1234567890",
"roles":[{
"name":"ADMIN"
}]
}
下面是创建用户的post请求格式:
User newUser = new User();
newUser.setFirstName(user.getFirstName());
newUser.setLastName(user.getLastName());
newUser.setEmail(user.getEmail());
newUser.setMobileNumber(user.getPassword());
newUser.setPassword(bcryptEncoder.encode(user.getPassword()));
newUser.setRoles(user.getRoles());
return userRepository.save(newUser);
}
{
"firstName":"first",
"lastName":"name",
"email":"email@gmail.com",
"mobileNumber":"1110122223",
"password":"1234567890",
"roles":[{
"name":"ADMIN"
}]
}
我不想插入的角色,如果存在,这应该是理想的。但这是我在使用角色实现spring安全性时发现的标准方法,您的请求缺少角色的
id
。Asid
不存在。Spring尝试在role
表中添加新角色
{
"firstName":"first",
"lastName":"name",
"email":"email@gmail.com",
"mobileNumber":"1110122223",
"password":"1234567890",
"roles":[{
"id" : "" // ID must be present here.
"name":"ADMIN"
}]
}
或者从角色->名称
,您可以从角色表中获取角色
实体/obj,并在用户
对象中进行设置
[更新2]:
@ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
@ToString.Exclude
private Set<Role> roles = new HashSet<>();
@ManyToMany(cascade=CascadeType.DETACH,fetch=FetchType.LAZY)
@ToString.Exclude
私有集角色=新HashSet();
您需要将级联类型从“全部”更改为“分离”。请参阅:
ALL
表示如果保存用户,角色也将被保存,如果删除用户,角色也将被删除。这不是我们想要的。您只需要使用“角色”,而不需要以任何方式操纵“角色”表记录。就我所知,您的要求是:
public class User {
... all fields
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@ToString.Exclude
private Set<Role> roles = new HashSet<>();
}
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
}
公共类用户{
…所有领域
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@ToString.Exclude
私有集角色=新HashSet();
}
公共阶级角色{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私有整数id;
私有字符串名称;
}
在角色存储库中,您需要一个方法:可选的findByName(字符串名称)代码>
在层之间(最好在服务层中),尝试以下操作:
public Map<String, Object> addUser(User user) {
// perform validations
user.getRoles().forEach(role -> {
Role existing = roleRepository.findByName(role.getName())
.orElse(new Role(role.getName())); // using optional to create new role with name passed in from the client
if (existing.getId() != null) user.setRole(existing); // UPDATE: NOT IDEAL
});
... other tasks
userRepository.save(user); // this all saves the correct role
return yourResponseMap;
}
publicmap addUser(用户){
//执行验证
user.getRoles().forEach(角色->{
Role existing=roleRepository.findByName(Role.getName())
.orElse(新角色(Role.getName());//使用optional以从客户端传入的名称创建新角色
if(existing.getId()!=null)user.setRole(existing);//更新:不理想
});
…其他任务
userRepository.save(user);//这将保存正确的角色
返回您的响应映射;
}
其他说明:
我们通常更喜欢让回访者保持懒惰,而不是渴望。但有些情况下,你可能需要急切的检索,所以这取决于你
在我看来,让Spring数据JPA处理第三个表更方便
org.hibernate.PersistentObjectException:当您试图保存从客户端直接传入的角色而不将其加载到应用程序时(请参阅“添加用户”的服务层方法),会发生传递到persistent的分离实体
检查此项,您可能会发现它很有用
你能添加例外吗?如果没有itLombok@Data合并@EqualsAndHashCode(集合所需),我们就不可能有想法。你不想那样。在类中,typ alt insert并实现Equals()和HashCode()。可能还有另一个问题,但这引起了我的注意。出现的异常是数据完整性冲突异常,因为角色管理员已存在使用save
方法调用将在数据库中插入记录,并且由于唯一约束,它将抛出错误。如果要防止重复值,则可以在调用save方法之前进行检查并显示自定义消息,但我正在对t_user_角色表而不是角色表org.hibernate.PersistentObjectException:传递给persist的分离实体:com.user.model.role。我在请求体中持久化对象时遇到此异常,我添加了存在的id,并尝试进行rest调用Yes写入,当您尝试保存用户时,spring会自动尝试保存角色(如果角色id不存在->尝试添加新记录),(如果存在id->尝试更新记录)。我们需要将用户中的角色字段标记为“分离”。为此->您需要更改角色集@ManytoMany注释中的级联类型。[cascade=CascadeType.DETACH]请添加注释以对答案进行向下投票。您的addUser
函数中存在两个问题,首先,它不支持用户中的多个角色,这是一个次要问题。其次,我们不应该在添加用户时添加新角色。角色通常只是预定义的。这似乎属于一类重大问题。我很抱歉,但你的回答对解决问题毫无帮助。您刚刚添加了额外的“惰性”加载。这在这种情况下仍然没有帮助。用户必须具有角色。”“LAZY”是我们在场景中使用的,在场景中,我们有额外的属性,这些属性可能有较大的集合,或者有变大的趋势。@AmanGarg的问题是:“但理想情况下,如果新角色已经存在,它不应该试图保存它。下面我将添加我的所有表和保存方法。”表示当角色不存在时,他会保存它。我同意他不应该保留这个新角色。关于处理多行,我发布了一个更新,但肯定有人谁在这个阶段编码可以确定他想如何修改代码。这不是一个能够满足所有情况的即插即用解决方案。然后需要添加验证。Cascade.ALL在此无效。感谢您的反馈。如前所述,