1. 概述

作为接口服务提供方,非常有必要在项目中加入参数校验,比如字段非空,字段长度限制,邮箱格式验证等等,数据校验常用到概念:
JSR303/JSR-349: JSR303是一项标准,只提供规范不提供实现,规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,位于javax.validation.constraints包下。JSR-349是其的升级版本,添加了一些新特性。
hibernate validation:hibernate validation是对这个规范的实现,并增加了一些其他校验注解,如@Email,@Length,@Range等等
spring validation:spring validation对hibernate validation进行了二次封装,在springmvc模块中添加了自动校验,并将校验信息封装进了特定的类中,能够通过BindingResult类在Controller层的处理方法中取得错误信息

如何校验

引入Maven依赖

在pom.xml中加入maven依赖, validation-api, hibernate-validator

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.0.Final</version>
</dependency>

spring-boot-starter-web已经依赖了validation-api和hibernate-validator,所以引入spring-boot-starter-web之后就不需要引入这两个依赖了。

Model上加JSR-303注解类型

JSR-303定义的校验类型:

空检查: 
@Null 验证对象是否为null 
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串 
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格. 
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.

Booelan检查: 
@AssertTrue 验证 Boolean 对象是否为 true 
@AssertFalse 验证 Boolean 对象是否为 false

长度检查: 
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内 
@Length(min=, max=) Validates that the annotated string is between min and max included.

日期检查: 
@Past 验证 Date 和 Calendar 对象是否在当前时间之前 
@Future 验证 Date 和 Calendar 对象是否在当前时间之后

数值检查: 
建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为”“,Integer为null 
@Min 验证 Number 和 String 对象是否大等于指定的值 
@Max 验证 Number 和 String 对象是否小等于指定的值 
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度 
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度 
@Digits 验证 Number 和 String 的构成是否合法 
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。

@Range(min=, max=) Checks whether the annotated value lies between (inclusive) the specified minimum and maximum. 
@Range(min=10000,max=50000,message=”range.bean.wage”) 
private BigDecimal wage;

@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证) 
@CreditCardNumber信用卡验证 
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。 
@ScriptAssert(lang= ,script=, alias=) 
@URL(protocol=,host=, port=,regexp=, flags=)

@Pattern 验证 String 对象是否符合正则表达式的规则

hibernate validator校验demo

先来看一个简单的demo,添加了Validator的注解:

package com.winner.model;

import org.hibernate.validator.constraints.Length;

import javax.validation.Valid;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.util.List;

/**
 * @author winner_0715
 * @description:
 * @date 2018/12/5
 */
public class ParamRo {

    @NotBlank(message = "userName不允许为空")
    @Length(min = 2, max = 5, message = "userName长度必须在{min}-{max}之间")
    private String userName;

    @NotBlank(message="年龄不能为空")
    @Pattern(regexp="^[0-9]{1,2}$",message="年龄不正确")
    private String userAge;

    @NotNull(message = "price不允许为空")
    @DecimalMin(value = "15.5", message = "价格不能低于 {value}")
    private BigDecimal price;

    @AssertFalse(message = "必须为false")
    private Boolean isFalse;
    /**
     * 如果是空,则不校验,如果不为空,则校验
     */
    @Pattern(regexp="^[0-9]{4}-[0-9]{2}-[0-9]{2}$",message="出生日期格式不正确")
    private String birthday;

    /**
     * 注意这里必须加@Valid注解
     */
    @Valid
    private List<ParamItem> list;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public String getUserAge() {
        return userAge;
    }

    public void setUserAge(String userAge) {
        this.userAge = userAge;
    }

    public Boolean getFalse() {
        return isFalse;
    }

