vaidate 주 해 를 검사 합 니 다.

15413 단어 자바springboot
머리말
이전에 도 hibenate 의 검증 주 해 를 사용 한 적 이 있 지만 정 리 를 하지 않 았 습 니 다.여기 서 블 로 그 를 참고 하여 정 리 를 하 겠 습 니 다.JSR 303/JSR-349,hibenate vaidation,spring vaidation 간 의 관 계 를 약술 합 니 다.JSR 303 은 표준 입 니 다.JSR-349 는 업그레이드 버 전 입 니 다.새로운 기능 을 추 가 했 습 니 다.그들 은 일부 검증 규범 즉 검증 주 해 를 규정 합 니 다.예 를 들 어@Null,@NotNull,@Pattern 은 자바 x.vaidation.constraints 가방 에 있 고 규범 만 제공 하고 실현 되 지 않 습 니 다.한편,hibenate vaidation 은 이 규범 에 대한 실천(hibenate 와 데이터베이스 orm 프레임 워 크 를 연결 하지 마 십시오)입 니 다.그 는 해당 하 는 실현 을 제공 하고 다른 검증 주 해 를 추 가 했 습 니 다.예 를 들 어@Email,@Length,@Range 등 은 org.hibenate.vaidator.constraints 가방 에 있 습 니 다.한편,만능 spring 은 개발 자 에 게 편리 함 을 제공 하기 위해 hibenate vaidation 을 2 차 로 패 키 징 했 습 니 다.검증 vaidated bean 을 표시 할 때 spring vaidation 이나 hibenate vaidation 을 사용 할 수 있 습 니 다.spring vaidation 의 또 다른 기능 은 springmvc 모델 에 자동 검증 을 추가 하고 검증 정 보 를 특정한 클래스 에 패키지 하 는 것 입 니 다.이것 은 의심 할 여지없이 우리 의 웹 개발 을 편리 하 게 했다.본 고 는 주로 springmvc 에서 자동 으로 검사 하 는 메커니즘 을 소개 한다.
도입 의존
우리 가 구축 한 것 은 spring boot 프로젝트 이기 때문에 웹 의 starter 의존 도 를 직접 도입 하면 됩 니 다.

    
        org.springframework.boot
        spring-boot-starter-web
    


자식 의존 도 를 보면 다음 과 같은 의존 도 를 발견 할 수 있 습 니 다.

    org.hibernate
    hibernate-validator


    com.fasterxml.jackson.core
    jackson-databind


검사 하 다
검 증 된 실체 클래스
여기에 lombok 의@Data 주 해 를 사 용 했 고 여러분 이 사용 하 는 플러그 인 을 매우 추천 합 니 다.
@Data
public class ValidateBO {

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

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

    @Email(message = "email    ")
    private String email;

    /**
     *                
     */
    @CannotHaveBlank
    private String blank;

    /**
     *     
     */
    @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "        ")
    private String phone;

}


여기 서 흔히 볼 수 있 는 주 해 를 사용 한 것 을 볼 수 있다.사용자 정의 검사 주 해 는 아래 에서 언급 합 니 다)
컨트롤 러 검사
controller 에서 이 필드 의 검 사 를 진행 하면 검사 해 야 할 대상 마다 BindingResult 가 검사 결 과 를 받 아야 하고 검사 할 클래스 에@Validated 주 해 를 추가 해 야 합 니 다.
 @GetMapping(value = "/validate")
    public String validate(ValidateBO validateBO, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            StringBuilder stringBuilder = new StringBuilder();
            for (String s : bindingResult.getFieldErrors().stream()
                    .map(FieldError::getDefaultMessage).collect(Collectors.toList())) {
                stringBuilder.append(s);
            }
            return stringBuilder.toString();
        }
        return "success";
    }

