我有两个数据Model User和Car:
User.java:
@Entity
@Table(name="APP_USER")
public class User implements Serializable{
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
......
@OneToMany(mappedBy="user",cascade=CascadeType.ALL)
private Set<Car> cars = new HashSet<Car>();
Car.java:
@Entity
public class Car implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id ;
.....
@ManyToOne(optional=false)
@JoinColumn(name="user_fk")
private User user;
在Controller中,我想添加一个新用户,所以
AppController.java:
@Controller
@RequestMapping("/")
@SessionAttributes("roles")
public class AppController {
@RequestMapping(value = { "/newuser" }, method = RequestMethod.GET)
public String newUser(ModelMap model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("edit", false);
model.addAttribute("loggedinuser", getPrincipal());
return "registration";
}
@RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)
public String saveUser(@ModelAttribute @Valid User user, BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "registration";
}
if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){
FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));
result.addError(ssoError);
return "registration";
}
userService.saveUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
model.addAttribute("loggedinuser", getPrincipal());
return "registrationsuccess";
}
另外,我创建了一个名为StringToUser的类(Implements Converter,所以我可以添加一个包含用户的新Car)
StringtoUser.java:
@Autowired
UserService userService ;
@Override
public User convert(Object element) {
Integer id = Integer.parseInt((String)element);
User user = userService.findById(id);
return user;
}
AppController.java和saveUser方法在我添加StringToUser类之前工作正常。但是在我创建了StringToUser类之后,我在saveUser方法中出错了
The error is : WARNING: Failed to bind request element: org.springframework.beans.TypeMismatchException: Failed to convert value of type [com.websystique.springmvc.model.User] to required type [com.websystique.springmvc.model.User]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [com.websystique.springmvc.model.User] to type [@org.springframework.web.bind.annotation.ModelAttribute @javax.validation.Valid com.websystique.springmvc.model.User] for value 'User [id=null, ssoId=alaa, password=alaa1991, firstName=, lastName=, email=, userProfiles=null, accounts=null, userDocuments=[], cars=[], documents=[]]'; nested exception is java.lang.ClassCastException: com.websystique.springmvc.model.User cannot be cast to java.lang.String
编辑:
错误:
WARNING: Failed to bind request element: org.springframework.beans.TypeMismatchException: Failed to convert value of type [com.websystique.springmvc.model.User] to required type [com.websystique.springmvc.model.User]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [com.websystique.springmvc.model.User] to type [@org.springframework.web.bind.annotation.ModelAttribute @javax.validation.Valid com.websystique.springmvc.model.User] for value 'User [id=null, ssoId=alaa, password=alaa1991, firstName=, lastName=, email=, userProfiles=null, accounts=null, userDocuments=[], cars=[], documents=[]]'; nested exception is java.lang.NullPointerException
答案 0 :(得分:0)
您不需要使用转换器,spring本身会将您的表单格式化为 User 类。
如果调试转换器类,您会注意到没有收到String作为参数,您会收到对类 User 的实例的引用。因此,您将用户转换为无意义的用户。
@Override
public User convert(Object element) {
if (element == null ) {
return null;
}
Integer id = ((User)element).getId();
User user = userService.findById(id);
return user;
}
现在,由于您尝试创建新用户,因此您的表单未设置和ID,因此您提供 userService null。您的服务失败,转换器无法显示该错误。
简单的解决方案就是删除它。
我理解你添加了角色转换器,因为表单正在向你发送一个整数列表,这些整数无法通过spring解析为Set。我强烈建议您将Command Objects实现为模型的中介,这样就可以避免使用Set。
但如果您需要实施转换器,我建议在下面进行更改:
@Component
public class RoleToUserProfileConverter implements Converter<Object, UserProfile>{
static final Logger logger = LoggerFactory.getLogger(RoleToUserProfileConverter.class);
@Autowired
private UserProfileService userProfileService;
private HashMap<Integer, UserProfile> userProfiles;
/**
* Gets UserProfile by Id
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
public UserProfile convert(Object element) {
Integer id = Integer.parseInt((String)element);
UserProfile profile = findUserProfile(id);
logger.info("Profile : {}",profile);
return profile;
}
private UserProfile findUserProfile(Integer id) {
//First time loading profiles
if(userProfiles == null) {
userProfiles = new HashMap<>();
List<UserProfile> userProfileList = userProfileService.findAll();
for(UserProfile userProfile: userProfileList) {
userProfiles.put(userProfile.getId(), userProfile);
}
}
if(userProfiles.containsKey(id)) {
return userProfiles.get(id);
}
return null;
}
}
在这个例子中,我使用一个hashmap来保存所有应该更少的UserProfile,然后第一次加载并重新加载。
您可以通过检查您正在查找的ID是否在哈希中来改进它,以便查询数据库并存储它,这样就可以按需加载新的UserProfiles。