Latest spring mvc, using freemarker.
Hoping someone could tell me what my options are in terms of validating a form with spring mvc, and what the recommend way would be to do this.
I have a form that doesn't map directly to a model, it has input fields that when posted, will be used to initialize 2 model objects which I will then need to validate, and if they pass I will save them.
If they fail, I want to return back to the form, pre-fill the values with what the user entered and display the error messages.
I have read here and there about 2 methods, once of which I have done and understand how it works:
@RequestMapping(...., method = RequestMethod.POST)
public ModelAndView myMethod(@Valid MyModel, BindingResult bindingResult) {
ModelAndView mav = new ModelAndView("some/view");
mav.addObject("mymodel", myModel);
if(bindingResult.hasErrors()) {
return mav;
}
}
Now this worked if my form mapped directly to the form, but in my situation I have:
form fields that don't map to any specific model, they have a few properties from 2 models.
before validation occurrs, I need to create the 2 models manually, set the values from the form, and manually set some properties also:
Call validate on both models (model1, model2), and append these error messages to the errors collection which I need to pass back to the same view page if things don't work.
when the form posts, I have to do some database calls, and based on those results may need to add additional messages to the errors collection.
Can someone tell me how to do this sort of validation?
Pseudo code below:
Model1 model1 = new Model1();
Model2 model2 = new Model2();
// manually or somehow automatically set the posted form values to model1 and model2.
// set some fields manually, not from posted form
model1.setProperty10(GlobalSettings.getDefaultProperty10());
model2.setProperty11(GlobalSettings.getDefaultProperty11());
// db calls, if they fail, add to errors collection
if(bindingResult.hasErrors()) {
return mav;
}
// validation passed, save
Model1Service.save(model1);
Model2Service.save(model2);
redirect to another view
Update
I have using the JSR 303 annotations on my models right now, and it would great if I can use those still.
Update II
Please read the bounty description below for a summary of what I am looking for.
Based on a similar experience, I'd propose the following and on the side I have a comment on the last step on the approach that you want to take. I use your numbered list of steps.
Step 1: Form Bean
There are two ways for this. The simple approach is to define a form bean (that I presume you've already done):
class MyModel {
private Model1 model1;
private Model2 model2;
// standard Java bean stuff
}
A more precise way is to actually define MyModel
such that I only borrows the fields that requires from Model1
and Model2
but I'm not sure if this fits your way.
Step 2: Data Binding
Spring does this for you if you have such form
structure in your view:
<form:form modelAttribute="myModel">
<form:input path="model1.somePropertyToBeSet" />
</form:form>
Step 3: Validation
Using Spring custom validations, you can define custom constraints:
@interface Model1Constraint {}
@interface Model2Constraint {}
class MyModel1 {
@Model1Constraint
private Model1 model1;
@Model2Constraint
private Model2 model2;
// ...
}
Then register your custom validators for the custom constraints:
class Model1ConstraintValidator implements ConstraintValidator<Model1Constraint, Model1> {
// implementation of isValid and initalize
}
And the same for Model2Constraint
. Using the custom validators, you can check what logic you need to ensure before MyModel
is passed into request processing method. I also presume that you've used <mvc:annotation-driven />
to have Spring register the validators; otherwise, you should configure them.
Step 4: Custom model processing before request processing
Your original idea is to use some data binder for this job. In your description, you also mention that this data processing does not depend on the data coming from the form data.
Regarding design and modularity, I do not believe a data binder is a good place for such a purpose. Second to that, since there is no data dependency to the form, the major reason for you is to allow data binding error processing.
So, my suggestion is that let's say that now you're in public ModelAndView myMethod(@Valid MyModel model, BindingResult bindingResult)
. Presumably, you have access to other service beans here. So, you can have a method in some service bean that can refine
or prepare
(just names) the model
that you've populated in this point. Based on exceptions or any other mechanism that suits you, you can use bindingResult
to return the errors again.
As another suggestion, you may also take advantage of Spring interceptors if you'd like a more DI/IoC way to do it. But in this way, you should extract MyModel
from ModelAndView
in interception and proceed.
I hope this helps.
awesome explaination here, Please check Integrating Spring MVC 3.0 with JSR 303 (aka javax.validation.*)
Check this below example too JSR 303 Bean Validation Using Spring 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With