Spring mvc nested model validation

I have two models: User,Project

 public class Project{ private int id; @NotEmpty(message="Project Name can not be empty") private String name; private User manager; private User operator; //getter/setter omitted } public class User{ private int id; private String name; //omit other properties and getter/setter } 

Now, when I create a new project, I will send the following parameters to ProjectController:

projects?name=jhon&manager.id=1&operator.id=2...

Then I will create a new project object and paste it into db.

However, I need to check the manager identifier, and the statement is valid to say that I will check this if there is a mapped identifier in the user table.

So, I want to know how to implement such validation?


update1: using validator

This is the form for creating a new project:

 <sf:form method="${project.id==0?'post':'put'}" commandName="project" action="${context}${action}"> Manager:<sf:input path="manager.id" /> <sf:errors path="manager.id" /> <br /> Operator:<sf:input path="operator.id" /> <sf:errors path="operator.id" /> <br /> Name:<sf:input path="name" /> <sf:errors path="name" /> <br /> <input type="submit" value="Submit" /> </sf:form> @Override public void validate(Object obj, Errors errors) { User user = (User) obj; int id=user.getId(); User u=userDao.query(id); if(u==null){ errors.rejectValue("id", "user does not exist!"); } } 

This validator seems to work.

However, the error message cannot be displayed on the form.

Then, although debug I check the result object, and I found this:

 org.springframework.validation.BeanPropertyBindingResult: 2 errors Field error in object 'project' on field 'id': rejected value [0]; codes [user does not exist!.project.id,user does not exist!.id,user does not exist!.int,user does not exist!]; arguments []; default message [null] Field error in object 'project' on field 'id': rejected value [0]; codes [user does not exist!.project.id,user does not exist!.id,user does not exist!.int,user does not exist!]; arguments []; default message [null] 

It seems that the result has errors, but its path is project.id , whereas in my form it is project.manager.id

How to fix?

+4
source share
4 answers

Here is one possible solution.

Create a class below:

 ... import org.springframework.validation.Validator; ... @Component public class ProjectValidator implements Validator { @Override public boolean supports(Class<?> clazz) { return Project.class.equals(clazz); } @Override public void validate(Object target, Errors errors) { Project project = (Project) target; /* Do your checks here */ ... if (managerIdDoesNotMatch) { errors.rejectValue("manager.id", "your_error_code"); } ... if (operatorIdDoesNotMatch) { errors.rejectValue("operator.id", "your_error_code"); } ... } } 

And in your controller do something like:

 ... public class ProjectController { @Autowired ProjectValidator projectValidator; ... @RequestMapping(...) public String yourCreateMethod(..., @ModelAttribute @Valid Project project, BindingResult result) { projectValidator.validate(project, result); if (result.hasErrors()){ // do something } else { // do something else } } } 

This should help you get started. You could create / install the validator in different ways, have a custom sub-validator, but you get the general idea.

References:

+3
source

Actually you need to add @Valid on

 private User manager; private User operator; 

like this

 @Valid private User manager; @Valid private User operator; 
+2
source

In your controller, you can add a custom validator:

 @InitBinder protected void initBinder(WebDataBinder binder) { binder.setValidator(new ProjectValidator()); } 

In this validator, you can check User objects or delegate to UserValidator , as is done here in the last paragraph before section 6.3

+1
source

I did what Jerome Dalbert suggested and added an additional custom BeanValidator to delegate the actual work of verifying the implementation of the JSR 303.

The prefix is ​​used to denote the property path in the form.

 @Component public class BeanValidator implements org.springframework.validation.Validator, InitializingBean { private Validator validator; public void afterPropertiesSet() throws Exception { ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); validator = validatorFactory.usingContext().getValidator(); } public boolean supports(Class clazz) { return true; } public void validate(Object target, Errors errors, String prefix) { Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target); for (ConstraintViolation<Object> constraintViolation : constraintViolations) { String propertyPath = constraintViolation.getPropertyPath().toString(); String message = constraintViolation.getMessage(); errors.rejectValue(prefix + "." + propertyPath, "", message); } } public void validate(Object target, Errors errors) { validate(target, errors, ""); } } 

and this is how I used it in UserValidator:

 @Component public class UserValidator implements Validator { @Autowired BeanValidator beanValidator; @Override public boolean supports(Class<?> clazz) { return User.class.equals(clazz); } @Override public void validate(Object target, Errors errors) { User user = (User) target; beanValidator.validate(user.getAddress(), errors, "address"); } } 

Literature:

0
source

Source: https://habr.com/ru/post/1432025/


All Articles