我有一个包含User类的Spring Boot应用程序-所有字段都有标准的JSR-303批注(@ NotNull,@ Size等),并且验证工作正常。
但是,当我向用户添加自定义验证时,我无法将依赖项注入到自定义验证器中:
@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
}
答案 0 :(得分:2)
您需要在User前面的公共String createUser(@ModelAttribute(“ newUser”)User newUser)中的实体类前面添加@Valid注释。
@RequestBody @Valid User user
答案 1 :(得分:0)
UserRepository实现需要一个注释,例如“ @Repository”或“ @Component”或“ @Service”。您的UserService通过构造函数获取资源库实例。也许使用了“ new UserRepositoryDao()”调用。在您的验证器中,您正在尝试自动接线。我想它要么未标注为服务,要么未标注在spring上下文路径中,或者未标注为spring.xml中的spring Bean
答案 2 :(得分: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;
}
}