最近把参数验证修改为自定义注解验证的需求,并设置全局的异常处理来捕捉参数验证未通过的情况。将基本的代码记录一下。
简单设置一下情景:
登录情景,登录的用户使用手机号和密码输入进行登录,验证手机号是否符合要求。
引入验证validation依赖。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
dependency>
将输入的手机号和密码整理成一个bean形式,方便使用注解
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginInfo {
@NotNull
@IsMobile(required = true)
private Long phoneNumber;
@NotNull
private String password;
}
使用了lombok来减少代码。@NotNull
为validation包实现的注解,@IsMobile
为自定义注解,用来验证手机号码形式正确性。
实现自定义注解类,将作用域设置为参数和成员。
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {IsMobileValidator.class})
public @interface IsMobile {
boolean required() default true;
String message() default "手机格式校验错误";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
require
中存放是否必要的布尔值,message
中存放错误提示信息,在后续的异常处理中使用。@Constraint
注解中对具体的参数验证类进行指定。
实现ConstraintValidator
接口,并在泛型中指定对应的注解类型和验证参数的类型。
// 手机号码校验类
public class IsMobileValidator implements ConstraintValidator<IsMobile, Long> {
// 是否必要
private boolean required = false;
@Override
public void initialize(IsMobile constraintAnnotation) {
required = constraintAnnotation.required();
}
@Override
public boolean isValid(Long s, ConstraintValidatorContext constraintValidatorContext) {
String ls = s.toString();
if(required){
return ValidatorUtil.isMobile(ls);
}else{
// 非必要情况,为空也可
// 不为空则校验
if(StringUtils.isEmpty(ls)){
return true;
}else{
return ValidatorUtil.isMobile(ls);
}
}
}
}
首先通过initialize()
方法可获取到触发验证的注解,进行属性的设置等前置操作。之后调用isValid()
方法进行参数验证,返回false的话,会抛出BindException
异常。
ValidatorUtil
为验证逻辑工具类。
public class ValidatorUtil {
public static boolean isMobile(String s){
if(s.isEmpty())
return false;
return s.length() == 11;
}
}
使用@RestControllerAdvice
和@ExceptionHandler
进行设置。
// 处理控制器抛出的异常
@RestControllerAdvice
public class GlobalExceptionHandler {
// 所有异常杂糅在一起处理
@ExceptionHandler(Exception.class)
public CommonResponse handleException(Exception e){
System.out.println(e.toString());
if(e instanceof GlobalException){
GlobalException ge = (GlobalException)e;
return new CommonResponse(false, ge.getMESSAGE());
}else if(e instanceof BindException){
BindException be = (BindException)e;
return new CommonResponse(false, "校验异常:" + be.getBindingResult().getAllErrors().get(0).getDefaultMessage());
}
return new CommonResponse(false, e.getMessage());
}
}
只要是针对BindException
进行捕获,使用getBindingResult().getAllErrors().get(0).getDefaultMessage()
来获取验证注解中设置的验证错误提示信息,以实现校验错误时的后续处理。
@ResponseBody
@RequestMapping("/checkLogin")
public CommonResponse checkLogin(@Valid LoginInfo loginInfo, HttpServletRequest request, HttpServletResponse response){
log.info("{}, {}", loginInfo.getPhoneNumber(), loginInfo.getPassword());
return userService.checkUserLogin(loginInfo.getPhoneNumber(), loginInfo.getPassword(), request, response);
}
使用@Valid
注解即可。
使用springboot中集成的hibernate-validator进行参数校验的自定义注解实现,还是挺方便的。简单记录一下用法,感兴趣的看看吧。