自定義校驗-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"
}

咱們能夠在代碼中增長異常處理,簡化、統一處理異常信息,這塊優化不在本節內容之中。

相關文章
相關標籤/搜索