刚刚学习SpringBoot,最近在做一个小小项目,使用到了Validation对前端传来的参数进行校验,具体操作如下:
使用Validation组件进行参数校验
-
添加pom依赖
<!--validation校验组件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
-
在Controller层添加@Valid注解
@RequestMapping("/doLogin") @ResponseBody public ResponseBean doLogin(@Valid LoginVo loginVo) { log.info("{}", loginVo); return userService.doLogin(loginVo); } }
-
在校验的bean定义中添加相应的校验注解
@Data public class LoginVo { @NotNull @IsMobile // 自定义注解 private String mobile; @NotNull @Length(min = 32, max = 32) private String password; }
-
由于存在自定义注解,所以需要编写注解
// 去复制其他的注解定义的内容,稍加修改 @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint( validatedBy = {IsMobileValidator.class} // 添加自定义校验类 ) public @interface IsMobile { // 是否必填,默认为true boolean required() default true; // 自定义默认返回信息 String message() default "手机号码格式错误"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
-
编写自定义校验类
public class IsMobileValidator implements ConstraintValidator<IsMobile, String> { private boolean required = false; // 是否必须字段 @Override public void initialize(IsMobile constraintAnnotation) { required = constraintAnnotation.required(); // 初始化 } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (!required) { // 如果非必须 if (StringUtils.isEmpty(value)) { // 如果非必须且为空直接返回true return true; } } return ValidatorUtil.isMobile(value); // 通过自定义校验规则校验 } }
-
ValidatorUtil.isMobile(String mobile)的定义
// 手机号码正则表达式 private static final Pattern MOBILE_PATTERN = Pattern.compile("[1]([3-9])[0-9]{9}$"); /** * 校验手机号是否正确 * @param mobile 手机号 * @return boolean */ public static boolean isMobile(String mobile) { if (StringUtils.isEmpty(mobile)) { return false; } Matcher matcher = MOBILE_PATTERN.matcher(mobile); return matcher.matches(); }
-
可以通过异常处理捕获BindException并将异常返回给前端处理
-
定义全局异常类
@Data @NoArgsConstructor @AllArgsConstructor public class GlobalException extends RuntimeException { private ResponseBeanEnum responseBeanEnum; }
-
定义全局异常处理类
@RestControllerAdvice // RestController增强器 public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) // 捕获所有Exception public ResponseBean exceptionHandler(Exception e) { if (e instanceof GlobalException) { GlobalException ex = (GlobalException) e; return ResponseBean.error(ex.getResponseBeanEnum()); } else if (e instanceof BindException) { // 如果异常是BindException BindException ex = (BindException) e; ResponseBean responseBean = ResponseBean.error(ResponseBeanEnum.BIND_ERROR); responseBean.setMessage("参数校验异常:" + ex.getBindingResult().getAllErrors().get(0).getDefaultMessage()); return responseBean; } return ResponseBean.error(ResponseBeanEnum.ERROR); } }
-
-
Validation组件如果校验不通过会抛出BindException异常,我们在上面的全局异常处理类GlobalExceptionHandler
中对此进行了捕获,可以看到,如果出现此异常,我们直接返回了错误信息responseBean.setMessage("参数校验异常:" + ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
其中ResponseBean
是我自定义的返回类型
所以只有参数校验通过了请求才会落到Controller层