    public void setFalse(Boolean aFalse) {
        isFalse = aFalse;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public List<ParamItem> getList() {
        return list;
    }

    public void setList(List<ParamItem> list) {
        this.list = list;
    }
}

POST接口验证,验证不通过的结果在全局处理器中处理,略

@RequestMapping(value = "/param/validate/post", method = RequestMethod.POST)
public ResultBean paramValidationPost(@Valid @RequestBody ParamRo ro) {
    return ResultBeanUtils.success(ro);
}

http://localhost:8080/param/validate/post,请求参数如下

{
    "userName": "zhangsan",
    "userAge":"1000",
    "price": 25.6,
    "isFalse":true,
    "birthday":"1990-09-09",
    "list": [
        {
            "address": "beijing"
        }
    ]
}

响应结果

{
    "success": false,
    "msg": "年龄不正确;address长度必须在2-5之间;userName长度必须在2-5之间;",
    "data": null,
    "errorCode": 0
}

参数验证非常方便,字段上注解+验证不通过提示信息即可代替手写一大堆的非空和字段限制验证代码。

hibernate的校验模式

上面例子中一次性返回了所有验证不通过的集合,通常按顺序验证到第一个字段不符合验证要求时,就可以直接拒绝请求了。

Hibernate Validator有以下两种验证模式:

普通模式

普通模式(会校验完所有的属性,然后返回所有的验证失败信息)

快速失败返回 

快速失败返回模式(只要有一个验证失败,则返回)

两种验证模式配置方式:

failFast:true  快速失败返回模式    false 普通模式

ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure()
        .failFast( true )
        .buildValidatorFactory();
Validator validator = validatorFactory.getValidator();

和 (hibernate.validator.fail_fast:true  快速失败返回模式    false 普通模式)

ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure()
        .addProperty( "hibernate.validator.fail_fast", "true" )
        .buildValidatorFactory();
Validator validator = validatorFactory.getValidator();

配置hibernate Validator为快速失败返回模式:

package com.winner.validate;

import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

@Configuration
public class ValidatorConfiguration {
    @Bean
    public Validator validator(){
        ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                .configure()
                .addProperty( "hibernate.validator.fail_fast", "true" )
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        return validator;
    }
}

此时相同的输入,输出变成

{
    "success": false,
    "msg": "年龄不正确;",
    "data": null,
    "errorCode": 0
}

即快速失败

GET参数校验(@RequestParam参数校验)

使用校验bean的方式,没有办法校验RequestParam的内容,一般在处理Get请求(或参数比较少)的时候,会使用下面这样的代码:

@RequestMapping(value = "/param/validate/get/2", method = RequestMethod.GET)
public ResultBean paramValidationGet2(@RequestParam String name,
                                      @RequestParam String address) {
    return ResultBeanUtils.success(name + address);
}

使用@Valid注解,对RequestParam对应的参数进行注解,是无效的,需要使用@Validated注解来使得验证生效。如下所示:

a.此时需要使用MethodValidationPostProcessor 的Bean:

package com.winner.validate;

import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

@Configuration
public class ValidatorConfiguration {
    @Bean
    public Validator validator(){
        ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                .configure()
                .addProperty( "hibernate.validator.fail_fast", "true" )
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        return validator;
    }

    //@Bean
    //public MethodValidationPostProcessor methodValidationPostProcessor() {
    //  /**默认是普通模式,会返回所有的验证不通过信息集合*/
    //    return new MethodValidationPostProcessor();
    //}

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
        /**设置validator模式为快速失败返回*/
        postProcessor.setValidator(validator());
        return postProcessor;
    }
}

b.方法所在的Controller上加注解@Validated

package com.winner.web;

import com.winner.model.ParamRo;
import com.winner.model.ResultBean;
import com.winner.util.ResultBeanUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;

/**
 * @author winner_0715
 * @description:
 * @date 2018/12/5
 */
@RestController
@Validated
public class HelloController {
    @RequestMapping(value = "/param/validate/get/2", method = RequestMethod.GET)
    public ResultBean paramValidationGet2(
                                        @NotBlank(message = "name不允许为空")
                                        @Length(min = 2, max = 5, message = "name长度必须在{min}-{max}之间")
                                        @RequestParam String name,
                                        @Min(value = 18, message = "年龄必须大于18")
                                        @RequestParam int age) {
        return ResultBeanUtils.success(name + age);
    }

}

c.返回验证信息提示

验证不通过时,抛出了ConstraintViolationException异常,使用同一捕获异常处理:略

d.验证

http://localhost:8080/param/validate/get/2?name=zhangsan&age=16

快速失败模式结果

{
    "success": false,
    "msg": "name长度必须在2-5之间;",
    "data": null,
    "errorCode": 0
}

默认模式结果

{
    "success": false,
    "msg": "name长度必须在2-5之间;年龄必须大于18;",
    "data": null,
    "errorCode": 0
}

对象级联校验

对象内部包含另一个对象作为属性,属性上加@Valid,可以验证作为属性的对象内部的验证:(验证Demo2示例时,可以验证Demo2的字段)

@Data
public class Demo2 {
    @Size(min = 3,max = 5,message = "list的Size在[3,5]")
    private List<String> list;

    @NotNull
    @Valid
    private Demo3 demo3;
}

