spring-boot 请求参数校验:注解 @Validated 的使用、手动校验、自定义校验

前言

spring-boot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。
spring-boot已经引入了基础包,所以直接使用就可以。

注解 @validated 的使用

@RestController
@Validated
public class LoginController {
    /**
     * 登录接口
     * @return
     */
    @PostMapping("login")
    public String login(@Length(min = 6, max = 12, message = "密码长度必须在6位到12位之间")String pwd) {
        return "ok";
    }
}

注解 @validated 校验参数类

在属性上添加校验注解:

import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.*;

public class User {

    @NotBlank(message = "用户名不能为null,长度必须大于0")
    String name;   //用户名

    @Min(value = 1, message = "最小年龄为1岁")
    @Max(value = 120, message = "最大年龄为120岁")
    Integer age;  //年龄

    @Email(message = "邮箱格式错误")
    @NotBlank(message = "邮箱必填")
    @Size(min = 6, max = 50, message = "邮箱长度必须在6位到50位之间")
    String email;  //邮箱

    @Length(min = 6, max = 12, message = "密码长度必须在6位到12位之间")
    String pwd;//密码
    
    //...
}

在Controller上添加 @Validated 注解

    /**
     * 登录接口
     * @return
     */
    @PostMapping("login")
    public String login(@Validated @RequestBody User user) {
        return "ok";
    }

校验未通过时,可能看到:

{
  "msg": "邮箱格式错误",
  "code": 500
}

可用的校验注解

JSR提供的校验注解:         
@Null   被注释的元素必须为 null    
@NotNull    被注释的元素必须不为 null,不能为 null , 可以为 ""    
@AssertTrue     被注释的元素必须为 true    
@AssertFalse    被注释的元素必须为 false    
@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@Size(max=, min=)   验证对象(Array,Collection,Map,String)长度是否在给定的范围之内    
@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内    
@Past   被注释的元素必须是一个过去的日期    
@Future     被注释的元素必须是一个将来的日期    
@Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式    

Hibernate Validator提供的校验注解:  
@NotBlank(message =)   只能作用在String上,不能为null,而且调用trim()后,长度必须大于0    
@Email  被注释的元素必须是电子邮箱地址    
@Length(min=,max=)  被注释的字符串的大小必须在指定的范围内    
@NotEmpty   被注释的字符串的必须非空,不能为 null、"",可以为 " "    
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内

手动处理错误

@Validated后面紧跟着追加BindingResult,可接管检验后的处理(处理校验出来的错误):

  /**
     * 登录接口
     *
     * @return
     */
    @PostMapping("login")
    public String login(@Validated @RequestBody User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            //有校验没通过
            List<ObjectError> errorList = bindingResult.getAllErrors();
            for (ObjectError error : errorList) {
                System.out.println(error.getDefaultMessage());  //输出具体的错误信息
            }
            return "参数异常";
        }
        return "ok";
    }

嵌套校验

如果一个类中包含了另外一个实体类,那么在上面加上@Validated即可,比如上面的

 public class User {    
    @validated
    private Dept dept;
 }

@pathvariable的校验

暂不支持

手动校验

    /**
     * 登录接口
     * @return
     */
    @PostMapping("login")
    public String login(@RequestBody User user) {
	    ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
		Validator validator = vf.getValidator();
		Set<ConstraintViolation<User>> set = validator.validate(user);
		for (ConstraintViolation<User> constraintViolation : set) {
		    System.out.println(constraintViolation.getMessage());
		}
        return "ok";
    }

自定义约束注解

自定义约束注解:

/**
 * 自定义手机号约束注解
 */
@Documented
// 注解的作用目标
@Target({ElementType.FIELD})
// 注解的保留策略
@Retention(RetentionPolicy.RUNTIME)
// 不同之处:于约束注解关联的验证器
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
 
    // 约束注解验证时的输出信息
    String message() default "手机号校验错误";
 
    // 约束注解在验证时所属的组别
    Class<?>[] groups() default {};
 
    // 约束注解的有效负载(严重程度)
    Class<? extends Payload>[] payload() default {};
}

真正的校验者类:

/**
 * 自定义手机号约束注解关联验证器
 */
public class PhoneValidator
        implements ConstraintValidator<Phone, String> {
 
    /**
     * 自定义校验逻辑方法
     * @param value
     * @param context
     * @return
     */
    @Override
    public boolean isValid(String value,
                           ConstraintValidatorContext context) {
 
        // 手机号验证规则:158后头随便
        String check = "158\\d{8}";
        Pattern regex = Pattern.compile(check);
 
        // 空值处理
        String phone = Optional.ofNullable(value).orElse("");
        Matcher matcher = regex.matcher(phone);
 
        return matcher.matches();
    }
}

自定义注解使用:

public class User{
    /**
     * 手机号
     */
    @Phone(message = "手机号不是158后头随便")
    private String phone;
}

手动校验时,自定义注解使用:

Configuration config = Validation.byProvider(PhoneValidator.class).configure();   
ValidatorFactory vf = config.buildValidatorFactory();   
Validator validator = vf.getValidator();  

参考

https://docs.spring.io/spring-framework/docs/5.0.6.RELEASE/spring-framework-reference/core.html#validation-beanvalidation
https://docs.spring.io/spring-framework/docs/5.0.6.RELEASE/spring-framework-reference/web.html#mvc-config-validation
https://docs.spring.io/spring-boot/docs/2.2.13.RELEASE/reference/htmlsingle/#boot-features-validation
https://www.cnblogs.com/zhaoyanjun/p/9007056.html
https://www.cnkirito.moe/spring-validation/
https://www.cnblogs.com/dinghaoran/p/12924518.html
https://www.jianshu.com/p/b3876bf9396c
https://blog.csdn.net/zhu_tianwei/article/details/43272181

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值