복붙노트

[SPRING] 서비스 레이어에서 봄 @ 인증 됨

SPRING

서비스 레이어에서 봄 @ 인증 됨

안녕하세요

다음과 같은 메소드를 실행하기 전에 @Validated (group = Foo.class) 주석을 사용하여 인수의 유효성을 검사하려고합니다.

public void doFoo(Foo @Validated(groups=Foo.class) foo){}

이 메소드를 Spring 애플리케이션의 Controller에 넣으면 @Validated가 실행되고 Foo 객체가 유효하지 않은 경우 오류가 발생합니다. 그러나 응용 프로그램의 서비스 계층에있는 메소드에 동일한 것을 넣으면 유효성 검사가 실행되지 않고 Foo 객체가 유효하지 않은 경우에도 메소드가 실행됩니다.

서비스 계층에서 @Validated 주석을 사용할 수 없습니까? 또는 작동하도록 구성하려면 추가로 구성해야합니까?

최신 정보:

service.xml에 다음 두 Bean을 추가했습니다.

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>

@Validate를 @Null로 대체했습니다.

public void doFoo(Foo @Null(groups=Foo.class) foo){}

나는 바보 같은 어노테이션이 있다는 것을 알고 있지만, 지금 메소드를 호출하고 null을 전달하면 그것이 위반 예외를 던질 수 있는지 확인하고 싶다. 그렇다면 @Null 주석과 @Validate 주석을 실행하는 이유는 무엇입니까? 하나는 javax.validation에서 왔고 다른 하나는 Spring에서 온 것입니다.하지만 그와 아무 관계가 없다고 생각합니까?

