英文:
how do I solve the ConstraintViolationException in Spring Boot
问题
以下是翻译好的部分:
我在Spring Boot中编写了自定义验证。这个自定义验证旨在检查两个字段是否匹配。一切都很正常,直到我尝试提交表单。突然间,我遇到了这个错误:
javax.validation.ConstraintViolationException: Validation failed for classes [com.joker.SampleAuthenticationWebApp.model.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='Passwords do not match!', propertyPath=con_password, rootBeanClass=class com.joker.SampleAuthenticationWebApp.model.User, messageTemplate='Passwords do not match!'}
]
这个问题真的妨碍了我的学习进度。非常感谢你的帮助。
PS: 我在 Stack Overflow 上搜寻了解决方案,但都没有成功。
注解:
package com.joker.SampleAuthenticationWebApp.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = FieldsValueMatchValidator.class)
public @interface FieldsValueMatch {
String message() default "Fields values don't match!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
String fieldMatch();
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@interface List {
FieldsValueMatch[] value();
}
}
验证器:
package com.joker.SampleAuthenticationWebApp.validator;
import com.joker.SampleAuthenticationWebApp.model.User;
import org.springframework.beans.BeanWrapperImpl;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldsValueMatchValidator implements ConstraintValidator<FieldsValueMatch, Object> {
private String field;
private String fieldMatch;
@Override
public void initialize(FieldsValueMatch constraintAnnotation) {
this.field = constraintAnnotation.field();
this.fieldMatch = constraintAnnotation.fieldMatch();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
final Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field);
final Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch);
boolean isValid = fieldValue == null && fieldMatchValue == null || fieldValue != null && fieldValue.equals(fieldMatchValue);
if (!isValid) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addPropertyNode(fieldMatch).addConstraintViolation();
return false;
}
return isValid;
}
catch (final Exception ignore) {
// ignore
}
return true;
}
}
用户模型:
package com.joker.SampleAuthenticationWebApp.model;
import com.joker.SampleAuthenticationWebApp.validator.FieldsValueMatch;
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Set;
@Entity
@Table(name = "auth_user")
@FieldsValueMatch(field = "password", fieldMatch = "con_password", message = "Passwords do not match!")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
@Column(name = "auth_user_id", unique = true)
private int id;
@NotNull
@NotEmpty(message = "First name is compulsory")
@Column(name = "firstname")
private String firstname;
// ... 其他属性 ...
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
英文:
I wrote a custom validation in spring boot. The custom validation is meant to check if two fields match. Everything works fine until i try to submit the form. Boom i experience the error:
javax.validation.ConstraintViolationException: Validation failed for classes [com.joker.SampleAuthenticationWebApp.model.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='Passwords do not match!', propertyPath=con_password, rootBeanClass=class com.joker.SampleAuthenticationWebApp.model.User, messageTemplate='Passwords do not match!'}
]
This problem has really hindered my learning progress. Your help would be very much appreciated.<br><br>
PS: I've Scraped SO in search of a solution but all was to no avail.<br><br>The Annotation:
package com.joker.SampleAuthenticationWebApp.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = FieldsValueMatchValidator.class)
public @interface FieldsValueMatch {
String message() default "Fields values don't match!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
String fieldMatch();
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@interface List {
FieldsValueMatch[] value();
}
}
The Validator:
package com.joker.SampleAuthenticationWebApp.validator;
import com.joker.SampleAuthenticationWebApp.model.User;
import org.springframework.beans.BeanWrapperImpl;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldsValueMatchValidator implements ConstraintValidator<FieldsValueMatch, Object> {
private String field;
private String fieldMatch;
@Override
public void initialize(FieldsValueMatch constraintAnnotation) {
this.field = constraintAnnotation.field();
this.fieldMatch = constraintAnnotation.fieldMatch();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
final Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field);
final Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch);
boolean isValid = fieldValue == null && fieldMatchValue == null || fieldValue != null && fieldValue.equals(fieldMatchValue);
if (!isValid) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addPropertyNode(fieldMatch).addConstraintViolation();
return false;
}
return isValid;
}
catch (final Exception ignore) {
// ignore
}
return true;
}
}
The User Model:
package com.joker.SampleAuthenticationWebApp.model;
import com.joker.SampleAuthenticationWebApp.validator.FieldsValueMatch;
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Set;
@Entity
@Table(name = "auth_user")
@FieldsValueMatch(field = "password", fieldMatch = "con_password", message = "Passwords do not match!")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
@Column(name = "auth_user_id", unique = true)
private int id;
@NotNull
@NotEmpty(message = "First name is compulsory")
@Column(name = "firstname")
private String firstname;
@NotNull
@NotEmpty(message = "Last name is compulsory")
@Column(name = "lastname")
private String lastname;
@NotNull
@NotEmpty(message = "Email is compulsory")
@Email
@Column(name = "email")
private String email;
@NotNull
@Column(name = "phone")
private String phone;
@NotNull
@NotEmpty(message = "Password is compulsory")
@Length(min = 5, message = "Password length should be at least 5 characters")
@Column(name = "password")
private String password;
@NotEmpty(message = "Confirm Password field is compulsory")
@Transient
private String con_password;
@NotNull
@Column(name = "enabled")
private int enabled;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "auth_user_role", joinColumns = @JoinColumn(name = "auth_user_id"), inverseJoinColumns = @JoinColumn(name = "auth_role_id"))
private Set<Role> roles;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCon_password() {
return con_password;
}
public void setCon_password(String con_password) {
this.con_password = con_password;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
this.enabled = enabled;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
答案1
得分: 0
我也遇到了这个问题。解决这个问题的唯一方法是在你的控制器类上包含 @ModelAttribute 和 @Valid 的注解,用于要检查的 bean 上,条件是要检查 @FieldsValueMatch(field = "password", fieldMatch = "con_password", message = "密码不匹配!") 是否为真,之后在你要检查的 bean 之后包含 BindingResult。检查 BindigResult 是否有错误,并返回接下来的步骤。
示例代码:
@PostMapping("/signup")
public String signup(@ModelAttribute(name = "user") @Valid User user, BindingResult result, Model model)
if (result.hasErrors())
return "signup_form";
希望这清楚明了。
英文:
I experienced this problem too . The only way to solve this is to include the annotations of @ModelAttribute and @Valid on your controller class for the bean you want to check weather the condition of @FieldsValueMatch(field = "password", fieldMatch = "con_password", message = "Passwords do not match!") is true , after that include the BindingResult right after the bean you want to check . Check if BindigResult hasErrors(), and return what is your next step .
EX:
@PostMapping("/signup")
<br>
public String signup(@ModelAttribute(name = "user") @Valid User user,BindingResult result,Model model)
<br>
if (result.hasErrors())
<br>
return "signup_form";
<br>
Hope this is clear .
专注分享java语言的经验与见解,让所有开发者获益!
评论