自定义校验-ConstraintValidator

在编写rest接口的时候,通常须要对参数进行校验,常见的校验好比java

  • NotNull
  • NotBlank
  • Size
  • Min

等等,可是这些注解没法知足咱们的需求的时候,该怎么办呢?难道须要在业务代码中进行大量判断吗?非也!咱们能够自定义参数校验注解。web

普通的rest接口

  • 新建一个spring boot工程
package com.yefengyu.validate;  
  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
  
@SpringBootApplication  
public class ValidateDemoApplication {  
    public static void main(String[] args) {  
        SpringApplication.run(ValidateDemoApplication.class, args);  
    }  
}
  • 删除test文件夹(咱们只是测试一个小功能,无需那么多额外的东西)
  • pom文件内容为:主要删除多余的配置,留下下面四个依赖便可
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.yefengyu.validate</groupId>
    <artifactId>validate-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>validate-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
    </dependencies>
</project>
  • 建立一个实体
package com.yefengyu.validate;  
  
import lombok.Data;  
  
@Data  
public class Event {  
    private Long id;  
    private Integer type;  
}
  • 编写一个简单 rest 接口
package com.yefengyu.validate;  
  
import org.springframework.web.bind.annotation.PostMapping;  
import org.springframework.web.bind.annotation.RequestBody;  
import org.springframework.web.bind.annotation.RestController;  
  
@RestController  
public class TestController {  
  
    @PostMapping("/test")  
    public Event test(@RequestBody Event event) {  
        return event;  
    }  
}
  • 测试

image.png

如今一个简单的rest接口编写好了,咱们如今有了需求, type 只能传递 一、二、3 这三个数值,其它数值传递都视为无效,该怎么办?不能使用业务代码去判断,由于相似这种类型、状态的参数,能够填写的数值自己就很少,咱们能够经过自定义校验器来实现。

自定义校验器

首先定义一个注解spring

package com.yefengyu.validate;  
  
import javax.validation.Constraint;  
import javax.validation.Payload;  
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;  
  
@Target({ElementType.FIELD, ElementType.PARAMETER})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Constraint(validatedBy = IntegerEnumValidator.class)  
public @interface IntegerEnum {  
  
    String message() default "invalid number";  
  
    int[] values() default {};  
  
    Class<?>[] groups() default {};  
  
    Class<? extends Payload>[] payload() default {};  
  
}

上面代码很简单,可是多了以下这句:apache

@Constraint(validatedBy = IntegerEnumValidator.class)

其中 IntegerEnumValidator 类主要是为了校验 IntegerEnum 注解的,代码以下:api

package com.yefengyu.validate;

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

public class IntegerEnumValidator implements ConstraintValidator<IntegerEnum, Integer> {

    private IntegerEnum integerEnum;

    @Override
    public void initialize(IntegerEnum constraintAnnotation) {
        this.integerEnum = constraintAnnotation;
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }
        int[] values = integerEnum.values();
        if (values.length == 0) {
            return true;
        }
        for (int v : values) {
            if (value == v) {
                return true;
            }
        }
        return false;
    }
}

此时咱们有了自定义的 整型校验器,如今尝试一下:app

1.实体增长注解:maven

package com.yefengyu.validate;  
  
import lombok.Data;  
  
@Data  
public class Event {  
    private Long id;  
    @IntegerEnum(values = {1, 2, 3}, message = "类型错误")  
    private Integer type;  
}

主要是这句:ide

@IntegerEnum(values = {1, 2, 3}, message = "类型错误")

2.接口开启注解spring-boot

package com.yefengyu.validate;  
  
import org.springframework.web.bind.annotation.PostMapping;  
import org.springframework.web.bind.annotation.RequestBody;  
import org.springframework.web.bind.annotation.RestController;  
  
import javax.validation.Valid;  
  
@RestController  
public class TestController {  
  
    @PostMapping("/test")  
    public Event test(@Valid @RequestBody Event event) {  
        return event;  
    }  
}

主要是增长了 @Valid测试

3.测试

{
    "id" : 1,
    "type" : 11
}

当传入参数 type 不是 一、二、3 的时候,那么结果为:

{
    "timestamp": "2019-12-27T08:10:10.569+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "IntegerEnum.event.type",
                "IntegerEnum.type",
                "IntegerEnum.java.lang.Integer",
                "IntegerEnum"
            ],
            "arguments": [
                {
                    "codes": [
                        "event.type",
                        "type"
                    ],
                    "arguments": null,
                    "defaultMessage": "type",
                    "code": "type"
                },
                [
                    1,
                    2,
                    3
                ]
            ],
            "defaultMessage": "类型错误",
            "objectName": "event",
            "field": "type",
            "rejectedValue": 11,
            "bindingFailure": false,
            "code": "IntegerEnum"
        }
    ],
    "message": "Validation failed for object='event'. Error count: 1",
    "path": "/test"
}

咱们能够在代码中增长异常处理,简化、统一处理异常信息,这块优化不在本节内容之中。

相关文章
相关标签/搜索