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. Codeforces Gym100783H 最短路 其他

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100783H.html 题目传送门 - CF-Gym100783H 题意 给定一个 $n$ 个节点 ...

  2. Linux安装Tomcat-Nginx-FastDFS-Redis-Solr-集群——【第二集之新建虚拟机】

    1, 2, 3, 4,(如果选择版本时,发现选项中没有centos,可以选择other linux2.6.x kernel) 5,(虚拟机命名:Centos_用途_IP) 6,(选择Split vir ...

  3. day67 ORM模型之高阶用法整理,聚合,分组查询以及F和Q用法,附练习题整理

    归纳总结的笔记: day67 ORM 特殊的语法 一个简单的语法 --翻译成--> SQL语句 语法: 1. 操作数据库表 创建表.删除表.修改表 2. 操作数据库行 增.删.改.查 怎么连数据 ...

  4. POJ 1094 Sorting It All Out 【拓扑排序】

    <题目链接> 题目大意: 对于N个大写字母,给定它们的一些关系,要求判断出经过多少个关系之后可以确定它们的排序或者排序存在冲突,或者所有的偏序关系用上之后依旧无法确定唯一的排序. 解题分析 ...

  5. Linux学习之日志管理(二十一)

    Linux学习之日志管理 目录 日志管理 日志服务 rsyslogd的新特点 启动日志服务 常见日志的作用 日志文件的一般格式 rsyslogd日志服务 /etc/rsyslog.conf配置文件 服 ...

  6. Unity容器在asp.net mvc中的IOC应用及AOP应用

    <asp.net-mvc框架揭秘>一书中,有个示例,是使用unity容器来注入自定义的控制器工厂.代码示例可以自己去下载源码,在这里我就不说了.IOC容器的本质是解耦的实例化接口类,而如何 ...

  7. Jenkins部署码云SpringBoot项目

    本文介绍jenkins如何从gitee上clone项目,然后使用maven打包并后台启动. 1.Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续 ...

  8. Windows 7 下如何配置 java 环境变量

    安装 JDK.从Oracel官方网站上下载,下载完成后安装. http://www.oracle.com/technetwork/java/javase/downloads/jdk8-download ...

  9. angular笔记_1

    第一个angular文件<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js&q ...

  10. 获取Android设备WIFI的MAC地址 “MAC地址”

    需要指出的是:wifi状态和wifi AP状态是互斥的状态:也就是一旦发现WIFI AP打开,WIFI是不能被打开的. 获取Android设备的WIFI MAC地址,首先需要将设备中的WIFI个人热点 ...