항목 을 시작 하고 url 에 항목 에 debug 를 입력 하 십시오.첫 번 째 필드 가 요구 에 부합 되 지 않 으 면 오 류 를 직접 되 돌려 주 는 것 이 아니 라 모든 검사 필드 를 검사 하 는 것 을 볼 수 있 습 니 다.물론 이것 도 설정 할 수 있 습 니 다.아래 에 fast-fail 설정 이 언급 되 어 있 습 니 다.마지막 으로 돌아 온 결과:이 대상 의 모든 오 류 를 인쇄 한 것 입 니 다.
일반적인 검사 주해
JSR 에서 제공 하 는 검사 설명:
@Null             null    
@NotNull               null    
@AssertTrue               true    
@AssertFalse              false    
@Min(value)                  ,                  
@Max(value)                  ,                  
@DecimalMin(value)               ,                  
@DecimalMax(value)               ,                  
@Size(max=, min=)                         
@Digits (integer, fraction)                  ,                
@Past                       
@Future                         
@Pattern(regex=,flag=)                    

Hibernate Validator 가 제공 하 는 검사 설명:
@NotBlank(message =)         null,       0    
@Email                     
@Length(min=,max=)                         
@NotEmpty                   
@Range(min=,max=,message=)                 

그룹 검사
장면
같은 클래스 가 있 으 면 서로 다른 사용 장면 에서 서로 다른 검사 규칙 이 있 으 면 그룹 검 사 를 사용 할 수 있 습 니 다.미성년 자 는 술 을 마 시 면 안 되 고 다른 장면 에서 우 리 는 특별한 제한 을 하지 않 는 다.이 수 요 는 어떻게 같은 실체,서로 다른 검사 규칙 을 나타 내 는가?
검사 대상
@Data
public class ValidateByGroupBO {

    /**
     *   adult      validate   
     */
    @Min(value = 18, groups = {Adult.class})
    private Integer age;

    public interface Adult{}

    public interface Minor{}
}

성인 그룹 에서 만 최소 값 18 의 검 사 를 할 수 있 도록 정의 합 니 다.
검증 을 진행 하 다
 /**
     *            ,    adult         
     * @param validateByGroupBO
     * @param bindingResult
     * @return
     */
    @GetMapping(value = "/drink")
    public String drink(@Validated({ValidateByGroupBO.Adult.class}) ValidateByGroupBO validateByGroupBO, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            //     
            return "false";
        }
        return "success";
    }

    /**
     *         adult            age    
     * @param validateByGroupBO
     * @param bindingResult
     * @return
     */
    @GetMapping(value = "live")
    public String live(@Validated ValidateByGroupBO validateByGroupBO, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            //     
            return "false";
        }
        return "success";
    }

