SpringBoot利用validation实现优雅的校验参数

目录
  • 1、前言
  • 2、常用校验
  • 3、spring boot的数据自动校验功能
    • 3.1 引入依赖
    • 3.2 构建启动类
    • 3.3 创建需要被校验的实体类
    • 3.4 在Controller中校验数据
    • 3.5 统一异常处理
  • 4、自定义校验注解
    • 4.1 @NameValidation
    • 4.2 校验类NameValidationValidator
    • 4.3 在Person类增加新注解
  • 5、总结

1、前言

数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已。可以使用本文将要介绍的validation来对数据进行校验。

2、常用校验

1.JSR303/JSR-349: JSR303是一项标准,只提供规范不提供实现,规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,位于javax.validation.constraints包下。JSR-349是其的升级版本,添加了一些新特性。

  • @Null 被注释的元素必须为null
  • @NotNull 被注释的元素必须不为null
  • @AssertTrue 被注释的元素必须为true
  • @AssertFalse 被注释的元素必须为false
  • @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Size(max, min) 被注释的元素的大小必须在指定的范围内
  • @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
  • @Past 被注释的元素必须是一个过去的日期
  • @Future 被注释的元素必须是一个将来的日期
  • @Pattern(value) 被注释的元素必须符合指定的正则表达式

2.hibernate validation:hibernate validation是对这个规范的实现,并增加了一些其他校验注解,如@Email,@Length,@Range等等

  • @Email 被注释的元素必须是电子邮箱地址
  • @Length 被注释的字符串的大小必须在指定的范围内
  • @NotEmpty 被注释的字符串的必须非空
  • @Range 被注释的元素必须在合适的范围内

3.spring validation:spring validation对hibernate validation进行了二次封装,在springmvc模块中添加了自动校验,并将校验信息封装进了特定的类中

3、spring boot的数据自动校验功能

3.1 引入依赖

spring-web模块使用了hibernate-validation,并且databind模块也提供了相应的数据绑定功能。

<dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

我们只需要引入spring-boot-starter-web依赖即可,如果查看其子依赖,可以发现如下的依赖:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

3.2 构建启动类

@SpringBootApplication
public class App {
   public static void main(String[] args) {
       SpringApplication.run(App.class, args);
       System.out.println("Start app success.");
   }
}

3.3 创建需要被校验的实体类

public class Person {
    @NotEmpty(message = "name不能为空")
    private String name;
    @Range(min = 0, max = 100, message = "age不能大于100小于0")
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3.4 在Controller中校验数据

springmvc为我们提供了自动封装表单参数的功能,一个添加了参数校验的典型controller如下所示。

@RequestMapping("/test")
public String valid(@Validated Person person, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            System.out.println(fieldError);
        }
        return "fail";
    }
    return "success";
}

值得注意的地方:

  • 参数Persison前需要加上@Validated注解,表明需要spring对其进行校验,而校验的信息会存放到其后的BindingResult中。注意,必须相邻,如果有多个参数需要校验,形式可以如下。valid(@Validated Person person, BindingResult personBindingResult ,@Validated Person2 person2, BindingResult person2BindingResult);即一个校验类对应一个校验结果。
  • 校验结果会被自动填充,在controller中可以根据业务逻辑来决定具体的操作,如跳转到错误页面。

一个最基本的校验就完成了.

启动容器测试结果如下:

Field error in object 'person' on field 'age': rejected value [105]; codes [Range.person.age,Range.age,Range.int,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.age,age]; arguments []; default message [age],100,0]; default message [age不能大于100小于0]

3.5 统一异常处理

前面那种方式处理校验错误,略显复杂,而且一般网站都会对请求错误做统一的404页面封装,如果数据校验不通过,则Spring boot会抛出BindException异常,我们可以捕获这个异常并使用Result封装返回结果。通过@RestControllerAdvice定义异常捕获类。

Controller类:

@RequestMapping(value = "valid", method = RequestMethod.GET)
public String valid(@Validated Person person) {
    System.out.println(person);
    return "success";
}

统一异常处理类:

@RestControllerAdvice
public class BindExceptionHanlder {
    @ExceptionHandler(BindException.class)
    public String handleBindException(HttpServletRequest request, BindException exception) {
        List<FieldError> allErrors = exception.getFieldErrors();
        StringBuilder sb = new StringBuilder();
        for (FieldError errorMessage : allErrors) {
            sb.append(errorMessage.getField()).append(": ").append(errorMessage.getDefaultMessage()).append(", ");
        }
        System.out.println(sb.toString());
        return sb.toString();
    }
}

测试: http://localhost:8080/valid?age=105&name=steven

输出:age: age不能大于100小于0,

4、自定义校验注解

4.1 @NameValidation

@Documented
@Constraint(validatedBy = NameValidationValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RUNTIME)
public @interface NameValidation {
    String message() default "不是合法的名字";

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

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

    @Target({PARAMETER, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        NameValidation[] value();
    }
}

4.2 校验类NameValidationValidator

public class NameValidationValidator implements ConstraintValidator<NameValidation, String> {
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if ("steven".equalsIgnoreCase(value)) {
            return true;
        }
        String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
        System.out.println("default message :" + defaultConstraintMessageTemplate);
        //禁用默认提示信息
		//context.disableDefaultConstraintViolation();
        //设置提示语
		//context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
        return false;
    }
}

4.3 在Person类增加新注解

@NotEmpty(message = "name不能为空")
@NameValidation
private String name;

测试: http://localhost:8080/valid?age=105&name=lxy

输出:age: age不能大于100小于0, name: 不是合法的名字,

