当前位置: 首页 > 面试题库 >

JSR303自定义验证器被调用两次

呼延明朗
2023-03-14
问题内容

我正在使用Spring MVC创建一个网站,并且为了持久性,我将Spring Data JPA与Hibernate
4用作我的JPA提供程序。目前正在使用Hibernate
Validator处理验证。我有一个问题,我的验证程序被两次调用,我不知道为什么。这是一个问题的主要原因是因为第二轮未将依赖项自动关联到验证器中,并且出现了空指针异常。以下是导致失败的调用顺序:

  1. 提交注册表,然后首先调用NotDefaultSectValidator并成功完成用户对象上的“ whereDidYouHearAboutUs”字段。
  2. 接下来将调用UniqueUsernameValidator,并成功完成“用户名”字段验证。
  3. 控制器上的“ addUserFromForm”方法启动,并且在bindingResults对象中未发现任何错误。
  4. 然后在UserService类上调用’addUser’方法。此方法到达“ userRepository.save(user);”行。但以后再也不要立即运行’print.ln’行。跨过此行将回到“ NotDefaultSectValidator”断点。这是第二次完成,我将再次输入第二个验证器“ UniqueUsernameValidator”。在这里,我得到了一个空指针异常,因为由于某种原因,Spring这次第二次未能在DAO中自动连线。

任何人都可以阐明为什么两次调用验证程序,特别是为什么要跳过“ userRepository.save(user);”行吗?回到这些验证器?

非常感谢

这是我的user.java类

package com.dating.domain;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;

import com.dating.annotation.NotDefaultSelect;
import com.dating.annotation.UniqueUsername;

@Entity
@Table(name = "dating.user")
public class User {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "username", unique = true)
    @NotEmpty
    @Pattern(regexp = "^[a-zA-Z0-9]*$")
    @UniqueUsername
    private String username;

    @Column(name = "password", nullable = false)
    @NotEmpty
    @Size(min = 8)
    private String password;

    @Column(name = "first_name", nullable = false)
    @NotEmpty
    private String firstName;

    @Column(name = "last_name", nullable = false)
    @NotEmpty
    private String lastName;

    @Transient
    private String fullName;

    @Column(name = "email", nullable = false)
    @NotEmpty
    @Email
    private String email;

    @Column(name = "gender", nullable = false)
    @NotEmpty
    private String gender;

    @Column(name = "date_of_birth", nullable = false)
    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
    @DateTimeFormat(pattern = "dd/MM/yyyy")
    private LocalDate dateOfBirth;

    @Column(name = "join_date", nullable = false)
    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
    private LocalDate joinDate;

    @Column(name = "where_did_you_hear_about_us", nullable = false)
    @NotDefaultSelect
    private String whereDidYouHearAboutUs;

    @Column(name = "enabled")
    private boolean enabled;

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "dating.user_roles", joinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
    private Set<Role> roles = new HashSet<Role>();

    @Column(name = "created_time", nullable = false)
    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
    private LocalDate createdTime;

    @Column(name = "modification_time", nullable = false)
    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
    private LocalDate modificationTime;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    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 getFullName() {
        return firstName + " " + lastName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    public LocalDate getJoinDate() {
        return joinDate;
    }

    public void setJoinDate(LocalDate joinDate) {
        this.joinDate = joinDate;
    }

    public String getWhereDidYouHearAboutUs() {
        return whereDidYouHearAboutUs;
    }

    public void setWhereDidYouHearAboutUs(String whereDidYouHearAboutUs) {
        this.whereDidYouHearAboutUs = whereDidYouHearAboutUs;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    public void addRole(Role role) {
        roles.add(role);
    }

    public LocalDate getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(LocalDate createdTime) {
        this.createdTime = createdTime;
    }

    public LocalDate getModificationTime() {
        return modificationTime;
    }

    public void setModificationTime(LocalDate modificationTime) {
        this.modificationTime = modificationTime;
    }

    @PreUpdate
    public void preUpdate() {
        modificationTime = new LocalDate();
    }

    @PrePersist
    public void prePersist() {
        LocalDate now = new LocalDate();
        createdTime = now;
        modificationTime = now;
    }
}

我的注册控制器中的相关方法:

@RequestMapping(value = "/register", method = RequestMethod.POST)
public String addUserFromForm(@Valid User user,
        BindingResult bindingResult, RedirectAttributes ra) {
    if (bindingResult.hasErrors()) {
        return "user/register";
    }
    userService.addUser(user);

    // Redirecting to avoid duplicate submission of the form
    return "redirect:/user/" + user.getUsername();
}

我的服务等级:

package com.dating.service.impl;

import javax.transaction.Transactional;

import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.dating.domain.Role;
import com.dating.domain.User;
import com.dating.repository.RoleRepository;
import com.dating.repository.UserRepository;
import com.dating.repository.specification.UserSpecifications;
import com.dating.service.UserService;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Transactional
    @Override
    public void addUser(User user) {
        user.setJoinDate(new LocalDate());
        user.setEnabled(true);
        Role role = roleRepository.findByName(Role.MEMBER);
        if (role == null) {
            role = new Role();
            role.setName(Role.MEMBER);
        }
        user.addRole(role);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPassword(encoder.encode(user.getPassword()));
        userRepository.save(user);
        System.out.println("User Saved");
    }

    @Override
    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @Override
    public Iterable<User> getAllUsers() {
        return userRepository.findAll();
    }

    @Override
    public void updateDetails(User user) {
        userRepository.save(user);
    }

    @Override
    public Iterable<User> lastNameIsLike(String searchTerm) {
        return userRepository.findAll(UserSpecifications
                .lastNameIsLike(searchTerm));
    }
}

