【发布时间】:2018-02-16 17:04:02
【问题描述】:
我有一个 spring 项目,希望在数据库中的字段上强制执行唯一性并将错误消息返回给 UI。
我已经阅读了this SO answer,这是有道理的,所以@Column(unique = true) 对表进行了约束,但没有强制执行。
所以问题变成了如何创建一个@Unique 注解来检查数据库并在 POST 处理程序上将错误消息返回到 BindingResult。
举个例子就好了。
更新
我尝试了以下方法来制作自定义验证器:
对象(注意我添加了@valid 以获取验证器消息以导航到 BindingResult)
Person.java
@Entity
public class Person {
public Person() {}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// other stuff
@UniqueNid
private BigInteger nid;
EpisodePerson.java
@Entity
public class EpisodePerson {
public EpisodePerson(){};
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@Valid
private Person person;
EpisodeViewModel (DTO)
public class EpisodeViewModel {
@Valid
private Episode episode = new Episode();
@Valid
private List<EpisodePerson> persons = new ArrayList<>();
UniqueNid.java
@Documented
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueNiaValidator.class)
public @interface UniqueNid {
String message() default "{Duplicate ID}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
UniqueNidValidator.java
public class UniqueNidValidator implements ConstraintValidator<UniqueNid, BigInteger> {
public UniqueNidValidator(){};
private PersonRepository personRepository;
@Autowired
public void setPersonRepository(PersonRepository personRepository) {this.personRepository = personRepository;}
public UniqueNidValidator(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@Override
public void initialize(UniqueNid constraint) {
}
@Override
public boolean isValid(BigInteger nid, ConstraintValidatorContext context) {
return nid != null && personRepository.existsByNid(nid);
}
}
PersonRepository.java
...
Boolean existsByNid(BigInteger nid);
...
Application.java
@SpringBootApplication
@EnableAutoConfiguration(exclude = { org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class })
public class Demo3Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebApplicationInitializer.class);
}
public static void main(String[] args) {
SpringApplication.run(Demo3Application.class, args);
}
@Bean
public javax.validation.Validator localValidatorFactoryBean() {
return new LocalValidatorFactoryBean();
}
}
当我提交一个人时,我得到:
堆栈跟踪(缩写)
java.lang.NullPointerException: null
at com.example.validators.UniqueNidValidator.isValid(UniqueNidValidator.java:31) ~[main/:na]
更新 2
我也试过这个配置
public class UniqueNidValidator implements ConstraintValidator<UniqueNid, BigInteger> {
public UniqueNidValidator(){};
private PersonRepository personRepository;
public UniqueNidValidator(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@Override
public void initialize(UniqueNid constraint) {
}
@Override
public boolean isValid(BigInteger nid, ConstraintValidatorContext context) {
System.out.println("About to check " +nid.toString());
System.out.println("person repo " +personRepository.toString() );
return personRepository.existsByNid(nid);
}
}
给出:
java.lang.NullPointerException: null
at com.example.validators.UniqueNiaValidator.isValid(UniqueNiaValidator.java:29) ~[main/:na]
当我尝试将 repo 打印到控制台时。
【问题讨论】:
-
第 31 行到底是什么代码?看起来
personRepository没有注入,因此现在是null。尝试找出它发生的原因。 -
另外你为什么要创建
LocalValidatorFactoryBean?为什么不让 Spring 为您引导它? -
ln31: return nid != null && personRepository.existsByNid(nid);如果我在测试评估(正确)为真时单步执行代码。
-
我想答案可能在这个:stackoverflow.com/questions/24955817/…
-
在这种情况下,解决此问题的一种方法是拆分实体和 dto。
标签: spring-boot spring-data-jpa bean-validation hibernate-validator