英文:
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 "User id already exists";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
UniqueUserValidator.java
public class UniqueUserValidator implements ConstraintValidator<NameMatch, 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;
    }
}
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<NameMatch, 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;
    }
} 
答案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 ^^
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论