Java 服务层中的Spring@Validated

Java 服务层中的Spring@Validated,java,spring,validation,spring-mvc,Java,Spring,Validation,Spring Mvc,嘿 我想在执行如下方法之前,使用@Validated(group=Foo.class)注释验证参数: public void doFoo(Foo @Validated(groups=Foo.class) foo){} 当我将此方法放入Spring应用程序的控制器中时,执行@Validated,并在Foo对象无效时抛出错误。但是,如果我在应用程序服务层的方法中放入相同的内容,则不会执行验证,并且即使当Foo对象无效时,该方法也会运行 您不能在服务层中使用@Validated注释吗?或者我必须做一

我想在执行如下方法之前,使用
@Validated(group=Foo.class)
注释验证参数:

public void doFoo(Foo @Validated(groups=Foo.class) foo){}
当我将此方法放入Spring应用程序的控制器中时,执行
@Validated
,并在Foo对象无效时抛出错误。但是,如果我在应用程序服务层的方法中放入相同的内容,则不会执行验证,并且即使当Foo对象无效时,该方法也会运行

您不能在服务层中使用
@Validated
注释吗?或者我必须做一些额外的配置才能让它工作

更新:

我已将以下两个bean添加到我的service.xml中:

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

我知道这是一个相当愚蠢的注释,但我想检查一下,如果我现在调用该方法并传递null,它是否会抛出一个违反规则的异常。那么为什么它要执行
@Null
注释而不是
@Validate
注释呢?我知道一个来自javax.validation,另一个来自Spring,但我不认为这与它有任何关系

在Spring MVC堆栈中,没有服务层。它对
@Controller
类处理程序方法有效的原因是Spring使用了一个名为
ModelAttributeMethodProcessor
的特殊
HandlerMethodArgumentResolver
,它在解析要在处理程序方法中使用的参数之前执行验证

我们称之为服务层,它只是一个普通bean,没有从MVC(
DispatcherServlet
)堆栈中添加额外的行为。因此,您不能期望Spring提供任何验证。你需要自己动手,可能是用AOP


使用
MethodValidationPostProcessor
,查看javadoc

适用的方法在其上有JSR-303约束注释 参数和/或其返回值(在后一种情况下指定 在方法级别,通常作为内联注释)

可以通过Spring的Validated命令指定验证组 包含目标类的类型级别的注释,应用 该类的所有公共服务方法。默认情况下,JSR-303将 仅针对其默认组进行验证


@Validated
注释仅用于指定验证组,它本身并不强制任何验证。您需要使用
javax.validation
注释之一,如
@Null
@Valid
。请记住,可以在方法参数上使用任意数量的注释。

如上所述,只有通过类级别的
@Validated
注释才能指定验证组。但是,这不是很方便,因为有时您有一个类包含多个方法,这些方法具有作为参数的相同实体,但每个方法都需要不同的属性子集来验证。这也是我的情况,下面你可以找到几个步骤来解决它

1) 实现自定义注释,除了在类级别通过
@Validated
指定的组外,还可以在方法级别指定验证组

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidatedGroups {

    Class<?>[] value() default {};
}
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) 注册验证后处理器,而不是Spring 1

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

@pgiecek您不需要创建新注释。您可以使用:

@已验证
公共类MyClass{
@已验证({Group1.class})
公共myMethod1(@Valid Foo Foo){…}
@已验证({Group2.class})
公共myMethod2(@Valid Foo Foo){…}
...
}

小心鲁宾萨的方法

这仅在声明
@Valid
为唯一注释时有效。当您将其与其他注释(如
@NotNull
组合时,
@Valid
之外的所有内容都将被忽略

以下将不起作用
@NotNull
将被忽略:

@已验证
公共类MyClass{
@已验证(Group1.class)
public void myMethod1(@NotNull@Valid Foo Foo){…}
@已验证(Group2.class)
public void myMethod2(@NotNull@Valid Foo Foo){…}
}
结合其他注释,您还需要声明
javax.validation.groups.Default
组,如下所示:

@已验证
公共类MyClass{
@已验证({Default.class,Group1.class})
public void myMethod1(@NotNull@Valid Foo Foo){…}
@已验证({Default.class,Group2.class})
public void myMethod2(@NotNull@Valid Foo Foo){…}
}

作为弹簧验证方法的旁注:

由于Spring在其方法中使用拦截器,因此验证本身仅在您与Bean的方法对话时执行:

当通过Spring或JSR-303验证程序接口与这个bean的实例交谈时,您将与底层ValidatorFactory的默认验证程序交谈。这非常方便,因为您不必再对工厂执行另一个调用,假设您几乎总是使用默认验证器

这一点很重要,因为如果您试图以这种方式为类内的方法调用实现验证,那么它将不起作用。例如:

@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进行测试,因此其他版本可能会有所不同。

这是正确的答案,但实际操作步骤在这里-不,链接中只包含安装说明needed@chrismarx对不起,那不一定是给你的。您会自动收到通知,因为您是唯一发表评论的人。还要注意接口类型:MethodValidationInterceptor使用接口类型收集方法的批注。如果您有
@有效
<bean class="my.package.ValidatedGroupsAwareMethodValidationPostProcessor"/> 
@Validated(groups = Group1.class)   
public class MyClass {

    @ValidatedGroups(Group2.class)
    public myMethod1(Foo foo) { ... }

    public myMethod2(Foo foo) { ... }

    ...
}
@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
    }        
}