Spring框架的验证不适用于JSR-303验证

时间:2019-12-11 11:04:49

标签: java spring spring-boot validation

我的问题与bean验证有关。显然,SpringBoot具有两种不同的验证机制,一种是JSR-303编译器(在javax.validation包中),另一种是由Spring框架提供的(在org.springframework.validation包中)。

虽然通过JSR-303@Validated批注很容易实施@Valid验证,但我找不到适合Spring批注的正确方法。

采用以下User bean。

@Entity
public class User {
    @Column
    @Id
    private String id;

    @Column(unique = true)
    @Username
    private String username;

    // [...]
}

@Username约束的定义如下。基本上,它只是@Pattern@Size Costrains的组成。

@Constraint(validatedBy = {})
@Documented
@Pattern(regexp = "[A-Za-z0-9_]+")
@Retention(RUNTIME)
@Size(max = 24, min = 3)
@Target(FIELD)
public @interface Username {
    String message() default "";

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

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

User bean存储在名为UserRepository的存储库中,定义如下。

@Repository
public interface UserRepository extends CrudRepository<User, String>, JpaSpecificationExecutor<User> {
}

要访问存储库,我写了一个服务,如下所示。

@Transactional
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Validated
    public void create(@Valid User user) {
        userRepository.save(user);
    }
}

直到现在,一切都非常整洁,一切正常。仅需几个注释,我就可以完成所有工作。

现在,我有了另一个验证器(不是JSR-303)。

// [...]
import org.springframework.validation.Validator;

@Component
public class UniqueUsernameValidator implements Validator {
    @Autowired
    private UserRepository userRepository;

    @Override
    public boolean supports(Class<?> clazz) {
        return User.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        User user = (User) target;

        if (userRepository.count(where(usernameIsEqualTo(user.getUsername()))) > 0) {
            errors.rejectValue("username", "username.exists");
        }
    }
}

理想情况下,我想通过相同的@Validated@Valid注释来实施它,但是直到现在我还是很不幸。考虑到类org.springframework.validation.Validator的文档说

,我想这绝对有可能
  

此接口与任何基础结构或上下文完全脱离;也就是说,它不与仅验证Web层,数据访问层或任何层中的对象耦合。因此,它可以在应用程序的任何层中使用,并支持将验证逻辑本身封装为一等公民。

1 个答案:

答案 0 :(得分:0)

@Valid是一个JSR-303 bean验证批注,它不会调用您的UniqueUsernameValidator Spring Validator。

如果要在服务中执行此操作,则需要手动调用它:

public void create(@Valid User user) {
    Errors errors = new BeanPropertyBindingResult(user, "user");

    // Validator component has been previously injected into the service.
    uniqueUsernameValidator.validate(user, errors); 
    if (errors.hasErrors()) {
        throw new RuntimeException(errors.toString());
    }

    userRepository.save(user);
}