我在Web应用程序中有一个子系统,它在注册过程中执行交互式验证,因此当用户键入用户名,电子邮件,密码等时,会向服务器发出异步请求以执行验证,然后返回一个回复。
对用户名或电子邮件执行的验证之一是,它们尚未用于任何其他用户,这意味着需要对数据库进行查询,这就是我选择在服务器端执行验证的原因。我使用的是Spring Framework 4.1,Spring Data和Hibernate Validator 5.1。
对于可用的用户名和电子邮件验证,按照HV参考指南我创建了自定义约束注释(仅显示用户名1):
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueUsernameValidator.class)
@Documented
public @interface UniqueUsername {
String message() default "{}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
和验证员类:
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername,String> {
private final UserRepository userRepository;
@Autowired
public UniqueUsernameValidator(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public void initialize(UniqueUsername annotation) {}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// this should be checked with @NotNull at field level
if (value == null)
return true;
User user = userRepository.findByUsername(value);
if (user == null)
return true;
return false;
}
}
因此,当用户键入表单字段时,有jQuery的AJAX请求,我在其中序列化整个表单并在POST请求中发送,我使用这样的@RestController捕获:
@RequestMapping(value = "/signup/validation/{field}", method = RequestMethod.POST)
public ResponseEntity<ValidationResponse> validateField(
@PathVariable("field") String field,
@Valid @ModelAttribute("registrationForm") UserRegistrationForm registrationForm,
BindingResult result,
Locale locale) {
...
}
问题1 :如果存储库在验证器类中抛出DataAccessException,是否有办法在使用@Valid注释时在其余控制器上捕获它?
问题2 :这种方法有什么问题吗?
注意:我没有在验证器类中捕获DataAccessException,因为我不希望它传播并能够在控制器上捕获它,所以我可以返回一个合适的具有ResponseEntity返回值的HTTP 500代码并通知用户验证存在一些问题,因为如果数据库由于某种原因而关闭,则注册请求将无法持久存在。
注意:我可以在@RestController方法中获取验证器实例,然后在那里执行验证,并且能够轻松捕获异常,这是我使用的解决方法现在,但是为了减少样板和代码重复,我想避免这种情况。