自定义 ConstraintValidator 不工作(异常)
Custom ConstraintValidator not working (Exception)
我对 Spring 有疑问,尤其是 ConstraintValidator。我想为包含电子邮件的字段发布自定义验证。它必须是独一无二的。好的。任务很明确,我是这样做的:
UniqueEmail.java
@Constraint(validatedBy = UniqueEmailValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueEmail {
String message() default "Invalid phone number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
UniqueEmailValidator.java
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
private final UserRepository userRepository;
public UniqueEmailValidator(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
return email != null && !userRepository.findByEmail(email).isPresent();
}
}
User.java
@Data
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
@NotEmpty(message = "Email should not be empty")
@Email(message = "Email should be valid")
@UniqueEmail(message = "Email address is already registered")
private String email;
@NotEmpty(message = "Password should not be empty")
private String password;
@NotEmpty(message = "Name should not be empty")
@Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters")
private String username;
private boolean enabled = true;
@Enumerated(value = EnumType.STRING)
private Role role;
}
UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
AuthController.java
@Controller
@RequestMapping("/auth")
public class AuthController {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
public AuthController(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@GetMapping("/login")
public String login(Principal principal) {
if(principal != null)
return "redirect:/";
return "auth/login";
}
@GetMapping("/register")
public String register(@ModelAttribute("user") User user, Principal principal) {
if(principal != null)
return "redirect:/";
return "auth/register";
}
@PostMapping("/register")
public String newCustomer(Principal principal, Model model, @ModelAttribute("user") @Valid User user, BindingResult bindingResult) {
if(principal != null)
return "redirect:/";
if(bindingResult.hasErrors())
return "auth/register";
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setRole(Role.CUSTOMER);
userRepository.saveAndFlush(user);
model.addAttribute("success", true);
model.addAttribute("user", new User());
return "auth/register";
}
}
如果我尝试输入现有的电子邮件,一切正常(收到消息“电子邮件地址已注册”)。但是,如果我尝试输入一封新电子邮件,我会收到错误消息“Servlet.service() for servlet [dispatcherServlet] in context with path [] throw exception [Request processing failed; nested exception is javax.validation.ValidationException: HV000064:无法实例化 ConstraintValidator:bla.bla.bla.validator.UniqueEmailValidator.] 具有根本原因。
我正在尝试使用@Component 和@Autowired,但得到了相同的结果。
我正在尝试使用 noArgs 构造函数并得到 NullPointerException(未注入 UserRepository)。
为什么?没看懂。
上述错误是因为您的 UniqueEmailValidator 的构造函数为空。
另见:javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator
您可以使用@Autowired 注释将 userRepository 注入您的约束验证器,如前所述:
- 此处:Inject Spring Beans into Annotation-based Bean Validator
- 这里:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#validation-beanvalidation-spring-constraints
另外请注意在所有相关的控制器方法User user之前加上@Valid注解
这样问题就解决了。我知道这是一个拐杖,但我还没有找到其他解决方案。
@Component
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
private UserRepository userRepository;
public UniqueEmailValidator() {
}
@Autowired
public UniqueEmailValidator(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
if(userRepository == null)
return true;
return email != null && !userRepository.findByEmail(email).isPresent();
}
}
添加了 noArgs 构造函数,并在 isValid 函数中添加了 ckeck if null userRepository。
我对 Spring 有疑问,尤其是 ConstraintValidator。我想为包含电子邮件的字段发布自定义验证。它必须是独一无二的。好的。任务很明确,我是这样做的:
UniqueEmail.java
@Constraint(validatedBy = UniqueEmailValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueEmail {
String message() default "Invalid phone number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
UniqueEmailValidator.java
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
private final UserRepository userRepository;
public UniqueEmailValidator(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
return email != null && !userRepository.findByEmail(email).isPresent();
}
}
User.java
@Data
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
@NotEmpty(message = "Email should not be empty")
@Email(message = "Email should be valid")
@UniqueEmail(message = "Email address is already registered")
private String email;
@NotEmpty(message = "Password should not be empty")
private String password;
@NotEmpty(message = "Name should not be empty")
@Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters")
private String username;
private boolean enabled = true;
@Enumerated(value = EnumType.STRING)
private Role role;
}
UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
AuthController.java
@Controller
@RequestMapping("/auth")
public class AuthController {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
public AuthController(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@GetMapping("/login")
public String login(Principal principal) {
if(principal != null)
return "redirect:/";
return "auth/login";
}
@GetMapping("/register")
public String register(@ModelAttribute("user") User user, Principal principal) {
if(principal != null)
return "redirect:/";
return "auth/register";
}
@PostMapping("/register")
public String newCustomer(Principal principal, Model model, @ModelAttribute("user") @Valid User user, BindingResult bindingResult) {
if(principal != null)
return "redirect:/";
if(bindingResult.hasErrors())
return "auth/register";
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setRole(Role.CUSTOMER);
userRepository.saveAndFlush(user);
model.addAttribute("success", true);
model.addAttribute("user", new User());
return "auth/register";
}
}
如果我尝试输入现有的电子邮件,一切正常(收到消息“电子邮件地址已注册”)。但是,如果我尝试输入一封新电子邮件,我会收到错误消息“Servlet.service() for servlet [dispatcherServlet] in context with path [] throw exception [Request processing failed; nested exception is javax.validation.ValidationException: HV000064:无法实例化 ConstraintValidator:bla.bla.bla.validator.UniqueEmailValidator.] 具有根本原因。
我正在尝试使用@Component 和@Autowired,但得到了相同的结果。 我正在尝试使用 noArgs 构造函数并得到 NullPointerException(未注入 UserRepository)。
为什么?没看懂。
上述错误是因为您的 UniqueEmailValidator 的构造函数为空。 另见:javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator
您可以使用@Autowired 注释将 userRepository 注入您的约束验证器,如前所述:
- 此处:Inject Spring Beans into Annotation-based Bean Validator
- 这里:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#validation-beanvalidation-spring-constraints
另外请注意在所有相关的控制器方法User user之前加上@Valid注解
这样问题就解决了。我知道这是一个拐杖,但我还没有找到其他解决方案。
@Component
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
private UserRepository userRepository;
public UniqueEmailValidator() {
}
@Autowired
public UniqueEmailValidator(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
if(userRepository == null)
return true;
return email != null && !userRepository.findByEmail(email).isPresent();
}
}
添加了 noArgs 构造函数,并在 isValid 函数中添加了 ckeck if null userRepository。