繁体   English   中英

无法提交JPA交易; 嵌套异常为javax.persistence.RollbackException:提交事务时出错

[英]Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction

尝试在数据库中插入用户时出现错误。

我做了一个自定义注释,当字段不匹配时,验证密码是否与确认密码匹配,但是当passowrd匹配时,我出现此错误:

在此处输入图片说明

这是我的代码这是我的田径比赛@Annotation:

package mereuta.marian.tennis01.annotations;


import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = FieldsValueMatchValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldsValueMatch {

    String message() default "Fields values don't match!";

    String field();

    String fieldMatch();

    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    @Target({ ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @interface List {
        FieldsValueMatch[] value();
    }
}

这是字段验证器:

package mereuta.marian.tennis01.annotations;

import mereuta.marian.tennis01.model.Utilisateur;
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 fieldsValueMatch) {
        this.field=fieldsValueMatch.field();
        this.fieldMatch=fieldsValueMatch.fieldMatch();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {


        Object fieldValue = new BeanWrapperImpl(value)
                .getPropertyValue(field);
        Object fieldMatchValue = new BeanWrapperImpl(value)
                .getPropertyValue(fieldMatch);

        if (fieldValue != null) {
            return fieldValue.equals(fieldMatchValue);
        } else {
            return fieldMatchValue == null;
        }
    }
}

这是我的实体:

@FieldsValueMatch(field = "password", fieldMatch = "confirmPassword", 
message = "Password do not match!")
@Entity(name = "utilisateurs")
public class Utilisateur {
    @Id @GeneratedValue
    @Column(name = "id_utilisateur")
    private Integer id;
    @NotNull
    @Size(min = 4, max = 255)
    @Column(name = "password")
    private String password;
    @Transient
    @NotNull
    private String confirmPassword;

这是控制器:

@PostMapping("/addUtilisateur")
    public String addUtilisateur(@Valid @ModelAttribute("utilisateur") Utilisateur utilisateur, BindingResult bindingResult, Model model) {


        if (bindingResult.hasErrors() ) {
            model.addAttribute("message", "le mot de passe ne correspond pas");
            return "utilisateur/formRegister";
        }


        utilisateurMetier.creerUtilisateur(utilisateur);

        return "utilisateur/utilisateurAjoute";


    }

最后是视图:

<div class="container">
        <form id="contact" th:action="@{addUtilisateur}" method="post" th:object="${utilisateur}">
            <h3>Créer compte</h3>


                <input placeholder="password" type="password" th:field="*{password}" tabindex="2" required/>
                <span class="text text-danger" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></span>

            </fieldset>


            <fieldset>

                <input placeholder="password" type="password" th:field="*{confirmPassword}" tabindex="2" required/>
                <span class="text text-danger" th:if="${#fields.hasErrors('confirmPassword')}"
                      th:errors="*{confirmPassword}" th:text="${message}"></span>


            </fieldset>

对于自定义注释,我在以下位置找到示例: https : //www.baeldung.com/spring-mvc-custom-validator

@Override
    public void creerUtilisateur(Utilisateur utilisateur) {

        Role role;
        float credit = 0;
        boolean actif = true;

        role = roleRepository.getOne(3);


        System.out.println(role);

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();


        utilisateur.setPassword(encoder.encode(utilisateur.getPassword()));

        utilisateur.setRole(role);
        utilisateur.setCredit(credit);
        utilisateur.setActif(actif);


        utilisateurRepository.save(utilisateur);
    }

预先感谢您的帮助

如前所述,ContraintViolationException抛出在“ creerUtilisateur”方法内部。 因此,当两个字段(密码,confirmPassword)具有相同的值时,对Utilisateur Bean的验证在传递给Spring MVC控制器方法( addUtilisateur(@Valid @ModelAttribute("utilisateur")... )时就可以正常工作。 ,您可以对密码进行编码并更改Utilitsateur的“ password”实例变量的值:

utilisateur.setPassword(encoder.encode(utilisateur.getPassword()));

现在,“ password”和“ passwordConfirm”不再相等了! 当将该实体保留在utilisateurRepository.save(utilisateur); JPA将再次对您的实体进行bean验证,然后再将其保存到数据库中(预持久化)。 当JPA / Hibernate触发预持久,预更新或预删除生命周期事件时,将自动执行验证。 然后抛出ContraintViolationException!

在您的creerUtilisateur方法中,只需为实例变量'password'和'passwordConfirm'设置编码密码,从而确保它们仍通过FieldsValueMatchValidator.isValid(Object value, ConstraintValidatorContext context)相等性检查:

 BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
 final String encodedPassword = encoder.encode(utilisateur.getPassword());
 utilisateur.setPassword(encodedPassword);
 utilisateur.setPasswordConfirm(encodedPassword);
 //...
 utilisateurRepository.save(utilisateur);

您还可以尝试自定义JPA的Bean验证行为:

https://www.thoughts-on-java.org/automatically-validate-entities-with-hibernate-validator/

对合并/更新禁用休眠验证

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM