gpt4 book ai didi

java - JSR303 自定义 validator 被调用两次

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:48:30 25 4
gpt4 key购买 nike

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

  1. 提交注册表单,首先调用 NotDefaultSectValidator 并成功完成用户对象上的“whereDidYouHearAboutUs”字段。
  2. 接下来调用 UniqueUsernameValidator 并成功完成“用户名”字段验证。
  3. Controller 上的“addUserFromForm”方法启动并在 bindingResults 对象中发现没有错误。
  4. 然后在 UserService 类上调用“addUser”方法。此方法到达“userRepository.save(user);”行但之后绝不会立即运行“print.ln”行。跨过这条线将返回到“NotDefaultSectValidator”断点。这是第二次完成,我重新输入第二个 validator “UniqueUsernameValidator”。在这里我得到一个空指针异常,因为出于某种原因,Spring 第二次未能在 DAO 中 Autowiring 。

谁能阐明为什么 validator 被调用两次,特别是为什么越过“userRepository.save(user);”行回到这些 validator ?

非常感谢

这是我的 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;
}
}

我的注册 Controller 中的相关方法:

@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 validator :

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;
}

}

我的唯一用户名 validator :

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 发送到数据存储区时由 hibernate 完成的。要关闭它,请将其添加到您的 persistence.xml 中:

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

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

By default, Bean Validation (and Hibernate Validator) is activated. When an entity is created, updated (and optionally deleted), it is validated before being sent to the database. The database schema generated by Hibernate also reflects the constraints declared on the entity.

You can fine-tune that if needed:

AUTO: if Bean Validation is present in the classpath, CALLBACK and DDL are activated.

CALLBACK: entities are validated on creation, update and deletion. If no Bean Validation provider is present, an exception is raised at initialization time.

DDL: (not standard, see below) database schemas are entities are validated on creation, update and deletion. If no Bean Validation provider is present, an exception is raised at initialization time.

NONE: Bean Validation is not used at all

由于@Valid 注释,第一个显然是由您的 Spring Controller 完成的。

关于java - JSR303 自定义 validator 被调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24955817/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com