针对@PasswordEquals实现校验逻辑
public class PasswordEqualsValidator implements ConstraintValidator<PasswordEquals, RegisterForm> {
@Override
public void initialize(PasswordEquals anno) {
}
@Override
public boolean isValid(RegisterForm form, ConstraintValidatorContext context) {
String passwordConfirm = form.getPasswordConfirm();
String password = form.getPassword();
boolean match = passwordConfirm != null ? passwordConfirm.equals(password) : false;
if (match) {
return true;
}
String messageTemplate = context.getDefaultConstraintMessageTemplate();
// disable default violation rule
context.disableDefaultConstraintViolation();
// assign error on password Confirm field
context.buildConstraintViolationWithTemplate(messageTemplate).addPropertyNode("passwordConfirm")
.addConstraintViolation();
return false;
}
}
如此,我们已经完成了自定义的校验工作。
六、异常拦截器
SpringBoot 框架中可通过 @ControllerAdvice 实现Controller方法的拦截操作。
可以利用拦截能力实现一些公共的功能,比如权限检查、页面数据填充,以及全局的异常处理等等。
在前面的篇幅中,我们提及了各种校验失败所产生的异常,整理如下表:
异常类型
描述
ConstraintViolationException
违反约束,javax扩展定义
BindException
绑定失败,如表单对象参数违反约束
MethodArgumentNotValidException
参数无效,如JSON请求参数违反约束
MissingServletRequestParameterException
参数缺失
TypeMismatchException
参数类型不匹配
如果希望对这些异常实现统一的捕获,并返回自定义的消息,
可以参考以下的代码片段:
@ControllerAdvice
public static class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { ConstraintViolationException.class })
public ResponseEntity<String> handle(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
StringBuilder strBuilder = new StringBuilder();
for (ConstraintViolation<?> violation : violations) {
strBuilder.append(violation.getInvalidValue() + " " + violation.getMessage() + "\n");
}
String result = strBuilder.toString();
return new ResponseEntity<String>("ConstraintViolation:" + result, HttpStatus.BAD_REQUEST);
}
@Override
protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status,
WebRequest request) {
return new ResponseEntity<Object>("BindException:" + buildMessages(ex.getBindingResult()),
HttpStatus.BAD_REQUEST);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return new ResponseEntity<Object>("MethodArgumentNotValid:" + buildMessages(ex.getBindingResult()),
HttpStatus.BAD_REQUEST);
}
@Override
public ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return new ResponseEntity<Object>("ParamMissing:" + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@Override
protected ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
return new ResponseEntity<Object>("TypeMissMatch:" + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
private String buildMessages(BindingResult result) {
StringBuilder resultBuilder = new StringBuilder();
List<ObjectError> errors = result.getAllErrors();
if (errors != null && errors.size() > 0) {
for (ObjectError error : errors) {
if (error instanceof FieldError) {
FieldError fieldError = (FieldError) error;
String fieldName = fieldError.getField();
String fieldErrMsg = fieldError.getDefaultMessage();
resultBuilder.append(fieldName).append(" ").append(fieldErrMsg).append(";");
}
}
}
return resultBuilder.toString();
}
}
默认情况下,对于非法的参数输入,框架会产生 HTTP_BAD_REQUEST(status=400) 错误码,
并输出友好的提示消息,这对于一般情况来说已经足够。
更多的输入校验及提示功能应该通过客户端去完成(服务端仅做同步检查),
客户端校验的用户体验更好,而这也符合富客户端(rich client)的发展趋势。
参考文档
springmvc-validation样例
使用validation api进行操作
Bean-Validation规范