5、总结

通过上面的例子可以看出,其实使用很简单,但是有没有注意到一个问题,错误信息没有实现国际化。hibernate-validator国际化还是比较繁琐的,包含:

  • SpringBoot场景国际化
  • SpringMvc场景国际化
  • Spring Jersey场景国际化
  • 非Spring场景国际化

以上就是SpringBoot利用validation实现优雅的校验参数的详细内容,更多关于SpringBoot validation校验参数的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot集成Validation参数校验

    本文实例为大家分享了SpringBoot集成Validation参数校验的具体代码,供大家参考,具体内容如下 1.依赖 SpringBoot在web启动器中已经包含validator包 <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId> </dependency>

  • springboot使用hibernate validation对参数校验的实现方法

    springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验,不仅难看,使用起来还很不方便: if(StringUtils.isEmpty(userName)){ throw new RuntimeException("用户名不能为空"); } 下面将介绍hibernate validation的基本使用方法. 一.引入依赖 这里在springboot 2.4.1中进行实验,引入以下依赖: <pare

  • SpringBoot使用validation做参数校验的实现步骤

    1.添加依赖 直接添加 hibernate-validator <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.2.Final</version> </dependency> 添加spring-boot-starter-validat

  • SpringBoot + validation 接口参数校验的思路详解

    有参数传递的地方都少不了参数校验.在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全.试想一下,如果在controller层中没有经过任何校验的参数通过service层.dao层一路来到了数据库就可能导致严重的后果,最好的结果是查不出数据,严重一点就是报错,如果这些没有被校验的参数中包含了恶意代码,那就可能导致更严重的后果. 实践 一.引入依赖 <!--引入spring-boot-starter-validation--> <dependency> <gr

  • SpringBoot 中使用 Validation 校验参数的方法详解

    目录 1. Validation 介绍 1.1 Validation 注解 1.2 @valid 和 @validated的区别 2. SpringBoot 中使用 Validator 校验参数 2.1 依赖引入 2.2 标注校验实体类 2.3 开启参数校验 2.3.1 简单参数校验 2.3.2 JavaBean 校验 2.4 捕捉参数校验异常 项目中写逻辑时,为保证程序的健壮性,需要对各种参数进行判断,这就导致业务代码不只健壮,还十分臃肿.其实 SpringBoot 中已经提供了 Valida

  • SpringBoot使用validation做参数校验说明

    目录 1.添加依赖 直接添加 hibernate-validator 添加spring-boot-starter-validation 添加spring-boot-starter-web 2. 配置文件 3.统一异常处理 4.使用 1.添加依赖 直接添加 hibernate-validator <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-valid

  • SpringBoot利用validation实现优雅的校验参数

    目录 1.前言 2.常用校验 3.spring boot的数据自动校验功能 3.1 引入依赖 3.2 构建启动类 3.3 创建需要被校验的实体类 3.4 在Controller中校验数据 3.5 统一异常处理 4.自定义校验注解 4.1 @NameValidation 4.2 校验类NameValidationValidator 4.3 在Person类增加新注解 5.总结 1.前言 数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱

  • 如何使用Spring Validation优雅地校验参数

    引言 不知道大家平时的业务开发过程中 controller 层的参数校验都是怎么写的?是否也存在下面这样的直接判断? public String add(UserVO userVO) { if(userVO.getAge() == null){ return "年龄不能为空"; } if(userVO.getAge() > 120){ return "年龄不能超过120"; } if(userVO.getName().isEmpty()){ return &q

  • springboot+dubbo+validation 进行rpc参数校验的实现方法

    注意:本文dubbo 版本 2.8.4 springboot 版本 2.0.4.RELEASE 项目结构 test-rest (前端消费着,controller 层,springboot+maven项目) test-api (dubbo服务 的 api ,只记录 service 接口和 model ,maven 项目) test-provider(dubbo 服务提供者,实际的数据库操作及业务层, springboot+maven项目 ) 背景: 使用springmvc做restful,使用du

  • SpringBoot如何优雅的处理校验参数的方法

    前言 做web开发有一点很烦人就是要校验参数,基本上每个接口都要对参数进行校验,比如一些格式校验 非空校验都是必不可少的.如果参数比较少的话还是容易 处理的一但参数比较多了的话代码中就会出现大量的IF ELSE就比如下面这样: 这个例子只是校验了一下空参数.如果需要验证邮箱格式和手机号格式校验的话代码会更多,所以介绍一下validator通过注解的方式进行校验参数. 什么是Validator Bean Validation是Java定义的一套基于注解的数据校验规范,目前已经从JSR 303的1.

  • SpringBoot集成validation校验参数遇到的坑

    公众号中分享了一篇文章,关于SpringBoot集成validation校验参数的,粉丝留言说有坑. 原留言如下: 有坑,你试试^A-\\d{12}-\\d{4}$,这条正则经过validate这个方法无论参数写的对不对都会报验证错误,而用main方法测试是正常的.. 话说,针对这种回复我是不太信了,直觉告诉我,肯定是这位粉丝用错了.但既然粉丝有疑问还是需要专门写一个demo来验证一下的.说写就写. SpringBoot集成validation 集成过程非常简单,在原项目的pom文件中直接引入如

  • Spring/Spring Boot 中优雅地做参数校验拒绝 if/else 参数校验

    数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据. 最普通的做法就像下面这样.我们通过 if/else 语句对请求的每一个参数一一校验. @RestController @RequestMapping("/api/person") public class PersonController { @PostMapping public ResponseEnti

随机推荐