spring validation实现对Restful请求的数据进行校验

spring validation实现对Restful请求的数据进行校验

转发:https://blog.csdn.net/steven2xupt/article/details/87452664

1、前言

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

2、常用校验

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

    <ul><li>@Null 被注释的元素必须为null</li>
    	<li>@NotNull 被注释的元素必须不为null</li>
    	<li>@AssertTrue 被注释的元素必须为true</li>
    	<li>@AssertFalse 被注释的元素必须为false</li>
    	<li>@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li>
    	<li>@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li>
    	<li>@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li>
    	<li>@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li>
    	<li>@Size(max, min) 被注释的元素的大小必须在指定的范围内</li>
    	<li>@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内</li>
    	<li>@Past 被注释的元素必须是一个过去的日期</li>
    	<li>@Future 被注释的元素必须是一个将来的日期</li>
    	<li>@Pattern(value) 被注释的元素必须符合指定的正则表达式</li>
    </ul></li>
    <li>
    <p>hibernate validation:hibernate validation是对这个规范的实现,并增加了一些其他校验注解,如@Email,@Length,@Range等等</p>
    
    <ul><li>@Email 被注释的元素必须是电子邮箱地址</li>
    	<li>@Length 被注释的字符串的大小必须在指定的范围内</li>
    	<li>@NotEmpty 被注释的字符串的必须非空</li>
    	<li>@Range 被注释的元素必须在合适的范围内</li>
    </ul></li>
    <li>spring validation:spring validation对hibernate validation进行了二次封装,在springmvc模块中添加了自动校验,并将校验信息封装进了特定的类中</li>
    

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

3.1 引入依赖

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


 
 
  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot </groupId>
  4. <artifactId>spring-boot-starter-web </artifactId>
  5. </dependency>
  6. </dependencies>

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


 
 
  1. <dependency>
  2. <groupId>org.hibernate </groupId>
  3. <artifactId>hibernate-validator </artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>com.fasterxml.jackson.core </groupId>
  7. <artifactId>jackson-databind </artifactId>
  8. </dependency>

