补习系列-springboot 参数校验详解 (3)

针对@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规范

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsdxg.html