使用Hibernate Validator进行REST接口上的数据校验

本文部分内容来自互联网。

在进行REST接口开发的时候,需要对POST/PUT等接口传入的参数进行一些校验的时候,可以通过Hibernate Validator提供的注解进行校验。这些注解放在参数实体定义的属性或者类上面,能够进行默认的校验。
配合@Valid注解和BindingResult功能一起使用,则可以在Controller的具体实现逻辑中进行校验后的处理。

1. 常用的校验注解

注解 功能
@NotNull 值不为空
@Null 值只能为空
@Pattern(regex=) 字符串必须匹配括号内的正则表达式
@Size(max=,min=) 集合的元素数量必须max和min之间的值
@CreditCardNumber(ignoreNonDigitCharacters=) 字符串必须是美国标准的信用卡卡号
@Email 字符串必须是email地址
@Length(min=,max=) 检查字符串的长度
@NotBlank 字符串必须有字符
@NotEmpty 字符串不为null,集合有元素
@Range(min=,max=) 数字必须大于min,小于max
@SafeHtml 字符串是安全的html代码
@URL 字符串是合法的url
@AssertFalse 值必须是false
@AssertTrue 值必须是true
@DecimalMax(value=,inclusive=) 值必须小于等于(inclusive=true)/值必须小于(inclusive=false):可以注解在字符串类型上
@DecimalMin(value=,inclusive=) 值必须大于等于(inclusive=true)/值必须大于(inclusive=false):可以注解在字符串类型上
@Max(value=) 值必须小于等于value指定的值,不能注解在字符串类型上
@Min(value=) 值必须大于等于value执行的值,不能注解在字符串类型上
@Digits(integer=,fraction=) 数字格式检查,integer指定整数部分的长度,fraction指定小数部分的长度
@Futrue 值必须是未来的注解
@Past 值只能是过去的时间

2. 在服务中使用校验

例如,通过请求添加一个用户信息,

  1. 那么首先需要在这个用户的定义时确定好要满足哪些信息。比如,用户名不能为空,密码不能为空等。
public class UserInfo {
    private int id;
    @NotBlank
    private String name;
    @NotNull
    private String passwd;
    @Range(min=10, message = "年龄不能小于10")
    private int age;
    private String mail;
    private String phoneNumber;
    private String address;
}
  1. 通过REST的post接口添加用户,则用户信息的body体必须满足这些条件,否则的话controller的服务中,就要校验,并捕获这些异常。
/**
     * 添加一个新的用户
     */
    @PostMapping(value = "/user")
    public UserInfo addOneSpecifiedUser(@Valid UserInfo userInfo, BindingResult errors) {
        if(errors.hasErrors()){
            errors.getAllErrors().stream().forEach(
                    error -> logger.error(error.toString())
            );
        }

        logger.info("进入到用户添加的页面");
        return userInfo;
    }

@Valid注解的功能是检查REST请求推送来的请求体是否满足预定义的格式,如果不满足,那么这些请求中的错误信息将会被BindingResult绑定的变量errors所接收,并带着这些异常进入请求响应代码,由请求响应部分去处理这些异常。

  1. 使用REST工具发送这样的请求后,产生的效果如下:
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController          : Field error in object 'userInfo' on field 'age': rejected value [1]; codes [Range.userInfo.age,Range.age,Range.int,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.age,age]; arguments []; default message [age],9223372036854775807,10]; default message [年龄不能小于10]
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController          : Field error in object 'userInfo' on field 'passwd': rejected value [null]; codes [NotNull.userInfo.passwd,NotNull.passwd,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.passwd,passwd]; arguments []; default message [passwd]]; default message [不能为null]

3. 自定义校验

要实现类似于本文中提供那些常用校验方式同样的便利,需要自定义我们自己的校验规则注解。

自定义注解进行校验的步骤

  1. 写一个校验注解,在注解中指定校验器类,校验注解与校验器一般一一对应。
  2. 写一个校验器类并在校验器类中写校验逻辑,校验器必须实现ConstraintValidator<?, ?>接口,第一个参数是对应的注解,第二个参数是要校验的属性的类型。

代码实例

S1: 自定义校验注解

package com.kunlun.validation.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

import com.kunlun.validation.validator.KlPatternValidator;

/**
 * 自定义的校验注解
 * 规则:
 *  1.如果字符串为空串或者为null,则不进行正则校验
 *  2.如果字符串不为空串,则必须进行正则校验
 * @author xc
 * @date 2018年1月19日上午11:38:02
 */
@Documented
// 指定该注解可以使用的地方
@Target(value= {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
// 指定实际进行校验的校验器,该校验器是自己写的且必须实现ConstraintValidator接口
@Constraint(validatedBy=KlPatternValidator.class)
public @interface KlPattern {
    /*
     * 用于验证的注解下列这三个方法必须要,这是Hibernate Validation框架要求的,否则程序再在调用的时候会报错
     * default用于对属性给定默认值
     *  如果不给定默认值,则在使用注解的时候必须给属性指定属性值,否则报错
     *  给定默认值时,在使用注解的时候可以不用指定属性值
     */
    String message() default "不符合正则!";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    // 没加default给定默认值,使用注解的时候该属性必须赋值,否则报错
    String regex();
    // value属性,加上了default "mercy" 使得该属性在使用注解的时候可以不用输入也不会报错
    String value() default "mercy";
}

S2: 与上面校验注解对应的校验器类

package com.kunlun.validation.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import com.kunlun.validation.annotation.KlPattern;

/**
 * KlPatternValidator是KlPattern注解实际调用的验证器
 * 在KlPatternValidator中完成校验逻辑
 * 
 * @author xc
 * @date 2018年1月19日上午11:44:38
 */
public class KlPatternValidator implements ConstraintValidator<KlPattern, String> {

    private String regex;

    /**
     * 通过initialize()可以获取注解里的属性值
     */
    @Override
    public void initialize(KlPattern constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
        regex = constraintAnnotation.regex();
    }

    /**
     * 实际验证逻辑
     *  返回值为true表示验证通过,
     *  返回值为false表示验证未通过
     */
    @Override
    public boolean isValid(String s, ConstraintValidatorContext ctx) {

        // 当前前端传过来的请求参数是空串,或者没传的时候,不进行后续正则校验
        if ("".equals(s) || s == null) {
            return true;
        }

        // 进行正则校验
        if(s.matches(regex)) {
            return true;
        }

        return false;
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • 摘要:MVC模式早在上个世纪70年代就诞生了,直到今天它依然存在,可见生命力相当之强。MVC模式最早用于Small...
    在风口阅读 1,553评论 1 20
  • SpringMVC介绍之Validation 对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时...
    yongguang423阅读 1,185评论 0 16
  • 一、什么是REST REST是一种软件架构风格,或者说是一种规范,其强调HTTP应当以资源为中心,并且规范了URI...
    Ferrari1001阅读 44,155评论 3 32
  • 文/李晓 图/网图 每一件事情都有沟通成本。尤其是在教别人一件你已经会的事情的时候。最最简单的例子,你需要做一张报...
    adaya阅读 615评论 0 2
  • 放学归来,和老妈一起到家门口的丝域养发馆洗头。 往日,老妈都带我去朗斯洗头,闹哄哄的,而刚走进这里,婉...
    阿莫灵阅读 198评论 0 0