실행 후 url 에 입력http://localhost:7001/drink?age=10첫 번 째 는 false 로 돌아 갑 니 다.그 중의 Adult 그룹 을 지정 하면 age 에 대한 검 사 를 시작 합 니 다.입력http://localhost:7001/live?age=10age 의 크기 를 검사 하지 않 고 success 로 돌아 갑 니 다.술 을 마 실 때 는 성인 여 부 를 검증 하고 생활 을 하지 않 아 도 비슷 한 장면 은 쉽게 만 날 수 있다.
사용자 정의 주석
주 해 를 실현 하 다
빈 칸 을 포함 할 수 없 는 문자열 을 만 듭 니 다.주로 두 단계 로 나 뉜 다.
4.567917.이 주 해 를 먼저 정의 합 니 다.그 중에서 vaidated By 는 진정 으로 검 사 를 하 는 실체 류 를 지정 합 니 다.그 중 groups 와 payload 는 기본 값 으로 사용 할 수 있 습 니 다
@Target({METHOD, FIELD, ANNOTATION_TYPE, ElementType.CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
//                 
@Constraint(validatedBy = {CannotHaveBlankValidator.class})
public @interface CannotHaveBlank {

    //       
    String message() default "      ";

    //   
    Class>[] groups() default {};

    //  
    Class extends Payload>[] payload() default {};

    //       
    @Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        CannotHaveBlank[] value();
    }
}


4.567917.두 번 째 단 계 는 진정 으로 검 사 를 하 는 실체 류 를 실현 하 는 것 이다
public class CannotHaveBlankValidator implements ConstraintValidator {


    @Override
    public void initialize(CannotHaveBlank cannotHaveBlank) {

    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        //null      
        if (value != null && value.contains(" ")) {
            //        
            String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
            System.out.println("default message :" + defaultConstraintMessageTemplate);
            //        
            context.disableDefaultConstraintViolation();
            //     
            context.buildConstraintViolationWithTemplate("can not contains blank")
                    .addConstraintViolation();
            return false;
        }
        return true;
    }
}

이 인 터 페 이 스 는 ConstraintValidator 인 터 페 이 스 를 실현 합 니 다.이 인터페이스 에는 이벤트 초기 화 방법 과 합 법 여 부 를 판단 하 는 방법 이 포함 되 어 있 습 니 다.
package javax.validation;

import java.lang.annotation.Annotation;

public interface ConstraintValidator{
void initialize(A var1);
boolean isValid(T var1, ConstraintValidatorContext var2);
}

그 중의 A 범 형 매개 변 수 는 이전 단계 에 정 의 된 주해 류 이 고 범 형 T 는 검증 할 필드 형식 입 니 다.ConstraintValidatorContext 이 매개 변수 컨 텍스트 는 인증 에 있 는 모든 정 보 를 포함 하고 있 습 니 다.저 희 는 이 컨 텍스트 를 이용 하여 기본 오류 알림 정 보 를 얻 고 오류 알림 정 보 를 사용 하지 않 으 며 오류 알림 정 보 를 바 꾸 는 등 작업 을 할 수 있 습 니 다.
사용자 정의 주석 검사
이 사용자 정의 주 해 를 첫 번 째 controller 로 검증 하 는 것 이 좋 습 니 다.검사 할 대상 에 사용자 정의 주해 의 blank 필드 가 추가 되 었 기 때 문 입 니 다.시작 항목,입력http://localhost:7001/validate?blank=19 209(여기에 빈 칸 을 넣 었 습 니 다).반환 값 은 사용자 정의 주석 이 작용 했다 는 것 을 알 수 있 습 니 다.
@Valid 와@Validated 의 차이
https://blog.csdn.net/qq_27680317/article/details/79970590 이 편 은 매우 분명하게 말 했다.
aop
분명히 우리 모든 controller 의 방법 이 Binding Result 를 쓰 면 매우 번 거 로 워 집 니 다.사실은 우 리 는 매개 변 수 를 검사 하고 log 에 출력 해 야 합 니 다.그러면 자 연 스 럽 게 op 이 생각 납 니 다.
주해 표식
주 해 를 정의 하여 표 지 를 표시 합 니 다.hibenate vaidate 주 해 를 사 용 했 습 니 다.
package com.zhanglijun.springbootdemo.domain.anno;

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;
import javax.validation.groups.Default;

/**
 *       hibernate     
 * @author   
 * @create 2018/8/19 22:28
 */
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableValidate {

    Class> [] groups() default { Default.class };//      
}


정의 절단면
package com.zhanglijun.springbootdemo.aspect;


import com.zhanglijun.springbootdemo.domain.anno.EnableValidate;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.executable.ExecutableValidator;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.hibernate.validator.HibernateValidator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

/**
 * @author   
 * @create 2018/8/19 18:45
 */
@Slf4j
@Aspect
@Component
public class ValidatorAspect {

    /**
     *           
     */
    private static final Validator validator = Validation.byProvider(HibernateValidator.class)
            .configure()
            //        ,             
            .failFast(true)
            .buildValidatorFactory().getValidator();

    /**
     * point  
     */
    @Pointcut("execution(* com.zhanglijun.springbootdemo.web.controller..*.*(..))")
    public void pointcut() {
    }


    /**
     * @desction:      1.           Hibernate validator   ,      2.           EgValidate  ,      ,  Bean     ,     
     * 3.        (    )(    、   )    EgValidate  ,               EgValidate  ,      ,          Bean    ,     
     * @author: wangji
     * @date: 2018/3/13 10:16
     */
    @Before("pointcut()")
    public void before(JoinPoint point) {

        //          
        Object target = point.getThis();
        //         
        Object[] args = point.getArgs();
        //        
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        Annotation[] classAnnotations = target.getClass().getAnnotations();
        Annotation[] methodAnnotations = method.getAnnotations();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        //            ,   Hibernate validator        
        if (parameterAnnotations != null) {
            validMethodParams(target, method, args);
        }

        //          EgValidate  ,      ,Bean       
        int i = 0;

        //                                   
        Set idSet = new HashSet<>(3);
        for (Object arg : args) {
            if (arg != null) {
                if (parameterAnnotations != null) {
                    for (Annotation parameterAnnotation : parameterAnnotations[i]) {
                        if (parameterAnnotation instanceof EnableValidate) {
                            if (!ClassUtils.isPrimitiveOrWrapper(arg.getClass())) {
                                validBeanParam(arg,
                                        ((EnableValidate) parameterAnnotation).groups());
                                idSet.add(i);
                            }
                        }
                    }
                }
                i++;
            }
        }
        //                         
        EnableValidate egValidate = null;
        //          
        if (methodAnnotations != null) {
            egValidate = AnnotationUtils.findAnnotation(method, EnableValidate.class);
        }
        //       
        if (egValidate == null && classAnnotations != null) {
            egValidate = AnnotationUtils.findAnnotation(target.getClass(), EnableValidate.class);
        }
        //                 ,                  ,            ,        
        if (egValidate != null && args != null && args.length > 0) {
            i = 0;
            for (Object arg : args) {
                if (arg != null && !ClassUtils.isPrimitiveOrWrapper(arg.getClass()) && !idSet
                        .contains(i)) {
                    validBeanParam(arg, egValidate.groups());
                }
                i++;
            }
        }

    }


    /**
     * @param obj     Bean    
     * @param groups     
     * @desction:       Bean  
     * @author: wangji
     * @date: 2018/3/13 10:10
     */
    private void validBeanParam(Object obj, Class>... groups) {
        Set> validResult = validator.validate(obj, groups);
        throwConstraintViolationException(validResult);
    }


    /**
     * @param obj      
     * @param method      
     * @param params   
     * @desction:   Hibernate     Bean            【   User getUserInfoById(@NotNull(message =
     * "    ") Integer id);】
     * @author: wangji
     * @date: 2018/3/13 10:11
     */
    private void validMethodParams(Object obj, Method method, Object[] params) {
        ExecutableValidator validatorParam = validator.forExecutables();
        Set> validResult = validatorParam
                .validateParameters(obj, method, params);
        throwConstraintViolationException(validResult);
    }

    /**
     * @desction:              
     * @author: wangji
     * @date: 2018/3/13 10:09
     */
    private void throwConstraintViolationException(Set> validResult) {
        if (!validResult.isEmpty()) {
            throw new ConstraintViolationException(validResult.iterator().next().getMessage(),
                    validResult);
        }
    }


}


이 절단면 도 매우 제거 되 어 여러 곳 에서 이 곳 을 사용 하 는 곳 에 대해 검 사 를 하 였 다.
github
위 코드 는 모두 제 github 에 있 습 니 다.코드 를 리 뷰 할 수 있 습 니 다.validated 주석 관련
인용 하 다.
참고 블 로그:
  • https://www.cnkirito.moe/spring-validation/
  • https://blog.csdn.net/oKuZuoZhou/article/details/81024795
  • https://blog.csdn.net/u012881904/article/details/79538895
  • 좋은 웹페이지 즐겨찾기