사용자 정의 검사 주석 ConstraintValidator

머리말
시스템 이 업무 논 리 를 실행 하기 전에 입력 데 이 터 를 검증 하여 데이터 가 유효 하고 합 법 적 인지 확인 합 니 다.그래서 우 리 는 대량의 if else 등 판단 논 리 를 쓸 수 있 습 니 다.특히 서로 다른 방법 으로 같은 데 이 터 를 나 타 낼 때 검 증 된 논리 코드 가 반복 되 어 코드 가 지루 하고 읽 기 성과 유지 가능성 이 매우 떨 어 집 니 다.
JSR-303 은 자바 가 Bean 데이터 의 합 법성 검사 에 제공 하 는 표준 프레임 워 크 로 전체 검사 주 해 를 정의 하여 구성원 변수,속성 방법 등에 표시 할 수 있 습 니 다.
hibenate-vaidator 는 이 표준 의 실현 을 제공 합 니 다.우 리 는 Springboot 로 웹 애플 리 케 이 션 을 개발 할 때 spring-boot-starter-web 의존 도 를 도입 합 니 다.기본적으로 spring-boot-starter-vaidation 의존 도 를 도입 합 니 다.spring-boot-starter-vaidation 에 서 는 hibenate-vaidator 의존 도 를 참조 합 니 다.

그러나 비교적 높 은 버 전의 spring-boot-starter-web 에 서 는 기본적으로 spring-boot-starter-vaidation 을 인용 하지 않 습 니 다.당연히 hibenate-vaidator 의존 에 기본적으로 도입 되 지 않 습 니 다.수 동 으로 의존 을 추가 해 야 합 니 다.

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.7.Final</version>
</dependency>
hibenate-vaidator 에는 NotNull,@NotEmpty,@Min,@Max,@Email,@PositiveOrZero 등 매우 간단 하고 사용 하기 좋 은 검사 주석 이 많 습 니 다.이 주석 들 은 우리 의 대부분의 데이터 검사 문 제 를 해결 할 수 있다.다음 과 같다.

package com.nobody.dto;

import lombok.Data;

import javax.validation.constraints.*;

@Data
public class UserDTO {

    @NotBlank(message = "      ")
    private String name;

    @Min(value = 18, message = "      18")
    private int age;

	@NotEmpty(message = "      ")
    @Email(message = "       ")
    private String email;
}
2.사용자 정의 매개 변수 검사 기
그러나 hibenate-vaidator 의 이러한 주 해 는 반드시 우리 의 모든 수 요 를 만족 시 킬 수 있 는 것 이 아니 라 우리 가 검증 하고 자 하 는 논 리 는 이것 보다 복잡 하 다.따라서 우 리 는 자신의 매개 변수 검사 기 를 사용자 정의 할 수 있다.
우선 의존 을 끌 어 들 이 는 것 은 필수 적 이다.

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.7.Final</version>
</dependency>
요즘 펀드 가 뜨 잖 아 요.부추 가 펀드 를 사 는 물결 에 미 친 듯 이 몰 려 들 고 있어 요.저 는 사용자 가 계 좌 를 개설 하 는 것 을 예 로 들 면 먼저 이 사용자 가 성인(즉 18 세 이하 가 되 어 서 는 안 된다)인지,그리고 이름 이'새 부추'로 시작 하 는 지,조건 에 부합 되 어야 계 좌 를 개설 할 수 있 는 지 확인 해 야 합 니 다.
사용자 의 이름 이'새 부추'로 시작 되 었 는 지 확인 하기 위해 주 해 를 정의 합 니 다.

package com.nobody.annotation;

import com.nobody.validator.IsLeekValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@Constraint(validatedBy = IsLeekValidator.class) //            
public @interface IsLeek {

    /**
     *       
     * 
     * @return        boolean 
     */
    boolean required() default true;

    /**
     *            
     * 
     * @return            
     */
    String message() default "        ,    !";

    /**
     *  validator    ,    group       validator  
     * 
     * @return validator     
     */
    Class<?>[] groups() default {};

    /**
     *      bean,    
     * 
     * @return   
     */
    Class<? extends Payload>[] payload() default {};

}
검사 클래스 를 정의 하고 ConstraintValidator 인 터 페 이 스 를 실현 합 니 다.인 터 페 이 스 는 범 형 을 사 용 했 습 니 다.두 개의 인 자 를 지정 해 야 합 니 다.첫 번 째 는 사용자 정의 주석 이 고 두 번 째 는 검사 해 야 할 데이터 형식 입 니 다.두 가지 방법 을 다시 쓰 십시오.initialize 방법 은 주로 초기 화 작업 을 합 니 다.그 매개 변 수 는 우리 가 사용 하 는 주해 입 니 다.실행 할 때의 주해 정 보 를 얻 을 수 있 습 니 다.isValid 방법 은 검증 논 리 를 실현 하 는 것 입 니 다.주 해 된 대상 은 이 방법 에 전 달 됩 니 다.

