如何在使用javax验证时,仅当字段不为null时对其应用自定义验证?

huangapple go评论73阅读模式
英文:

How to apply custom validation on a field using javax validation only if it is not null?

问题

我正在Spring Boot应用程序中使用javax验证API。我有一个用户实体(bean),我需要验证请求中提供的用户名是否唯一且不存在于数据库中。

我已经为此创建了自定义注解(UniqueUser.java)和自定义验证器(UniqueUserValidator.java)。

public class User {
    @NotNull
    @UniqueUser
    private String username;

    @NotNull
    private String password;

    @NotNull
    @Email
    private String email;

    @NotNull
    private String phone;
}

UniqueUser.java

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueUserValidator.class)
@Documented
public @interface UniqueUser {
    String message() default "User id already exists";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

UniqueUserValidator.java

public class UniqueUserValidator implements ConstraintValidator<UniqueUser, Object> {
    @Autowired
    UserRepository userRepository;

    @Override
    public boolean isValid(String userName, final ConstraintValidatorContext context) {
        boolean isValidUser = false;
        if (userName != null && !userName.isEmpty()) {
            Optional<User> user = userRepository.findByUserId(userName);
            isValidUser = !user.isPresent();
        }
        return isValidUser;
    }
}

在上述代码中,即使用户名字段为null,唯一用户验证也会被调用,并显示“用户名已存在”错误消息。我希望只有在用户名具有某些值时才调用自定义验证器。是否有可能避免这种调用。

我可以通过修改下面的方法来修复错误,如果用户名为null,则返回true,但我想避免这种不必要的调用。

public class UniqueUserValidator implements ConstraintValidator<UniqueUser, Object> {
    @Autowired
    UserRepository userRepository;

    @Override
    public boolean isValid(String userName, final ConstraintValidatorContext context) {
        boolean isValidUser = false;
        if (userName != null && !userName.isEmpty()) {
            Optional<User> user = userRepository.findByUserId(userName);
            isValidUser = !user.isPresent();
        } else {
            isValidUser = true;
        }
        return isValidUser;
    }
}
英文:

I am working on javax validation API in Spring Boot Application. I have a User bean and i have to validate that username given in request is unique and doesn't exist into Database.

I have created custom annotation (UniqueUser.java) and custom Validator(UniqueUserValidator.java) for this requirement.

public class User  {
    @NotNull
    @UniqueUser
    private String username;

    @NotNull
    private String password;

    @NotNull
    @Email
    private String email;

    @NotNull
    private String phone;
}

UniqueUser.java

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueUserValidator.class)
@Documented
public @interface NameMatch
{
    String message() default &quot;User id already exists&quot;;

    Class&lt;?&gt;[] groups() default {};

    Class&lt;? extends Payload&gt;[] payload() default {};
}

UniqueUserValidator.java

public class UniqueUserValidator implements ConstraintValidator&lt;NameMatch, Object&gt;
{
    @Autowired
    UserRepository userRepository;
   
    @Override
    public boolean isValid(String userName, final ConstraintValidatorContext context)
    {
        boolean isValidUser = false;
        if(userName!=null &amp;&amp; !userName.isEmpty()) {
        Optional&lt;User&gt; user= userRepository.findByUserId(userName);
           isValidUser = !user.isPresent(); 
        }
        return isValidUser;
    }
}

In above code, the unique user validation get called for username field even if the field is null and shows Username already exists error message. I want the custom validator to get called only when username has some value. Is it possible to avoid this call.

I can fix the error by modifying the below method and returning true if username is null, but i want't to avoid this unnecessary call.

public class UniqueUserValidator implements ConstraintValidator&lt;NameMatch, Object&gt;
{
    @Autowired
    UserRepository userRepository;
   
    @Override
    public boolean isValid(String userName, final ConstraintValidatorContext context)
    {
        boolean isValidUser = false;
        if(userName!=null &amp;&amp; !userName.isEmpty()) {
        Optional&lt;User&gt; user= userRepository.findByUserId(userName);
           isValidUser = !user.isPresent(); 
        } else {
           isValidUser = true; 
        }
        return isValidUser;
    }
} 

答案1

得分: 1

我认为您要寻找的是分组约束

> 分组允许您在验证期间限制应用的约束集。验证组的一个用例是 UI 向导,在每个步骤中只需要验证指定的一部分约束。目标组以 var-arg 参数的形式传递给适当的验证方法。

在您的情况下,应该是这样的:

@GroupSequence({ FirstConstaint.class, SecondConstaint.class })
public class User  {
    @NotNull(groups = FirstConstaint.class)
    @UniqueUser(groups = SecondConstaint.class)
    private String username;

    // 其他字段
}

interface FirstConstaint {
}

interface SecondConstaint {
}

这样,它只会在字段不为空时检查 @UniqueUser,否则,它将返回 @NotNull 验证的消息。

另外,如 @User 所说,您还可以将这些检查用于服务层 ^^

英文:

I think what you are looking for is Grouping constraints;

> Groups allow you to restrict the set of constraints applied during
> validation. One use case for validation groups are UI wizards where in
> each step only a specified subset of constraints should get validated.
> The groups targeted are passed as var-arg parameters to the
> appropriate validate method.

In your case it should look like this:

@GroupSequence({ FirstConstaint.class, SecondConstaint.class })
public class User  {
    @NotNull(groups = FirstConstaint.class)
    @UniqueUser(groups = SecondConstaint.class)
    private String username;

    // the rest of your fields
}

interface FirstConstaint {
}

interface SecondConstaint {
}

This way, it will check @UniqueUser only if the field is not null, otherwise, it will return the message of @NotNull validation.

Otherwise like @User said you can use this checks in service layer ^^

huangapple
  • 本文由 发表于 2020年7月26日 22:18:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/63101373.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定