我的问题与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层,数据访问层或任何层中的对象耦合。因此,它可以在应用程序的任何层中使用,并支持将验证逻辑本身封装为一等公民。
答案 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);
}