package com.nobody.validator;

import com.nobody.annotation.IsLeek;
import org.springframework.util.StringUtils;

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

public class IsLeekValidator implements ConstraintValidator<IsLeek, String> {

    //       
    private boolean required;

    @Override
    public void initialize(IsLeek constraintAnnotation) {
        this.required = constraintAnnotation.required();
    }

    @Override
    public boolean isValid(String name, ConstraintValidatorContext constraintValidatorContext) {
        if (required) {
            //    "   "        
            return !StringUtils.isEmpty(name) && name.startsWith("   ");
        }
        return false;
    }
}
3.사용자 정의 주석 사용
상기 몇 가지 절 차 를 통 해 사용자 정의 검사 주 해 를 완성 하 였 습 니 다.우 리 는 테스트 효 과 를 사용 합 니 다.

package com.nobody.dto;

import com.nobody.annotation.IsLeek;
import lombok.Data;

import javax.validation.constraints.*;

@Data
public class UserDTO {

    @NotBlank(message = "      ")
    @IsLeek //         
    private String name;

    @Min(value = 18, message = "      18")
    private int age;

    @NotEmpty(message = "      ")
    @Email(message = "       ")
    private String email;
}
인 터 페 이 스 를 써 서 사용자 의 계좌 개설 업 무 를 모 의 하고 테스트 를 호출 합 니 다.주의 하 세 요.@Valid 주 해 를 더 해서 검 사 를 시작 하 세 요.그렇지 않 으 면 유효 하지 않 습 니 다.

package com.nobody.controller;

import com.nobody.dto.UserDTO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
@RequestMapping("user")
public class UserController {

    @PostMapping("add")
    public UserDTO add(@RequestBody @Valid UserDTO userDTO) {
        System.out.println(">>>       ...");
        return userDTO;
    }

}
매개 변수 검사 가 통과 되 지 않 으 면 MethodArgument NotValid Exception 이상 을 던 져 서 전체 적 으로 처리 한 다음 인터페이스 에 되 돌려 줍 니 다.

package com.nobody.exception;

import javax.servlet.http.HttpServletRequest;

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 lombok.extern.slf4j.Slf4j;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    //               
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Object errorHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
        return e.getBindingResult().getAllErrors();
    }
}
우 리 는 먼저 사용자 의 이름 이'새 부추'접 두 사 를 가지 고 있 지 않 은 것 을 테스트 하고 검사 가 통과 되 지 않 은 것 을 발견 하여 주해 가 효력 이 발생 했다 는 것 을 증명 합 니 다.
POST http://localhost:8080/user/add
Content-Type: application/json
{"name":"초록","age":19,"email":"[email protected]"}