해결법

  1. ==============================

    1.스프링 MVC 스택에는 서비스 레이어와 같은 것이 없다. @Controller 클래스 핸들러 메소드에서 작동하는 이유는 Handler 메소드에서 사용할 인수를 해결하기 전에 유효성 검사를 수행하는 ModelAttributeMethodProcessor라는 특수 HandlerMethodArgumentResolver를 Spring에서 사용하기 때문입니다.

    스프링 MVC 스택에는 서비스 레이어와 같은 것이 없다. @Controller 클래스 핸들러 메소드에서 작동하는 이유는 Handler 메소드에서 사용할 인수를 해결하기 전에 유효성 검사를 수행하는 ModelAttributeMethodProcessor라는 특수 HandlerMethodArgumentResolver를 Spring에서 사용하기 때문입니다.

    서비스 레이어는 MVC (DispatcherServlet) 스택에서 추가 된 동작이없는 단순한 빈입니다. 따라서 스프링의 검증은 기대할 수 없습니다. 아마도 AOP로 자신 만의 롤백을해야합니다.

    MethodValidationPostProcessor를 사용하여 javadoc을 살펴보십시오.

    @Validated 주석은 유효성 검사 그룹을 지정하는 데만 사용되며 자체 검증을 수행하지는 않습니다. @Null 또는 @Valid와 같은 javax.validation 주석 중 하나를 사용해야합니다. 메서드 매개 변수에서 원하는만큼의 주석을 사용할 수 있습니다.

  2. ==============================

    2.@pgiecek 새로운 주석을 작성할 필요가 없습니다. 당신이 사용할 수있는:

    @pgiecek 새로운 주석을 작성할 필요가 없습니다. 당신이 사용할 수있는:

    @Validated
    public class MyClass {
    
        @Validated({Group1.class})
        public myMethod1(@Valid Foo foo) { ... }
    
        @Validated({Group2.class})
        public myMethod2(@Valid Foo foo) { ... }
    
        ...
    }
    
  3. ==============================

    3.유효성 검사 그룹을 지정하기 위해 위에서 언급 한 것처럼 클래스 수준의 @Validated 주석을 통해서만 가능합니다. 그러나 때때로 매개 변수와 같은 엔티티로 여러 메소드를 포함하지만 각각 다른 속성의 서브 세트를 검증해야하는 클래스가 있기 때문에 매우 편리하지 않습니다. 그것은 또한 나의 경우 였고 아래에서는 그것을 해결하기 위해 취할 수있는 몇 가지 단계를 찾을 수 있습니다.

    유효성 검사 그룹을 지정하기 위해 위에서 언급 한 것처럼 클래스 수준의 @Validated 주석을 통해서만 가능합니다. 그러나 때때로 매개 변수와 같은 엔티티로 여러 메소드를 포함하지만 각각 다른 속성의 서브 세트를 검증해야하는 클래스가 있기 때문에 매우 편리하지 않습니다. 그것은 또한 나의 경우 였고 아래에서는 그것을 해결하기 위해 취할 수있는 몇 가지 단계를 찾을 수 있습니다.

    1) 클래스 수준에서 @Validated를 통해 지정된 그룹 외에도 메서드 수준에서 유효성 검사 그룹을 지정할 수있는 사용자 지정 주석을 구현합니다.

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ValidatedGroups {
    
        Class<?>[] value() default {};
    }
    

    2) MethodValidationInterceptor를 확장하고 다음과 같이 determineValidationGroups 메소드를 재정의합니다.

    @Override
    protected Class<?>[] determineValidationGroups(MethodInvocation invocation) {
        final Class<?>[] classLevelGroups = super.determineValidationGroups(invocation);
    
        final ValidatedGroups validatedGroups = AnnotationUtils.findAnnotation(
                invocation.getMethod(), ValidatedGroups.class);
    
        final Class<?>[] methodLevelGroups = validatedGroups != null ? validatedGroups.value() : new Class<?>[0];
        if (methodLevelGroups.length == 0) {
            return classLevelGroups;
        }
    
        final int newLength = classLevelGroups.length + methodLevelGroups.length;
        final Class<?>[] mergedGroups = Arrays.copyOf(classLevelGroups, newLength);
        System.arraycopy(methodLevelGroups, 0, mergedGroups, classLevelGroups.length, methodLevelGroups.length);
    
        return mergedGroups;
    }
    

    3) 자신의 MethodValidationPostProcessor (Spring 하나 복사)를 구현하고 afterPropertiesSet 메소드에서 2 단계에서 구현 된 유효성 검사 인터셉터를 사용하십시오.

    @Override
    public void afterPropertiesSet() throws Exception {
        Pointcut pointcut = new AnnotationMatchingPointcut(Validated.class, true);
        Advice advice = (this.validator != null ? new ValidatedGroupsAwareMethodValidationInterceptor(this.validator) :
                new ValidatedGroupsAwareMethodValidationInterceptor());
        this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
    }
    

    4) 스프링 1 대신 유효성 검사 후 프로세서를 등록하십시오.

    <bean class="my.package.ValidatedGroupsAwareMethodValidationPostProcessor"/> 
    

    그게 전부 야. 이제 다음과 같이 사용할 수 있습니다.

    @Validated(groups = Group1.class)   
    public class MyClass {
    
        @ValidatedGroups(Group2.class)
        public myMethod1(Foo foo) { ... }
    
        public myMethod2(Foo foo) { ... }
    
        ...
    }
    
  4. ==============================

    4.루벤 사의 접근 방식에주의하십시오.

    루벤 사의 접근 방식에주의하십시오.

    이것은 유일한 주석으로 @Valid를 선언 할 때만 작동합니다.

    다음은 작동하지 않고 @NotNull은 무시됩니다.

    @Validated
    public class MyClass {
    
        @Validated(Group1.class)
        public myMethod1(@NotNull @Valid Foo foo) { ... }
    
        @Validated(Group2.class)
        public myMethod2(@NotNull @Valid Foo foo) { ... }
    
    }
    

    다른 주석과 함께 다음과 같이 javax.validation.groups.Default 그룹을 선언해야합니다.

    @Validated
    public class MyClass {
    
        @Validated({ Default.class, Group1.class })
        public myMethod1(@NotNull @Valid Foo foo) { ... }
    
        @Validated({ Default.class, Group2.class })
        public myMethod2(@NotNull @Valid Foo foo) { ... }
    
    }
    
  5. ==============================

    5.스프링 밸리데이션 (Spring Validation) 방법에 대한 보조 노트 :

    스프링 밸리데이션 (Spring Validation) 방법에 대한 보조 노트 :

    Spring은 접근 방식에서 인터셉터를 사용하기 때문에 유효성 검증 자체는 Bean의 메소드와 대화 할 때만 수행됩니다.

    이것은 클래스 내에서 메소드 호출을 위해 유효성 검증을 구현하려는 경우 작동하지 않으므로 중요합니다. 예 :

    @Autowired
    WannaValidate service;
    //...
    service.callMeOutside(new Form);
    
    @Service
    public class WannaValidate {
    
        /* Spring Validation will work fine when executed from outside, as above */
        @Validated
        public void callMeOutside(@Valid Form form) {
             AnotherForm anotherForm = new AnotherForm(form);
             callMeInside(anotherForm);
        }
    
        /* Spring Validation won't work for AnotherForm if executed from inner method */
        @Validated
        public void callMeInside(@Valid AnotherForm form) {
             // stuff
        }        
    }
    

    누군가 도움이되기를 바랍니다. Spring 4.3으로 테스트되었으므로 다른 버전에서는 상황이 다를 수 있습니다.

  6. from https://stackoverflow.com/questions/19425221/spring-validated-in-service-layer by cc-by-sa and MIT license