专栏首页晏霖JavaBean基于注解实现校验

JavaBean基于注解实现校验

前言 上一文我通过传递不合法参数触发异常,进行了统一拦截,那么这篇文章主要介绍JSR303,Hibernate Validator详细讲解及如何优雅的对参数进行校验,使用和技巧。

正文 JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了,笔者还是基于springboot(1.5.8.RELEASE)。

直接上干货,带你们一起实验是使用org.hibernate.validator.constraints包下的注解。

首先定义一个实体类,属性分别用了校验注解,分别进行触发。

import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.List;

/**
 * @author yanlin
 * @version v1.3
 * @date 2018-10-18 下午3:16
 * @since v8.0
 **/
public class Student implements Serializable {
    private static final long serialVersionUID = 7003907324788760110L;
    @NotBlank(message = "姓名不能为空")
    private String name;
    @Min(value = 2, message = "不能小于2")
    @Max(value = 5, message = "不能大于5")
    private Integer age;
    @NotEmpty(message = "集合不能为空")
    private List<String> stringList;
    @AssertTrue(message = "bool必须为true")
    private Boolean bool;
    @NotNull(message = "对象不能为空")
    private Student student;
    //省略getter setter

这是一个用来测试的 controller,

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.Valid;


/**
 * @author yanlin
 * @version v1.2
 * @date 2018-08-16 下午2:21
 * @since v8.0
 **/
@SpringBootApplication
@EnableDiscoveryClient
@RestController
//@Validated
public class EurekaClientApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApp.class, args);
    }


    @RequestMapping(value = "/ClientService/body", method = RequestMethod.POST)
    public void testBodyE(@Valid @RequestBody Student student) {
        System.out.println(student.toString());

    }

我利用postman发送五次请求,每一次我都更改了部分参数以便触发校验注解,下面是我操作的过程

1

2

3

4

5

图片

从上面的操作过程可以发现,其实不同类型的注解校验是有顺序的,并不是实体类里属性自上而下的顺序,最后一张图可以发现,我名字是空,但是断言bool是true时,他优先触发了断言,所以小伙伴们在使用的时候要主意哦,同类型的注解是有顺序的,切记,不同类型的不是越靠前越先触发哦!

下面介绍一下直接校验方法参数体中的基本数据类型,这是笔者在做这个实验前由于好奇心无意发现的,先贴两个注解的代码,你们会发现我上面写的代码,如果是JavaBean校验,我都会在参数前加@Valid,当然加@Validated效果也是一样的(这两个注解往下看我会有介绍),但是他俩最重要的区别是@Validated可以注释在类上,这个我当时很好奇,所以我实验了一下,结论是:当@Validated使用在类上时,会触发当前类所有写在方法参数上的参数校验注解的生效。

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {

    /**
     * Specify one or more validation groups to apply to the validation step
     * kicked off by this annotation.
     * <p>JSR-303 defines validation groups as custom annotations which an application declares
     * for the sole purpose of using them as type-safe group arguments, as implemented in
     * {@link org.springframework.validation.beanvalidation.SpringValidatorAdapter}.
     * <p>Other {@link org.springframework.validation.SmartValidator} implementations may
     * support class arguments in other ways as well.
     */
    Class<?>[] value() default {};

}
-----------------------------
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Valid {
}

例如:test方法的name参数前加参数校验注解(@NotBlank),但是类上必须加@Validated,否则你在基本数据类型前加的参数校验注解是不生效的,这点笔者已经实验了,大家直接当结论就可以。

/**
 * @author yanlin
 * @version v1.2
 * @date 2018-08-16 下午2:21
 * @since v8.0
 **/
@SpringBootApplication
@EnableDiscoveryClient
@Validated
public class EurekaClientApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApp.class, args);
    }


    @RequestMapping(value = "/ClientService/body", method = RequestMethod.POST)
    public void testBodyE(@Valid @RequestBody Student student) {
        System.out.println(student.toString());

    }

    @GetMapping("/ClientService/name")
    public String test(@NotBlank(message = "name 不能为空") @RequestParam("name") String name) {
        if (name.equals("1")) {
            throw new ParameterServiceException("这里填写错误代码,规范应是一个枚举", "描述当前错误原因");
        }
        return name;
    }

下面我总结一下@Validated&@Valid区别 1.该注解表示对该对象进行验证需要在实体类内配合其他注解使用

2.使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同

3.@Validated是@Valid 的一次封装,是Spring提供的校验机制使用。@Valid不提供分组功能

4.@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制

5.@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能

6.如果一个bean中包含第二个bean,这时要检验第二个bean中某个字段,即嵌套校验,必须要在第一个bean对象中使用@Valid标注到表示第二个bean对象的字段上,然后再第二个bean对象里面的字段上加上校验类型.

7.@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上

8.@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上

下面是我总结的所有参数校验注解的使用规则方法 空检查 @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 对象是否在当前时间之后

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

数值检查 建议使用在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=)

本篇依赖了我上篇文章的异常拦截处理,类图如下

类的代码在上篇文章已经贴出来了,大家自行拷贝。

注:对本文有异议或不明白的地方微信探讨,wx:15524579896

本文分享自微信公众号 - 晏霖(yanlin199507),作者:晏霖

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-01-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【RocketMq实战第六篇】-Offset

    实际运行 中的系统,难免 会遇到重新消费某条消息、 跳过 一段 时间内的消息等情况 。 这些异常情况的处理,都和 Offset 有关。

    胖虎
  • SpringBoot配置文件敏感信息加密

    SpringBoot配置文件中的内容通常情况下是明文显示,安全性就比较低一些。在application.properties或application.yml,比...

    胖虎
  • 深入理解HashMap及面试相关问答

    HashMap是面试必备的一个知识点,无论你是初级中级还是高级,基本上逃不过这个问题,下面的内容很简单,只要你理解了其中的含义,这对你使用hashmap和面试都...

    胖虎
  • 初识Java异常处理

    异常是程序之中导致程序中断的一种指令流,下面,通过两个程序来进行异常产生问题的对比。

    葆宁
  • 深入机器学习系列之异常检测

    今天要给大家介绍的是异常检测(Anomaly Detection), 它是机器学习的一个重要分支,实际应用领域广泛,更与我们的生活息息相关。那么什么是异常检测?...

    数据猿
  • 学习猿地 python教程 django教程8 Django部署(Apache)

    > 在前面的章节中我们使用**python3 manage.py runserver**来运行服务器。这只适用测试环境中使用。

    学习猿地
  • 学习猿地 python教程 django教程8 Django部署(Apache)

    > 在前面的章节中我们使用**python3 manage.py runserver**来运行服务器。这只适用测试环境中使用。

    学习猿地
  • 程序员基本素养和特质

    Allen.Wu
  • 盘点2014:10个词让你看懂今年的移动互联网

      2014年就要过去了,这一年,微商、众筹、O2O、自媒体、境外电商、互联网金融、P2P租车、大数据、移动支付、社会化营销等成为最大的移动互联网风口。   时...

    小莹莹
  • java操作redis: 将string、list、map、自定义的对象保存到redis中

    import java.util.HashMap; import java.util.List; import java.util.Map; import r...

    似水的流年

扫码关注云+社区

领取腾讯云代金券