在JSR-303自定义验证器中未自动装配的依赖关系

问题描述 投票:13回答:3

我有一个包含User类的Spring Boot应用程序 - 所有字段都有标准的JSR-303注释(@ NotNull,@ Size等),并且验证工作正常。

但是,当我向User添加自定义验证时,我无法将依赖注入到自定义验证器中:

@Component
public class UniqueUsernameValidator implements 
ConstraintValidator<UniqueUsername, String> {

@Autowired
private UserRepository userRepository;

@Override
public boolean isValid(String username, ConstraintValidatorContext context) {
    // implements logic
}

@UniqueUsername注释声明为:

@Documented
@Retention(RUNTIME)
@Target({FIELD, ANNOTATION_TYPE, PARAMETER})
@Constraint(validatedBy = UniqueUsernameValidator.class)
@interface UniqueUsername {
   String message() default "{com.domain.user.nonUniqueUsername}";
   Class<?>[] groups() default { };
   Class<? extends Payload>[] payload() default { };
}

带注释的字段:

@NotBlank
@Size(min = 2, max = 30)
@UniqueUsername
private String username;

验证器用法:

@Service
public final class UserService {

   private final UserRepository userRepository;
   private final Validator validator;

   public UserService(UserRepository userRepository, Validator validator) 
   {
       this.userRepository = userRepository;
       this.validator = validator;
   }

   public void createUser(User user) {
      Set<ConstraintViolation<User>> validate = validator.validate(user);
      // logic...
   }
}

问题是UserRepository没有在UniqueUsernameValidator中自动装配。字段始终为空。

我正在使用LocalValidatorFactoryBean。

有谁知道为什么自动装配不起作用?


@Controller
public class UserController {

private final UserService userService;

public UserController(UserService userService) {
    this.userService = userService;
}

@PostMapping("/user/new")
public String createUser(@ModelAttribute("newUser") User newUser, BindingResult bindingResult,
                         Model model) {
    userService.createUser(newUser);
    // omitted
}
java spring bean-validation
3个回答
2
投票

您需要在User前面的public String createUser(@ModelAttribute(“newUser”)User newUser)中的实体类前面添加@Valid注释。

@RequestBody @Valid User user

0
投票

UserRepository实现需要一个注释,如“@Repository”或“@Component”或“@Service”。您的UserService通过构造函数获取存储库实例。也许有一个“新的UserRepositoryDao()”调用。在您的验证器中,您正在尝试自动装配。我想它要么没有注释为服务,要么没有在spring上下文路径中加载,或者作为spring.xml中的spring bean


0
投票

我几个月前处理过同样的问题。而不是自动装配存储库,通过注释传递已经使用相同存储库的服务。

声明注释以接受要求唯一的字段和执行验证的服务。

@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueUsernameValidator.class)
@Documented
public @interface UniqueUsername {

    String message() default "{com.domain.user.nonUniqueUsername}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    Class<? extends UniqueUsernameValidation> service();      // Validating service
    String fieldName();                                       // Unique field
}

在POJO上使用它:

@NotBlank
@Size(min = 2, max = 30)
@UniqueUsername(service = UserService.class, fieldName = "username")
private String username;

请注意,传递给注释的服务(Class<? extends UniqueUsernameValidation> service())必须实现UniqueUsernameValidation接口。

public interface UniqueUsernameValidation {
    public boolean isUnique(Object value, String fieldName) throws Exception;
}

现在让传递的UserService实现上面的接口并覆盖它唯一的方法:

@Override
public boolean isUnique(Object value, String fieldName) throws Exception {
    if (!fieldName.equals("username")) {
        throw new Exception("Field name not supported");
    }

    String username = value.toString();
    // Here is the logic: Use 'username' to find another username in Repository
}

不要忘记处理注释的UniqueUsernameValidator

public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, Object>
{
    @Autowired
    private ApplicationContext applicationContext;

    private UniqueUsernameValidation service;

    private String fieldName;

    @Override
    public void initialize(UniqueUsername unique) {
        Class<? extends UniqueUsernameValidation> clazz = unique.service();
        this.fieldName = unique.fieldName();
        try {
            this.service = this.applicationContext.getBean(clazz);
        } catch(Exception ex) {
            // Cant't initialize service which extends UniqueUsernameValidator
        }
    }

    @Override
    public boolean isValid(Object o, ConstraintValidatorContext context) {
        if (this.service !=null) {
            // here you check whether the username is unique using UserRepository
            return this.service.isUnique(o, this.fieldName))                    
        }
        return false;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.