[
  {
    "codes": [
      "IsLeek.userDTO.name",
      "IsLeek.name",
      "IsLeek.java.lang.String",
      "IsLeek"
    ],
    "arguments": [
      {
        "codes": [
          "userDTO.name",
          "name"
        ],
        "arguments": null,
        "defaultMessage": "name",
        "code": "name"
      },
      true
    ],
    "defaultMessage": "        ,    !",
    "objectName": "userDTO",
    "field": "name",
    "rejectedValue": "  ",
    "bindingFailure": false,
    "code": "IsLeek"
  }
여러 매개 변수 검사 에 실패 하면 오류 보고 정보 도 얻 을 수 있 습 니 다.아래 와 같이 이름과 메 일 을 모두 검사 하 는 데 실 패 했 습 니 다.
POST http://localhost:8080/user/add
Content-Type: application/json
{"name":"초록","age":19,"email":"84513654"}

[
  {
    "codes": [
      "Email.userDTO.email",
      "Email.email",
      "Email.java.lang.String",
      "Email"
    ],
    "arguments": [
      {
        "codes": [
          "userDTO.email",
          "email"
        ],
        "arguments": null,
        "defaultMessage": "email",
        "code": "email"
      },
      [],
      {
        "defaultMessage": ".*",
        "codes": [
          ".*"
        ],
        "arguments": null
      }
    ],
    "defaultMessage": "       ",
    "objectName": "userDTO",
    "field": "email",
    "rejectedValue": "84513654",
    "bindingFailure": false,
    "code": "Email"
  },
  {
    "codes": [
      "IsLeek.userDTO.name",
      "IsLeek.name",
      "IsLeek.java.lang.String",
      "IsLeek"
    ],
    "arguments": [
      {
        "codes": [
          "userDTO.name",
          "name"
        ],
        "arguments": null,
        "defaultMessage": "name",
        "code": "name"
      },
      true
    ],
    "defaultMessage": "        ,    !",
    "objectName": "userDTO",
    "field": "name",
    "rejectedValue": "  ",
    "bindingFailure": false,
    "code": "IsLeek"
  }
]
다음은 모든 매개 변수 검사 가 통 과 된 상황 입 니 다.
POST http://localhost:8080/user/add
Content-Type: application/json
{"name":"새 부추 초록","age":19,"email":"[email protected]"}
{
  "새 부추 초록
  "age": 19,
  "email": "[email protected]"
}
저 희 는 UserDTO 대상 을 다른 인터페이스 에서 인 자 를 받 을 수 있 습 니 다.예 를 들 어 인 터 페 이 스 를 새로 추가 하고 수정 하 는 것 입 니 다.새로 추 가 된 인터페이스 에서 userId 를 검사 할 필요 가 없습니다.수정 인터페이스 에서 userId 를 검사 해 야 합 니 다.그럼 주해 에 있 는 groups 필드 가 도움 이 됩 니 다.groups 와@Validated 가 어떤 주 해 를 제어 할 수 있 는 지 확인 할 필요 가 없습니다.
우 리 는 먼저 2 개의 groups 그룹 인터페이스 Update 와 Create 를 정의 하고 Default 인 터 페 이 스 를 계승 합 니 다.물론 Default 인 터 페 이 스 를 계승 하지 않 아 도 됩 니 다.주 해 를 사용 할 때 지정 한 groups 의 값 을 표시 하지 않 으 면 기본적으로 groups={Default.class}입 니 다.그래서 Default 인 터 페 이 스 를 계 승 했 습 니 다.@Validated(Create.class)를 사용 할 때 groups={Default.class}의 주 해 를 검사 합 니 다.

package com.nobody.annotation;

import javax.validation.groups.Default;

public interface Create extends Default {
}

package com.nobody.annotation;

import javax.validation.groups.Default;

public interface Update extends Default {
}
주 해 를 사용 하 는 곳 에 groups 의 값 을 입력 하 십시오.

package com.nobody.dto;

import com.nobody.annotation.Create;
import com.nobody.annotation.IsLeek;
import com.nobody.annotation.Update;
import lombok.Data;

import javax.validation.constraints.*;

@Data
public class UserDTO {

    @NotBlank(message = "  ID    ", groups = Update.class)
    private String userId;

    @NotBlank(message = "      ", groups = {Update.class, Create.class})
    @IsLeek
    private String name;

    @Min(value = 18, message = "      18")
    private int age;

    @NotEmpty(message = "      ")
    @Email(message = "       ")
    private String email;
}
마지막 으로 인증 이 필요 한 곳 에 서 는@Validated 의 지정 을 통 해 확인 할 수 있 습 니 다.

package com.nobody.controller;

import com.nobody.annotation.Create;
import com.nobody.annotation.Update;
import com.nobody.dto.UserDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("user")
public class UserController {

    @PostMapping("add")
    public Object add(@RequestBody @Validated(Create.class) UserDTO userDTO) {
        System.out.println(">>>       ...");
        return userDTO;
    }

    @PostMapping("update")
    public Object update(@RequestBody @Validated(Update.class) UserDTO userDTO) {
        System.out.println(">>>         ...");
        return userDTO;
    }

}
add 인 터 페 이 스 를 호출 할 때 userId 를 전달 하지 않 아 도 통과 할 수 있 습 니 다.즉,userId 를 검사 하지 않 습 니 다.
POST http://localhost:8080/user/add
Content-Type: application/json
{"name":"새 부추 초록","age":18,"email":"[email protected]"}
update 인 터 페 이 스 를 호출 할 때 userId 를 전송 하지 않 으 면 검사 가 통과 되 지 않 습 니 다.
POST http://localhost:8080/user/update
Content-Type: application/json
{"name":"새 부추 초록","age":18,"email":"[email protected]"}

[
  {
    "codes": [
      "NotBlank.userDTO.userId",
      "NotBlank.userId",
      "NotBlank.java.lang.String",
      "NotBlank"
    ],
    "arguments": [
      {
        "codes": [
          "userDTO.userId",
          "userId"
        ],
        "arguments": null,
        "defaultMessage": "userId",
        "code": "userId"
      }
    ],
    "defaultMessage": "  ID    ",
    "objectName": "userDTO",
    "field": "userId",
    "rejectedValue": null,
    "bindingFailure": false,
    "code": "NotBlank"
  }
]
이 프레젠테이션 항목 은 Github 에 업로드 되 었 습 니 다.필요 하 다 면 직접 다운로드 할 수 있 습 니 다.스타 를 환영 합 니 다https://github.com/LucioChn/spring
이상 은 사용자 정의 검증 주석 ConstraintValidator 의 상세 한 내용 입 니 다.사용자 정의 검증 주석 ConstraintValidator 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기