我如何解决 Spring Boot 中的 ConstraintViolationException 问题

huangapple 未分类评论44阅读模式
英文:

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=&#39;Passwords do not match!&#39;, propertyPath=con_password, rootBeanClass=class com.joker.SampleAuthenticationWebApp.model.User, messageTemplate=&#39;Passwords do not match!&#39;}
]

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 &quot;Fields values don&#39;t match!&quot;;

    Class&lt;?&gt;[] groups() default {};

    Class&lt;? extends Payload&gt;[] 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&lt;FieldsValueMatch, Object&gt; {
    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 &amp;&amp; fieldMatchValue == null || fieldValue != null &amp;&amp; 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 = &quot;auth_user&quot;)
@FieldsValueMatch(field = &quot;password&quot;, fieldMatch = &quot;con_password&quot;, message = &quot;Passwords do not match!&quot;)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = &quot;native&quot;)
    @Column(name = &quot;auth_user_id&quot;, unique = true)
    private int id;

    @NotNull
    @NotEmpty(message = &quot;First name is compulsory&quot;)
    @Column(name = &quot;firstname&quot;)
    private String firstname;

    @NotNull
    @NotEmpty(message = &quot;Last name is compulsory&quot;)
    @Column(name = &quot;lastname&quot;)
    private String lastname;

    @NotNull
    @NotEmpty(message = &quot;Email is compulsory&quot;)
    @Email
    @Column(name = &quot;email&quot;)
    private String email;

    @NotNull
    @Column(name = &quot;phone&quot;)
    private String phone;

    @NotNull
    @NotEmpty(message = &quot;Password is compulsory&quot;)
    @Length(min = 5, message = &quot;Password length should be at least 5 characters&quot;)
    @Column(name = &quot;password&quot;)
    private String password;

    @NotEmpty(message = &quot;Confirm Password field is compulsory&quot;)
    @Transient
    private String con_password;

    @NotNull
    @Column(name = &quot;enabled&quot;)
    private int enabled;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = &quot;auth_user_role&quot;, joinColumns = @JoinColumn(name = &quot;auth_user_id&quot;), inverseJoinColumns = @JoinColumn(name = &quot;auth_role_id&quot;))
    private Set&lt;Role&gt; 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&lt;Role&gt; getRoles() {
        return roles;
    }

    public void setRoles(Set&lt;Role&gt; 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 .

huangapple
  • 本文由 发表于 2020年4月9日 18:51:06
  • 转载请务必保留本文链接:https://java.coder-hub.com/61119456.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定