Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring Hibernate验证-每个字段获取一条错误消息_Java_Spring Mvc_Bean Validation_Hibernate Validator - Fatal编程技术网

Java Spring Hibernate验证-每个字段获取一条错误消息

Java Spring Hibernate验证-每个字段获取一条错误消息,java,spring-mvc,bean-validation,hibernate-validator,Java,Spring Mvc,Bean Validation,Hibernate Validator,每个字段只能收到一条错误消息。我对每个字段都有很多规则,我想逐一验证它们。如果其中一条失败,验证将停止并仅返回一条消息,描述此字段的失败规则 经过研究,我发现了类似于@ReportAssingeViolation注释的东西,它可以正常工作,但它修复了来自自定义约束的消息。所以这不是我想要的 我已经读过@GroupSequence,但我也无法让它像我描述的那样工作 这是具有自定义约束规则的我的实体: @实体 @表(name=“users”,schema=“myschema”) 公共类用户{ 私有

每个字段只能收到一条错误消息。我对每个字段都有很多规则,我想逐一验证它们。如果其中一条失败,验证将停止并仅返回一条消息,描述此字段的失败规则

经过研究,我发现了类似于@ReportAssingeViolation注释的东西,它可以正常工作,但它修复了来自自定义约束的消息。所以这不是我想要的

我已经读过@GroupSequence,但我也无法让它像我描述的那样工作

这是具有自定义约束规则的我的实体:

@实体
@表(name=“users”,schema=“myschema”)
公共类用户{
私有int-id;
@ValidLogin
私有字符串登录;
@有效密码
私有字符串密码;
@瓦利德梅尔
私人字符串电子邮件;
//接球手和接球手
}
以及使用两个内置规则实现自定义约束:

@约束(validatedBy=UsernameValidator.class)
@目标(ElementType.FIELD)
@保留(RetentionPolicy.RUNTIME)
@空空如也
@模式(regexp=“^[a-zA-Z0-9]*$”)
@长度.列表({
@长度(min=3,message=“{Length.min.user.login}”),
@长度(max=30,message=“{Length.max.user.login}”)
})
public@interface ValidLogin{
字符串消息()默认为“”;
类[]组()默认值{};

类每个注释都有
属性,可用于将检查划分为组:

public class MyForm {

    @NotEmpty(groups = LoginLevel1.class)
    @Pattern(regexp = "^[a-zA-Z0-9]*$", groups = LoginLevel2.class)
    @Length.List({
        @Length(min = 3 , message = "{Length.min.user.login}", groups = LoginLevel3.class),
        @Length(max = 30, message = "{Length.max.user.login}", groups = LoginLevel3.class)
    })
    private String login;
}
下一步是使用允许快速故障行为的
@GroupSequence
对这些组进行分组:

public class MyForm {
    ...
    @GroupSequence({
        LoginLevel1.class,
        LoginLevel2.class,
        LoginLevel3.class
    })
    public interface LoginChecks {}

    public interface LoginLevel1 {}
    public interface LoginLevel2 {}
    public interface LoginLevel3 {}
}
最后一步是指示Spring使用以下组序列进行验证:

@PostMapping("/form-handler")
public String processForm(@Validated({MyForm.LoginChecks.class, MyForm.PasswordChecks.class}) MyForm form, BindingResult result) {

    if (result.hasErrors()) {
        return null;
    }
    ...
}

我想知道GroupSequence是否因为自定义约束而无法工作,是的,这就是原因

我在自定义约束中应用了内置规则,但这些规则的组不起作用。在自定义约束中,只有一个组默认值可见,因为:

Class<?>[] groups() default { };
Class[]groups()默认值{};
当我将这些内置规则从自定义约束移动到字段(现在更难看了,我想保持实体的美观)时,这是可行的

但我们又来了。现在它必须一级一级地进行,意思是当一个字段为空时,其他字段不为空时,只有一条消息为空。其他字段即使无效,也在等待下一个“级别”序列。这同样不是我想要的

对于spring/hibernate来说,每个字段出现一个错误似乎太多了


如果有人有办法让它工作的话,请告诉我,我会试试看。

我想这是你想要的:

@Test
public void test() {
    Validator v = Validation.byProvider( HibernateValidator.class )
            .configure()
            .buildValidatorFactory()
            .getValidator();

    // validations for each group - shows only corresponding violations even if other constraints
    // are violated as well
    assertThat( v.validate( new Bar( null, null ), First.class ) ).hasSize( 2 );
    assertThat( v.validate( new Bar( "", "" ), Second.class ) ).hasSize( 2 );
    assertThat( v.validate( new Bar( "a", "a" ), Third.class ) ).hasSize( 2 );

    // shows that validation will go group by group as defined in the sequence:
    //NotNull
    Set<ConstraintViolation<Bar>> violations = v.validate( new Bar( null, null ) );
    assertThat( violations ).hasSize( 2 );
    assertThat( violations ).extracting( "message" ).containsOnly( "must not be null" );

    //NotBlank
    violations = v.validate( new Bar( "", "" ) );
    assertThat( violations ).hasSize( 2 );
    assertThat( violations ).extracting( "message" ).containsOnly( "must not be blank" );

    //Size
    violations = v.validate( new Bar( "a", "a" ) );
    assertThat( violations ).hasSize( 2 );
    assertThat( violations ).extracting( "message" ).containsOnly( "size must be between 5 and 2147483647" );

}

@GroupSequence({ First.class, Second.class, Third.class, Bar.class })
private static class Bar {

    @NotNull(groups = First.class)
    @NotBlank(groups = Second.class)
    @Size(min = 5, groups = Third.class)
    private final String login;

    @NotNull(groups = First.class)
    @NotBlank(groups = Second.class)
    @Size(min = 5, groups = Third.class)
    private final String password;

    public Bar(String login, String password) {
        this.login = login;
        this.password = password;
    }
}

interface First {
}

interface Second {
}

interface Third {
}

在这种情况下,您只需拥有自己的自定义约束和验证器。然后逐个检查,然后根据第一次失败的检查构建冲突。此外,如果您要对登录和pa执行类似的检查,您还可以将
模式
最小值
最大值
提取为约束的属性ssword,但例如字符串长度上有不同的模式…

检查此项,它将帮助您:我的意思是添加此注释(@reportassingelivision)在您的自定义注释中,我说过我已经尝试过了,为什么它不是我想要的。它只返回为@ValidLogin定义的一般消息,而不是为内部破坏的特定规则返回的消息。@codeboy,请尝试,测试并提问。我已经在我的项目中成功使用了一段时间,可能会错过一些东西。它对我不起作用。我已经尝试过了it.I收到以下错误:
javax.validation.ConstraintViolationException:在组[javax.validation.groups.Default]的持久化时间内,类[package.entities.User]的验证失败,]
似乎它仍然需要默认组,但当我将其放在我的GroupSequence末尾时,再次一次返回所有错误。可能是因为自定义约束?在您的示例中,您将规则注释放在字段上。PS:不允许在一个文件中将多个interfece定义为公共^^^谢谢!我已将答案更新为put接口进入form类。您的错误意味着您在同一对象上混合了验证批注和JPA批注。Hibernate尝试在将对象持久化到数据库之前验证该对象,但失败。您可以通过此附加验证将其禁用,或者使用不同的对象进行验证和持久化。这与之前的答案类似,wh变化在哪里?我也说过并表明我在自定义约束中应用内置规则,而不是在字段中。同样,这就像:例如,如果密码为空,但登录长度为3,则密码只有一条消息为空。在这种情况下,不会有登录太短的消息,对吗?@codeboy the differentce是定义
@GroupSequence
的地方和方式-这应该可以解决您在对上一个解决方案的评论中提到的问题,并在持久化期间进行验证。是的……这将检查所有
NotNull
字段,如果至少有一个
null
字段,则其他字段即使为null但不为空,也会检查将不会检查其他约束。是的,编辑方法它将工作,我以前见过它,但我想让它与内置约束一起工作。无论如何,感谢您的努力。
    @Test
public void test2() throws Exception {
    Set<ConstraintViolation<Foo>> violations = validator.validate( new Foo( "", null ) );
    assertThat( violations ).hasSize( 2 );
    assertThat( violations ).extracting( "message" )
            .containsOnly( "value should be between 3 and 30 chars long", "Value cannot be null" );
}

private static class Foo {

    @ValidLogin
    private final String login;

    @ValidLogin
    private final String password;

    public Foo(String login, String password) {
        this.login = login;
        this.password = password;
    }
}

@Target({ FIELD })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { ValidLogin.ValidLoginValidator.class })
@interface ValidLogin {
    String message() default "message";

    Class<?>[] groups() default { };

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

    class ValidLoginValidator implements ConstraintValidator<ValidLogin, String> {
        private static final Pattern PATTERN = Pattern.compile( "^[a-zA-Z0-9]*$" );

        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            String message = "";
            if ( value == null ) {
                message = "Value cannot be null";
            }
            else if ( !PATTERN.matcher( value ).matches() ) {
                message = "Value should match pattern ";
            }
            else if ( message.length() < 3 || message.length() > 30 ) {
                message = "value should be between 3 and 30 chars long";
            }
            if ( !message.isEmpty() ) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate( message ).addConstraintViolation();
            }
            return false;
        }
    }
}