我的NotDefaultSelect验证器:

package com.dating.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import com.dating.annotation.NotDefaultSelect;

public class NotDefaultSelectValidator implements
        ConstraintValidator<NotDefaultSelect, String> {
    @Override
    public void initialize(NotDefaultSelect constraint) {

    }

    @Override
    public boolean isValid(String selectedValue, ConstraintValidatorContext ctx) {
        if (selectedValue == null) {
            return false;
        }
        if (selectedValue.equals("") || selectedValue.equals("0")
                || selectedValue.equalsIgnoreCase("default")
                || selectedValue.equalsIgnoreCase("please select")) {
            return false;
        }
        return true;
    }

}

我的uniqueUsername验证器:

package com.dating.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;

import com.dating.annotation.UniqueUsername;
import com.dating.repository.UserRepository;

public class UniqueUsernameValidator implements
        ConstraintValidator<UniqueUsername, String> {

    @Autowired
    private UserRepository userRepository;

    @Override
    public void initialize(UniqueUsername constraint) {

    }

    @Override
    public boolean isValid(String username, ConstraintValidatorContext ctx) {
        if (username == null || userRepository.findByUsername(username) == null) {
            return true;
        }
        return false;
    }

}

我的用户资料库:

package com.dating.repository;

import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;

import com.dating.domain.User;

//Spring Data JPA Marker interfaces being extended for automatic CRUD repository creation
public interface UserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor<User> {

    //Automatic query creation from method name
    public User findByUsername(String username);
}

最后是我的persistence-context.xml文件

<!-- Data source properties -->
<util:properties id="dataSourceSettings" location="classpath:datasource.properties" />

<!-- Pooled data source using BoneCP -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"
    destroy-method="close">
    <property name="driverClass" value="#{dataSourceSettings['jdbc.driverClass']}" />
    <property name="jdbcUrl" value="#{dataSourceSettings['jdbc.url']}" />
    <property name="username" value="#{dataSourceSettings['jdbc.username']}" />
    <property name="password" value="#{dataSourceSettings['jdbc.password']}" />
    <property name="idleConnectionTestPeriodInMinutes" value="60" />
    <property name="idleMaxAgeInMinutes" value="240" />
    <property name="maxConnectionsPerPartition" value="30" />
    <property name="minConnectionsPerPartition" value="10" />
    <property name="partitionCount" value="3" />
    <property name="acquireIncrement" value="5" />
    <property name="statementsCacheSize" value="100" />
    <property name="releaseHelperThreads" value="3" />
</bean>

