【发布时间】:2022-07-13 17:38:48
【问题描述】:
我正在构建一个 Spring Boot 应用程序,并尝试为我将在服务层中验证的一些 DTO/实体实现自定义验证。基于Spring documentation on this matter,我认为一种方法是实现org.springframework.validation.Validator接口。
作为一个最小的、完整的、可重现的示例,请考虑以下代码:
Spring Initializr Bootstrapped Project
在src/main/java/com.example.usingvalidation中添加以下代码:
// Person.java
package com.example.usingvalidation;
public class Person {
private String firstName;
private String lastName;
private int age;
private String gender;
public Person() {
}
public Person(String firstName, String lastName, int age, String gender) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.gender = gender;
}
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
// PersonValidator.java
package com.example.usingvalidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
@Component
public class PersonValidator implements Validator {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public boolean supports(Class<?> clazz) {
log.info("supports called");
return Person.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
log.info("validate called");
Person person = (Person) target;
errors.reject("E00001", "This is the default error message, just to test.");
}
}
// MyController.java
package com.example.usingvalidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.ConstraintViolation;
import java.util.Set;
@RestController
public class MyController {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final LocalValidatorFactoryBean validatorFactory;
@Autowired
public MyController(LocalValidatorFactoryBean validatorFactory) {
this.validatorFactory = validatorFactory;
}
@GetMapping("/")
public Person getPerson(@RequestBody Person person) {
log.info("calling validate");
Set<ConstraintViolation<Person>> errors = validatorFactory.validate(person);
log.info("called validate, result: {}", errors);
return null;
}
}
// UsingValidationApplication.java nothing changed here
package com.example.usingvalidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final LocalValidatorFactoryBean validatorFactory;
@Autowired
public MyController(LocalValidatorFactoryBean validatorFactory) {
this.validatorFactory = validatorFactory;
}
@GetMapping("/")
public Person getPerson(@RequestBody Person person) {
log.info("calling validate");
validatorFactory.validate(person);
return null;
}
}
如果我点击端点来触发验证,什么都不会发生。我看到了calling validate 日志消息。但是错误对象是空的。
PersonValidater 中的任何日志消息都没有被记录,因此显然没有呼叫到达那里。
我的问题是:我如何注册我的验证器到 Spring 以便我可以使用验证器?
我已多次阅读文档和数百个 SO 问题(如 java - Implementing custom validation logic for a spring boot endpoint using a combination of JSR-303 and Spring's Validator - Stack Overflow),但无济于事。
附加信息
- 如果有任何 JSR-303 注释,如
@NotNull,则当前设置将拾取与 JSR-303 验证相关的错误。但这不是我需要的,我需要它来使用我的自定义验证器。 - 我看到了其他 SO 问题,其中
InitBinder在控制器中用于向 Spring 注册验证器。但我不想这样做,因为我计划在服务层中进行这些自定义验证。
【问题讨论】:
-
"var person" 是可怕的语法。
-
@K.Nicholas 感谢您的反馈。你能详细说明为什么它不好吗?
标签: java spring spring-boot spring-mvc