Зависимость не подключена автоматически в пользовательском валидаторе JSR-303 - PullRequest
0 голосов
/ 29 августа 2018

У меня есть приложение Spring Boot, которое содержит класс User - все поля имеют стандартные аннотации 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
}

Ответы [ 3 ]

0 голосов
/ 07 сентября 2018

Реализация UserRepository нуждается в аннотации, такой как "@Repository" или "@Component" или "@Service". Ваш UserService получает экземпляр хранилища через конструктор. Возможно, был использован новый вызов UserRepositoryDao (). И в вашем валидаторе вы пытаетесь автопроводить. Я предполагаю, что он либо не аннотирован как сервис ИЛИ не загружен в контексте контекста Spring, либо как Spring Bean в вашем spring.xml

0 голосов
/ 07 сентября 2018

Я сталкивался с той же проблемой несколько месяцев назад. Вместо автоматического подключения хранилища передайте службу, которая уже использует тот же хранилище, через аннотацию.

Объявите аннотацию для принятия поля, которое должно быть уникальным, и службы, выполняющей проверку.

@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;
    }
}
0 голосов
/ 06 сентября 2018

Вам нужно добавить аннотацию @Valid перед классом сущности в общедоступной строке createUser (@ModelAttribute ("newUser") User newUser) перед пользователем.

@RequestBody @Valid User user
...