<!-- JPA entity manager factory bean -->
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.dating.domain" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">#{dataSourceSettings['hibernate.dialect']}</prop>
            <prop key="hibernate.hbm2ddl.auto">#{dataSourceSettings['hibernate.hbm2ddl.auto']}
            </prop>
            <prop key="hibernate.show_sql">#{dataSourceSettings['hibernate.show_sql']}</prop>
            <prop key="hibernate.format_sql">#{dataSourceSettings['hibernate.format_sql']}</prop>
            <prop key="hibernate.use_sql_comments">#{dataSourceSettings['hibernate.use_sql_comments']}
            </prop>
        </props>
    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<context:annotation-config />

<jpa:repositories base-package="com.dating.repository"/>

问题答案:

当您将bean发送到数据存储区时,也许第二次验证是由休眠完成的。要关闭它,请将其添加到您的persistence.xml中:

<property name="javax.persistence.validation.mode" value="none"/>

https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/configuration.html说:

默认情况下,Bean验证(和休眠验证器)被激活。创建,更新(和可选地删除)实体后,在将其发送到数据库之前先对其进行验证。Hibernate生成的数据库模式还反映了在实体上声明的约束。

您可以根据需要进行微调:

自动:如果在类路径中存在Bean验证,则激活CALLBACK和DDL。

回调:实体在创建,更新和删除时均经过验证。如果不存在Bean验证提供程序,则在初始化时引发异常。

DDL :(不是标准的,请参见下文)数据库架构是在创建,更新和删除时经过验证的实体。如果不存在Bean验证提供程序,则在初始化时引发异常。

无:完全不使用Bean验证

由于@Valid批注,第一个显然是由您的Spring控制器完成的。



 类似资料:
  • null 有人能解释为什么要调用验证器两次,特别是为什么要跳过“userrepository.save(user);”回到这些验证器里? 多谢 下面是我的user.java类 我的用户存储库: 最后,我的persistence-context.xml文件

  • 我有一个像下面这样的模型对象,带有自定义约束验证器。自定义验证器检查是否填充了fileName或小时。 有一种方法将此作为输入,它验证所有以下条件 > 条件不为空(通过默认验证器) criteria.id不为空(通过默认验证器) criteria.name不为空(通过默认验证器) 标准文件名或小时不为空(通过自定义验证器) 空评估(@NotNull@有效标准标准){} 现在,当我为这个模型类编写单

  • 主要内容:自定义验证器类实例我们可以在JSF中创建自己的自定义验证器。以下列表是在JSF中创建自定义验证器的步骤。 通过实现接口创建一个验证器类。 实现上面接口的方法。 使用注释为自定义验证器分配唯一的ID。 自定义验证器类实例 打开 NetBeans IDE 创建一个Web工程:CustomValidator,其目录结构如下所示 - 创建以下文件代码,文件:index.xhtml 的代码内容如下所示 - 文件:result

  • 我正努力在我的Android应用程序中实现一个自定义验证器。我想在列表视图中显示一些从服务器检索到的建议(它可以正常工作),即使在我的AutoCompleteTextView中不以相同的字母开头。 所以,也就是说,如果我写“n”,我希望得到服务器响应,它是“r”。因此,我尝试实现一个验证器,设置示例,该示例控制服务器响应是否为空。 建议?提前致谢

  • 我们可以在JSF中创建自己的Custom验证器。 在JSF中定义自定义验证器分为三个步骤。 步 描述 1 通过实现javax.faces.validator .Validator接口创建验证器类。 2 实现上述接口的validate()方法。 3 使用注释@FacesValidator为自定义验证程序分配唯一ID。 步骤1:创建Validator类:UrlValidator.java public

  • 我创建了一个自定义约束验证器,用于检查用户名的验证,验证器正在访问数据库并检查记录是否已存在以及是否符合正则表达式。我收到相当奇怪的错误,因为如果用户名已经存在,验证器可以正常工作,但是当输入有效输入(不存在的用户名)时,它会抛出一个 NullPointerException。 我放置了一个计数器和一些语句来跟踪应用程序崩溃的位置,我将在堆栈跟踪中包括这些。应用程序似乎正在调用和方法两次,第二次是