java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot集成validation参数校验

Spring Boot集成validation实现参数校验功能

作者:HBLOGA

Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回,这篇文章主要介绍了Spring Boot集成validation实现参数校验功能,需要的朋友可以参考下

1.什么是Bean Validation?

Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。java 在2009年的 JAVAEE 6 中发布了 JSR303以及javax下的validation包内容。这项工作的主要目标是为java应用程序开发人员提供 基于java对象的 约束(constraints)声明 和 对约束的验证工具(validator),以及约束元数据存储库和查询API。但是该内容并没有具体的实现, Hibernate-Validator框架 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。

常用的Validation注解

一些最常见的验证注解如下:

2.代码工程

实验目标:校验controller传递的参数

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>validtion</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
        </dependency>
    </dependencies>
</project>

controller

Spring 自动将传入的 JSON 映射到 Java 对象参数上。 现在,我们要校验传入的 Java 对象是否满足我们预先定义的约束条件。 为了校验传入 HTTP 请求的请求实体,我们在 REST 控制器中使用 @Valid 注解对请求实体进行标记:

package com.et.validation.controller;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.et.validation.entity.UserInfoReq;
import com.fasterxml.jackson.databind.util.JSONPObject;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HelloWorldController {
    @RequestMapping("/hello")
    public Map<String, Object> showHelloWorld(@RequestBody @Validated UserInfoReq req){
        Map<String, Object> map = new HashMap<>();
        map.put("msg", JSONUtil.toJsonStr(req));
        return map;
    }
}

enttiy

我们有一个 int类型 字段,它的值必须介于 1 和 10200之间,如@Min@Max 注解所定义的那样。 我们还有一个 String 类型字段,它必须是一个 IP 地址,正如@Pattern 注解中的正则表达式所定义的那样(正则表达式实际上仍然允许大于 255 的无效 IP 地址,但在我们创建自定义验证器时,我们将在本教程的后面修复这个BUG)。

package com.et.validation.entity;
import com.et.validation.validate.IpAddress;
import lombok.Data;
import lombok.ToString;
import javax.validation.constraints.*;
@Data
@ToString
public class UserInfoReq {
    @NotNull(message = "id不能为null")
    private Long id;
    @NotBlank(message = "username不能为空")
    private String username;
    @NotNull(message = "age不能为null")
    @Min(value = 1, message = "年龄不符合要求")
    @Max(value = 200, message = "年龄不符合要求")
    private Integer age;
    @Email(message = "邮箱不符合规范")
    private String email;
    @IpAddress(message = "ip不符合规范")
    //@Pattern(regexp = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$") 
    private String ip;
}

自定义error捕获

当校验失败时,我们通常希望向客户端返回一条有意义的错误消息。 为了使客户端能够显示有用的错误消息,我们应该返回一个统一的数据结构,其中包含每个校验失败的错误消息。 我们在这里所做的只是从异常中读取有关校验失败信息并将它们转换到我们的 ValidationErrorResponse 数据结构中。 请注意@ControllerAdvice 注解,它使得上述类型异常的异常处理机制对所有Controller全局可用。

package com.et.validation.error;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
@ControllerAdvice
class ErrorHandlingControllerAdvice {
  @ExceptionHandler(ConstraintViolationException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ResponseBody
  ValidationErrorResponse onConstraintValidationException(
      ConstraintViolationException e) {
    ValidationErrorResponse error = new ValidationErrorResponse();
    for (ConstraintViolation violation : e.getConstraintViolations()) {
      error.getViolations().add(
        new Violation(violation.getPropertyPath().toString(), violation.getMessage()));
    }
    return error;
  }
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ResponseBody
  ValidationErrorResponse onMethodArgumentNotValidException(
      MethodArgumentNotValidException e) {
    ValidationErrorResponse error = new ValidationErrorResponse();
    for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
      error.getViolations().add(
        new Violation(fieldError.getField(), fieldError.getDefaultMessage()));
    }
    return error;
  }
}
package com.et.validation.error;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Data
public class ValidationErrorResponse implements Serializable {
  private List<Violation> violations = new ArrayList<>();
}
package com.et.validation.error;
import lombok.Data;
import java.io.Serializable;
@Data
public class Violation implements Serializable {
  private final String fieldName;
  private final String message;
  public Violation(String fieldName, String message) {
    this.fieldName = fieldName;
    this.message = message;
  }
}

自定义validator

如果官方提供可用的校验注解不能满足我们的需要,我们自己可以定义一个自定义校验器。 自定义校验注解需要包含以下要素:

校验器的实现如下所示:

package com.et.validation.validate;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({ FIELD })
@Retention(RUNTIME)
@Constraint(validatedBy = IpAddressValidator.class)
@Documented
public @interface IpAddress {
  String message() default "{IpAddress.invalid}";
  Class<?>[] groups() default { };
  Class<? extends Payload>[] payload() default { };
}
package com.et.validation.validate;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class IpAddressValidator implements ConstraintValidator<IpAddress, String> {
  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    Pattern pattern =
      Pattern.compile("^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$");
    Matcher matcher = pattern.matcher(value);
    try {
      if (!matcher.matches()) {
        return false;
      } else {
        for (int i = 1; i <= 4; i++) {
          int octet = Integer.valueOf(matcher.group(i));
          if (octet > 255) {
            return false;
          }
        }
        return true;
      }
    } catch (Exception e) {
      return false;
    }
  }
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

3.测试

启动spring boot应用

测试参数校验接口

访问http://127.0.0.1:8088/hello,返回结果如下

4.引用

到此这篇关于Spring Boot集成validation实现参数校验功能的文章就介绍到这了,更多相关Spring Boot集成validation参数校验内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文