我面临同样的问题,但在我的情况下,一个或多个字段可以重复(用户名或电子邮件)。因此,org.hibernate.exception.ConstraintViolationException 不足以具体说明用户名或电子邮件是否导致引发此异常以及结果显示什么消息。
我刚刚查看了danny.lesnik's answer,但它并不好,因为它只是重定向到“专用”页面。假设您只是重定向到用户所在的页面将避免创建您所说的新页面。但是,我假设您已经有一个 Spring validator 进行一些表单验证工作。这就是为什么在我的情况下,我决定在同一个地方(在验证器中)简单地进行我的字段(用户名和电子邮件)重复检查。似乎是一个更合适、更一致(位于验证的其余部分)和更清洁的解决方案。
这里有一些代码来说明:
我的控制器
@Controller
public class WebController {
@Autowired
private UserServiceImpl userService;
@Autowired
private CustomUserDetailsValidator customUserDetailsValidator;
...
@RequestMapping(value = "/login/create-account", method = RequestMethod.POST)
public String createAccount(@ModelAttribute("user") CustomUserDetails user, BindingResult result, Model model, SessionStatus status) {
customUserDetailsValidator.validate(user, result);
if(result.hasErrors()){
model.addAttribute("user", user);
// Print the errors to the console - FIXME: log error instead
System.out.println("Validation errors:");
for (FieldError error : result.getFieldErrors()) {
System.out.println(error.getField() + " - " + error.getDefaultMessage());
}
return "login/create-account";
}
else{
userService.registerUser(user);
return "redirect:/login/create-account-success";
}
}
...
}
我的验证者
public class CustomUserDetailsValidator implements Validator {
@Autowired
private UserServiceImpl userService;
...
@Override
public void validate(Object target, Errors errors) {
// some simple validations
// and here some complex validation (is username or email used duplicated?)
if(errors.getAllErrors().size() == 0){
if ( userService.doesUsernameAlreadyExist( user.getUsername() ) )
errors.rejectValue(usernameFieldName, "duplicate.username","username already exists");
if ( userService.doesEmailAlreadyExist( user.getEmail() ) )
errors.rejectValue(emailFieldName, "duplicate.email","email already exists");
}
}
}
我不确定这是否是最好的方法,但我认为我的解决方案将允许更多扩展(您可以对任何其他约束添加各种检查)。
希望它可以帮助其他人,并且让更多开发人员对这个解决方案产生想法也很有趣。