3.2 构建启动类


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

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


 
 
  1. public class Person {
  2. @NotEmpty(message = "name不能为空")
  3. private String name;
  4. @Range(min = 0, max = 100, message = "age不能大于100小于0")
  5. private int age;
  6. public String getName() {
  7. return name;
  8. }
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public void setAge(int age) {
  16. this.age = age;
  17. }

3.4 在Controller中校验数据

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


 
 
  1. @RequestMapping("/test")
  2. public String valid( @Validated Person person, BindingResult bindingResult) {
  3. if (bindingResult.hasErrors()) {
  4. for (FieldError fieldError : bindingResult.getFieldErrors()) {
  5. System. out.println(fieldError);
  6. }
  7. return "fail";
  8. }
  9. return "success";
  10. }

值得注意的地方:

  1. 参数Persion前需要加上@Validated注解,表明需要spring对其进行校验,而校验的信息会存放到其后的BindingResult中。注意,必须相邻,如果有多个参数需要校验,形式可以如下。valid(@Validated Person person, BindingResult fooBindingResult ,@Validated Bar bar, BindingResult barBindingResult);即一个校验类对应一个校验结果。
  2. 校验结果会被自动填充,在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类:


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

统一异常处理类:


 
 
  1. @RestControllerAdvice
  2. public class BindExceptionHanlder {
  3. @ExceptionHandler(BindException. class)
  4. public String handleBindException(HttpServletRequest request, BindException exception) {
  5. List<FieldError> allErrors = exception.getFieldErrors();
  6. StringBuilder sb = new StringBuilder();
  7. for (FieldError errorMessage : allErrors) {
  8. sb.append(errorMessage.getField()).append( ": ").append(errorMessage.getDefaultMessage()).append( ", ");
  9. }
  10. System.out.println(sb.toString());
  11. return sb.toString();
  12. }
  13. }

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

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

4、自定义校验注解

4.1 @NameValidation


 
 
  1. @Documented
  2. @Constraint(validatedBy = NameValidationValidator.class)
  3. @Target({ElementType.METHOD, ElementType.FIELD})
  4. @Retention(RUNTIME)
  5. public @interface NameValidation {
  6. String message() default "不是合法的名字";
  7. Class<?>[] groups() default {};
  8. Class<? extends Payload>[] payload() default {};
  9. @Target({PARAMETER, ANNOTATION_TYPE})
  10. @Retention(RUNTIME)
  11. @Documented
  12. @interface List {
  13. NameValidation[] value();
  14. }
  15. }

4.2 校验类NameValidationValidator


 
 
  1. public class NameValidationValidator implements ConstraintValidator<NameValidation, String> {
  2. @Override
  3. public boolean isValid( String value, ConstraintValidatorContext context) {
  4. if ( "steven".equalsIgnoreCase(value)) {
  5. return true;
  6. }
  7. String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
  8. System.out.println( "default message :" + defaultConstraintMessageTemplate);
  9. //禁用默认提示信息
  10. //context.disableDefaultConstraintViolation();
  11. //设置提示语
  12. //context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
  13. return false;
  14. }
  15. }

4.3 在Person类增加新注解


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

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

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

spring validation实现对Restful请求的数据进行校验


1、前言

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

2、常用校验

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

    <ul><li>@Null 被注释的元素必须为null</li>
    	<li>@NotNull 被注释的元素必须不为null</li>
    	<li>@AssertTrue 被注释的元素必须为true</li>
    	<li>@AssertFalse 被注释的元素必须为false</li>
    	<li>@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li>
    	<li>@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li>
    	<li>@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li>
    	<li>@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li>
    	<li>@Size(max, min) 被注释的元素的大小必须在指定的范围内</li>
    	<li>@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内</li>
    	<li>@Past 被注释的元素必须是一个过去的日期</li>
    	<li>@Future 被注释的元素必须是一个将来的日期</li>
    	<li>@Pattern(value) 被注释的元素必须符合指定的正则表达式</li>
    </ul></li>
    <li>
    <p>hibernate validation:hibernate validation是对这个规范的实现,并增加了一些其他校验注解,如@Email,@Length,@Range等等</p>
    
    <ul><li>@Email 被注释的元素必须是电子邮箱地址</li>
    	<li>@Length 被注释的字符串的大小必须在指定的范围内</li>
    	<li>@NotEmpty 被注释的字符串的必须非空</li>
    	<li>@Range 被注释的元素必须在合适的范围内</li>
    </ul></li>
    <li>spring validation:spring validation对hibernate validation进行了二次封装,在springmvc模块中添加了自动校验,并将校验信息封装进了特定的类中</li>
    

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

3.1 引入依赖

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


 
 
  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot </groupId>
  4. <artifactId>spring-boot-starter-web </artifactId>
  5. </dependency>
  6. </dependencies>

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


 
 
  1. <dependency>
  2. <groupId>org.hibernate </groupId>
  3. <artifactId>hibernate-validator </artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>com.fasterxml.jackson.core </groupId>
  7. <artifactId>jackson-databind </artifactId>
  8. </dependency>

3.2 构建启动类


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

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


 
 
  1. public class Person {
  2. @NotEmpty(message = "name不能为空")
  3. private String name;
  4. @Range(min = 0, max = 100, message = "age不能大于100小于0")
  5. private int age;
  6. public String getName() {
  7. return name;
  8. }
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public void setAge(int age) {
  16. this.age = age;
  17. }

3.4 在Controller中校验数据

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


 
 
  1. @RequestMapping("/test")
  2. public String valid( @Validated Person person, BindingResult bindingResult) {
  3. if (bindingResult.hasErrors()) {
  4. for (FieldError fieldError : bindingResult.getFieldErrors()) {
  5. System. out.println(fieldError);
  6. }
  7. return "fail";
  8. }
  9. return "success";
  10. }

值得注意的地方:

  1. 参数Persion前需要加上@Validated注解,表明需要spring对其进行校验,而校验的信息会存放到其后的BindingResult中。注意,必须相邻,如果有多个参数需要校验,形式可以如下。valid(@Validated Person person, BindingResult fooBindingResult ,@Validated Bar bar, BindingResult barBindingResult);即一个校验类对应一个校验结果。
  2. 校验结果会被自动填充,在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类:


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

统一异常处理类:


 
 
  1. @RestControllerAdvice
  2. public class BindExceptionHanlder {
  3. @ExceptionHandler(BindException. class)
  4. public String handleBindException(HttpServletRequest request, BindException exception) {
  5. List<FieldError> allErrors = exception.getFieldErrors();
  6. StringBuilder sb = new StringBuilder();
  7. for (FieldError errorMessage : allErrors) {
  8. sb.append(errorMessage.getField()).append( ": ").append(errorMessage.getDefaultMessage()).append( ", ");
  9. }
  10. System.out.println(sb.toString());
  11. return sb.toString();
  12. }
  13. }

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

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

4、自定义校验注解

4.1 @NameValidation


 
 
  1. @Documented
  2. @Constraint(validatedBy = NameValidationValidator.class)
  3. @Target({ElementType.METHOD, ElementType.FIELD})
  4. @Retention(RUNTIME)
  5. public @interface NameValidation {
  6. String message() default "不是合法的名字";
  7. Class<?>[] groups() default {};
  8. Class<? extends Payload>[] payload() default {};
  9. @Target({PARAMETER, ANNOTATION_TYPE})
  10. @Retention(RUNTIME)
  11. @Documented
  12. @interface List {
  13. NameValidation[] value();
  14. }
  15. }

4.2 校验类NameValidationValidator


 
 
  1. public class NameValidationValidator implements ConstraintValidator<NameValidation, String> {
  2. @Override
  3. public boolean isValid( String value, ConstraintValidatorContext context) {
  4. if ( "steven".equalsIgnoreCase(value)) {
  5. return true;
  6. }
  7. String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
  8. System.out.println( "default message :" + defaultConstraintMessageTemplate);
  9. //禁用默认提示信息
  10. //context.disableDefaultConstraintViolation();
  11. //设置提示语
  12. //context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
  13. return false;
  14. }
  15. }

4.3 在Person类增加新注解


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

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

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值