============================== right code
My code use dto "student" to verify.
student dto
@Getter
@Setter
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private Integer grade;
}
StudentValidator
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
@Component
public class StudentValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
boolean result = Student.class.equals(clazz);
return result;
}
@Override
public void validate(Object target, Errors errors) {
Student student = (Student) target;
ValidationUtils.rejectIfEmpty(errors, "name","name must not be empty");
}
}
StudentValidator2. if having error, not to validate.
@Component
public class StudentValidator2 implements Validator {
@Autowired
private MessageSource messageSource;
@Override
public boolean supports(Class<?> clazz) {
boolean result = Student.class.equals(clazz);
return result;
}
@Override
public void validate(Object target, Errors errors) {
if(errors.hasErrors()){ // if having error, not go ahead
return ;
}
Student student = (Student) target;
if (student.getGrade() <= 0) {
errors.rejectValue("grade", "grade must be more than 0");
}
}
}
StudentController
@RestController("/")
public class StudentController {
@Autowired
private StudentValidator studentValidator;
@Autowired
private StudentValidator2 studentValidator2;
@InitBinder(value = "student")
void initStudentValidator(WebDataBinder binder) {
binder.addValidators(studentValidator, studentValidator2);
}
@PostMapping("/student")
public ResponseEntity<Student> saveStudent(@RequestBody @Valid Student student) {
// Other logic here(Calling the service layer,etc.)
return new ResponseEntity<>(student, HttpStatus.CREATED);
}
}
use postMan to do post to "/student" and no params. Its response as below
{
"status": "BAD_REQUEST",
"error": "Validation failed",
"count": 1,
"errors": [
"name must not be empty"
]
}
======================================= the below is not right
I think you should use WebDataBinder and Override validate() method to implement it. Please ref here. The below I give some pseudocode
- create a customized WebDataBinder called MyWebDataBinder. In that, override validate() method.
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
@Component
public class MyWebDataBinder extends WebDataBinder {
public MyWebDataBinder(Object target) {
super(target);
}
public MyWebDataBinder(Object target, String objectName) {
super(target, objectName);
}
@Override
public void validate() {
Object target = getTarget();
Assert.state(target != null, "No target to validate");
BindingResult bindingResult = getBindingResult();
// Call each validator with the same binding result
for (Validator validator : getValidators()) {
validator.validate(target, bindingResult);
if(bindingResult.hasErrors()) // jump out when if having error
break;
}
}
}
- in your controller, inject MyWebDataBinder and Validator1 & Validator2
@Controller
public class CustomerController {
@Autowired
Validator1 validator1
@Autowired
Validator2 validator2
@InitBinder(value = "car")
void initCarValidator(@Qualifier("myWebDataBinder")WebDataBinder binder) {
binder.addValidators(validator1);
binder.addValidators(validator2);
}
@RequestMapping(value = "....", method = RequestMethod.POST)
public void validateCar(@Valid @RequestBody Car car) {
// .... your code
}