我正在使用Spring框架编写应用程序。我想为我的实体对象创建dto模型,并在spring控制器中使用它。这并不困难,但是我在数据库中的表与我必须在我的实体对象中进行设置之间存在关系。
用户实体
@Entity
@Table(name = "users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "id")
private Integer id;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
@Column(name = "username")
private String username;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
@Column(name = "password")
private String password;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
@Column(name = "firstName")
private String firstName;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
@Column(name = "lastName")
private String lastName;
@Size(min = 11, max = 11)
@Column(name = "personalId")
private String personalId;
@Size(max = 40)
@Column(name = "city")
private String city;
@Size(max = 40)
@Column(name = "address")
private String address;
@NotBlank
@NotNull
@Email
@Size(max = 40)
@Column(name = "email")
private String email;
@Size(min = 9, max = 9)
@Column(name = "phone")
private String phone;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<UserRole> userRoleSet;
user_roles实体
@Entity
@Table(name = "user_roles")
public class UserRole implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "id")
private Integer id;
@NotNull
@Size(max = 40)
@Column(name = "name")
private String name;
@JoinColumn(name = "userId")
@ManyToOne(targetEntity = User.class)
private User user;
表用户与user_role表是一对多的关系。
我为此实体创建一个DTO对象:
userDto
public class UserDto {
private Integer id;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
private String username;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
private String password;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
private String firstName;
@NotBlank
@NotNull
@Size(min = 3, max = 40)
private String lastName;
@Size(min = 11, max = 11)
private String personalId;
@Size(min = 3, max = 40)
private String city;
@Size(min = 3, max = 40)
private String address;
@NotBlank
@NotNull
@Email
@Size(max = 40)
private String email;
@Size(min = 9, max = 9)
private String phone;
private Set<UserRoleDto> userRoleSetDto;
userRoleDto
public class UserRoleDto {
private Integer id;
@NotNull
@Size(min = 3, max = 40)
private String name;
private UserDto userDto;
我的控制器,重定向到包含用户列表的页面
@SuppressWarnings("unchecked")
@RequestMapping(value = "/admin/adminlist", method = RequestMethod.GET)
public ModelAndView goAdminList() {
ModelAndView mav = new ModelAndView("admin/adminlist");
List<UserDto> admins = prepareUserListDto(userService.getAdminList());
mav.addObject("admins", admins);
return mav;
}
在此控制器中,我使用方法prepareUserListDto将用户列表准备为userdto列表:
private List<UserDto> prepareUserListDto(List<User> users) {
List<UserDto> userDtoList = null;
if (users != null && !users.isEmpty()) {
userDtoList = new ArrayList<UserDto>();
UserDto userDto = null;
for (User user : users) {
userDto = new UserDto();
userDto.setId(user.getId());
userDto.setUsername(user.getUsername());
userDto.setPassword(user.getPassword());
userDto.setFirstName(user.getFirstName());
userDto.setLastName(user.getLastName());
userDto.setEmail(user.getEmail());
userDto.setUserRoleSetDto(prepareUserRoleDtoSet(user
.getUserRoleSet()));
userDtoList.add(userDto);
}
}
return userDtoList;
}
此方法调用方法以将userRole准备为userRoleDto
private Set<UserRoleDto> prepareUserRoleDtoSet(Set<UserRole> userRoles) {
Set<UserRoleDto> userRoleDtoSet = null;
if (userRoles != null && !userRoles.isEmpty()) {
userRoleDtoSet = new HashSet<UserRoleDto>();
UserRoleDto userRoleDto = null;
for (UserRole userRole : userRoles) {
userRoleDto = new UserRoleDto();
userRoleDto.setId(userRole.getId());
userRoleDto.setName(userRole.getName());
userRoleDto.setUserDto(prepareUserDto(userRole.getUser()));
userRoleDtoSet.add(userRoleDto);
}
}
return userRoleDtoSet;
}
但是此方法再次调用方法:
private UserDto prepareUserDto(User user) {
UserDto userDto = new UserDto();
userDto.setId(user.getId());
userDto.setUsername(user.getUsername());
userDto.setPassword(user.getPassword());
userDto.setFirstName(user.getFirstName());
userDto.setLastName(user.getLastName());
userDto.setEmail(user.getEmail());
userDto.setUserRoleSetDto(prepareUserRoleDtoSet(user.getUserRoleSet()));
return userDto;
}
总之,当我尝试显示管理员列表时,我有递归调用,并且出现此错误:
java.lang.StackOverflowError
org.hibernate.collection.internal.PersistentSet.isEmpty(PersistentSet.java:166)
pl.piotr.ibank.controller.AdminController.prepareUserRoleDtoSet(AdminController.java:170)
pl.piotr.ibank.controller.AdminController.prepareUserDto(AdminController.java:139)
pl.piotr.ibank.controller.AdminController.prepareUserRoleDtoSet(AdminController.java:177)
pl.piotr.ibank.controller.AdminController.prepareUserDto(AdminController.java:139)
pl.piotr.ibank.controller.AdminController.prepareUserRoleDtoSet(AdminController.java:177)
pl.piotr.ibank.controller.AdminController.prepareUserDto(AdminController.java:139)
pl.piotr.ibank.controller.AdminController.prepareUserRoleDtoSet(AdminController.java:177)
pl.piotr.ibank.controller.AdminController.prepareUserDto(AdminController.java:139)
pl.piotr.ibank.controller.AdminController.prepareUserRoleDtoSet(AdminController.java:177)
pl.piotr.ibank.controller.AdminController.prepareUserDto(AdminController.java:139)
在
userDto.setUserRoleSetDto(prepareUserRoleDtoSet(user.getUserRoleSet()));
方法中,第139行是private UserDto prepareUserDto(User user)
;在private UserDto prepareUserDto(User user)
方法中,第177行是private Set<UserRoleDto> prepareUserRoleDtoSet(Set<UserRole> userRoles)
。如何为此实体编写dto?如果没有约束,这很容易,但是我的实体在user和user_role之间有约束,我不知道如何找到好的解决方案。
最佳答案
一个非常简单的解决方案是从UserRoleDto类中完全删除userDto
属性。与可能需要从一个实体到另一个实体并包含双向关系的实体类相反,客户端通常只需要获取用户的角色,而无需从角色中获取用户。因此,您不需要这两个dto之间的双向关系