@Data
public class Demo3 {
    @Length(min = 5, max = 17, message = "length长度在[5,17]之间")
    private String extField;
}

参考:

https://www.cnblogs.com/mr-yang-localhost/p/7812038.html

Spring Boot参数校验的更多相关文章

  1. Spring Boot 参数校验

    1.背景介绍 开发过程中,后台的参数校验是必不可少的,所以经常会看到类似下面这样的代码 这样写并没有什么错,还挺工整的,只是看起来不是很优雅而已. 接下来,用Validation来改写这段 2.Spr ...

  2. Validated 注解完成 Spring Boot 参数校验

    1.  @Valid 和 @Validated @Valid 注解,是 Bean Validation 所定义,可以添加在普通方法.构造方法.方法参数.方法返回.成员变量上,表示它们需要进行约束校验. ...

  3. spring boot输入数据校验(validation)

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  4. spring boot 参数传递(spring boot 参数传数 arg0 每一个参数 arg0#{arg0},arg1 #{arg1})

    spring boot 参数传数 arg0 每一个参数 arg0#{arg0},arg1  #{arg1} @Select("select * from sys_user where nam ...

  5. Spring Boot (一) 校验表单重复提交

    一.前言 在某些情况下,由于网速慢,用户操作有误(连续点击两下提交按钮),页面卡顿等原因,可能会出现表单数据重复提交造成数据库保存多条重复数据. 存在如上问题可以交给前端解决,判断多长时间内不能再次点 ...

  6. 59. Spring Boot Validator校验【从零开始学Spring Boot】

    大纲: (1) 入门例子: (2) 国际化: (3) 在代码中添加错误信息: (1) 入门例子: Validator主要是校验用户提交的数据的合理性的,比如是否为空了,密码长度是否大于6位,是否是纯数 ...

  7. spring mvc参数校验

    一.在SringMVC中使用 使用注解 1.准备校验时使用的JAR validation-api-1.0.0.GA.jar:JDK的接口: hibernate-validator-4.2.0.Fina ...

  8. spring boot参数验证

    必须要知道 简述 JSR303/JSR-349,hibernate validation,spring validation 之间的关系 JSR303 是一项标准,JSR-349 是其的升级版本,添加 ...

  9. Spring boot validation校验

    使用 Hibernate validator 的步骤:1. 在 Pojo 类的字段上, 加上 Hibernate validator 注解2. 在Controller 函数的形参前加上 @Valid ...

随机推荐

  1. Centos6.5系统压力测试过程大量TIME_WAIT

    统计tcp状态的命令: netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' netstat -n | awk '/ ...

  2. js中的new Option默认选中

    new Option("文本","值",true,true).后面两个true分别表示默认被选中和有效! //js默认选中 var sel = document ...

  3. day 54 jQuery, part-1

    上节内容回顾: 1. 前情回顾 1. DOM对象和BOM对象 1. BOM 对象 --> window location location.href location.href="ht ...

  4. 关于mybatis缓存配置讲解

    一级缓存: 一级缓存是默认的. 测试:在WEB页面同一个查询执行两次从日志里面看同样的sql查询执行两次. 2次sql查询,看似我们使用了同一个sqlSession,但是实际上因为我们的dao继承了S ...

  5. 整合django和bootstrap框架

    环境: python版本:2.7.8 django版本:1.7.1 bootstrap版本:3.3.0 首先github上面有两个开源的项目用来整合django和bootstrap. https:// ...

  6. HBase的概述和安装部署

    一.HBase概述 1.HBase是Hadoop数据库,是一个分布式.可扩展的大数据存储. HBase是用于对大数据进行随机.实时读写访问的非关系型数据库,它的目标托管非常大的表——数十亿行N百万列. ...

  7. Codeforces 300C Beautiful Numbers 【组合数】+【逆元】

    <题目链接> 题目大意: 给出a和b,如果一个数每一位都是a或b,那么我们称这个数为good,在good的基础上,如果这个数的每一位之和也是good,那么这个数是excellent.求长度 ...

  8. java.util.List API解读

    list的API 如下: 下面是我对这段API的翻译 An ordered collection (also known as a sequence). 一个有序的集合(也被称为序列) The use ...

  9. redis安装,第一天

    1.直接官网下载 2.进入redis安装目录 : cd /redis-4.0.11    make install 3.启动:redis-server /myredis/redis.conf //复制 ...

  10. js点击回到顶部2

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>点 ...