JSR303参数校验
系统需要登录时先做一个参数校验,有的方法同样也需要做参数校验,例如注册。
为了大量代码重复,这里使用JSR303校验
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
登录功能中我们要验证loginVo中两个属性
- Controller中在参数loginVo前加上标签@Valid
@RequestMapping("/do_login")
@ResponseBody
public Result<Boolean> doLogin(HttpServletResponse response, @Valid LoginVo loginVo) {
log.info(loginVo.toString());
//登录
userService.login(response, loginVo);
return Result.success(true);
}
- 在LoginVo类中每一个需要验证的属性上加注解,这里自定义了一个IsMobile校验器
public class LoginVo {
@NotNull
@IsMobile
private String mobile;
@NotNull
@Length(min=32) //formPass为32个字符,128字节
private String password;
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "LoginVo{" +
"mobile='" + mobile + '\'' +
", password='" + password + '\'' +
'}';
}
}
自定义校验器
- 定义@IsMobile注解
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {IsMobileValidator.class} //系统看到@IsMobile注解时调用的校验器
)
public @interface IsMobile {
boolean required() default true; //默认不能为空
String message() default "手机号格式错误"; //验证不通过时的信息
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- 定义具体的IsMobileValidator校验器类来判断格式问题
//需要extends ConstraintValidator,String为校验器校验的字段类型
public class IsMobileValidator implements ConstraintValidator<IsMobile,String> {
private boolean required = false;
//初始化时接收注解里的值
@Override
public void initialize(IsMobile isMobile) {
required = isMobile.required();
}
//判断value是否合法
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if (required) {
return ValidatorUtil.isMobile(value);
} else {
if (StringUtils.isEmpty(value)) {
return true;
} else {
return ValidatorUtil.isMobile(value);
}
}
}
}
ValidatorUtil类
public class ValidatorUtil {
//正则表达式:第一位为1,后面加10位数字
private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");
public static boolean isMobile(String src) {
if (StringUtils.isEmpty(src)) {
return false;
}
Matcher m = mobile_pattern.matcher(src);
return m.matches();
}
}
全局异常处理
参数校验不通过会出现org.springframework.validation.BindException的异常,需要拦截这个绑定异常,输出错误信息。
这里自定义一个全局异常拦截器,使用@ControllerAdvice注解
@ControllerAdvice可用于实现:
- 全局异常处理 @ExceptionHandler
- 全局数据绑定 @ModelAttribute
- 全局预处理 @ModelAttribute, @InitBinder
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(value=Exception.class)//指明异常的处理类型
public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
e.printStackTrace();
if (e instanceof GlobalException) {
GlobalException ex = (GlobalException)e;
return Result.error(ex.getCm());
} else if (e instanceof BindException) { //处理BindException
BindException ex = (BindException)e;
List<ObjectError> errors = ex.getAllErrors();
ObjectError error = errors.get(0); //这里只取第一个,可以都取
String msg = error.getDefaultMessage();
return Result.error(CodeMsg.BIND_ERROR.fillArgs(msg)); //返回带参数的错误码
} else {
return Result.error(CodeMsg.SERVER_ERROR);
}
}
}
CodeMsg
public class CodeMsg {
...
public static CodeMsg BIND_ERROR = new CodeMsg(500101, "参数校验异常:%s");
public CodeMsg(int code, String msg) {
this.code = code;
this.msg = msg;
}
public CodeMsg fillArgs(Object... args) { //实参个数可变
int code = this.code;
String message = String.format(this.msg, args); //原始信息拼接参数
return new CodeMsg(code, message);
}
}