Is it possible to use Bean Validation annotations like #Past or #Length on Request Parameters in spring mvc?
I would like to do something like:
#RequestMapping(method = RequestMethod.POST)
public RedirectView initiateSignup(#RequestParam #Valid #Past Date birthdate, BindingResult birthdateResult,
HttpServletResponse httpServletResponse) throws HttpMediaTypeNotAcceptableException {
I made it work with the help of a blog post:
http://blog.codeleak.pl/2012/03/how-to-method-level-validation-in.html
an additional annotation and a bean post processor were nessecary, but now it works.
I don't think that's possible. You can apply #Valid but not e.g. #Past. You can instead create a model class with fields that correspond to your request parameters, and put the JSR-303 annotations on the class's fields. You can then use that class as the controller method argument type, with #Valid on it, and Spring should validate it appropriately.
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/validation.html#validation-mvc-jsr303
Related
I am creating a small validation application using Spring MVC. I am very new to Spring MVC and would like to ensure that what I want is possible.
I have simplified my problem.
I have setup a controller that will be called when a URL is executed. localhost/validate/{SOME TEXT}
The {SOME TEXT} value with be sent to all my validation classes I created.
I currently have 4 classes which does the validation and returns another Object data about what happened during the validation
The 4 validation classes are:
CreditCardValidator
AddressValidator
ZipcodeValidator
AccountNumberValidator
I have a main controller bean that when called I want the string to be passed to each class and the object returned from each to be stored and then finally all results are sent back in a response.
Normally, I would do this without Spring by creating an interface that each validation class implements. Then iteration through the list of classes and execute a method.
The problem doing it that way is that whenever I need to add a new validation class I'll need to register it so the request can use it. This involved modifying existing classes.
Since I am using Spring quick heavily in this application I am wondering if this is possible to do via Spring and annotated classes.
I was thinking of creating a custom annotation that each validation class has and then using spring component-scan to get the classes. This would allow me to create new validations without modifying existing code.
Below is the what I am trying to do.
#Controller
public class StringValidationController {
#RequestMapping(value = "/validate/{text:.+}", method = RequestMethod.GET)
public ModelAndView index(#PathVariable("text") String text) {
ModelAndView model = new ModelAndView();
model.setViewName("index");
model.addObject("result", getListOfValidatedData());
return model;
}
public List getListOfValidatedData(){
//Scan for IValidator annotation
//call each concrete class and pass in text
// get object with has validation information in it
}
}
I'm writing an application using Spring MVC.
I have a method that returns values from a database. And I want to display these values in the site's header (which is shown on all pages). How I can do this?
I need to call this method in every controller.
Declare a class with #ControllerAdvice annotation, then declare a method with #ModelAttribute annotation. For example:
#ControllerAdvice
public class GlobalControllerAdvice {
#ModelAttribute
public void myMethod(Model model) {
Object myValues = // obtain your data from DB here...
model.addAttribute("myDbValues", myValues);
}
}
Spring MVC will invoke this method before each method in each MVC controller. You will be able to use the myDbValues attribute in all pages.
The #ControllerAdvice class should be in the same Java namespace where all your MVC controllers are (to make sure Spring can detect it automatically).
See the Spring Reference for more details on #ControllerAdvice and #ModelAttribute annotations.
You could write your own interceptor.
I have some questions from a design point of view in Spring Web MVC.
Is it good practice to use Request Object in controller? If not, then what is alternative way to pass pass one text fields value to controller? Do I need to create one new from bean for this single fields?
It depends of the situation, in a few cases I used the HttpServletRequest; for example for writing a file to the output stream.
If you want to get the Request Parameters you can use the annotation #RequestParam, that it´s more easy to get the parameters from the request.
Depends that you want to handle, for example for a form you can use #ModelAttribute and this attribute can be in a session or in the request.
For example:
#Controller
public class YourController {
#RequestMapping(value = "someUrl", method = RequestMethod.GET)
public String someMethod(#RequestParam("someProperty") String myProperty)
{
// ... do some stuff
}
}
Check the documentation here:
#RequestParam
#ModelAttribute
#PathVariable
I know spring 3.2 does convert a json to a list of objects with RequestBody annotation. Its not working for me. I can use regular Jackson object mapper to do it. Just checking if any one can help me.. Below is my json and controller method
[{"uniqueJqGridId":"1","fileProcessingDate":"2012-09-24","createdTimeStamp":"1348569180191","csoCode":"A-A ","cycleDate":"2012-09-24","accountDate":"2012-10-02","originName":"NCAA ","amount":"-95996.33","policyNumber":"C ","transactionCode":"PCH","id":"1"}]
#RequestMapping(method = RequestMethod.POST, value = "/washTransactions", headers="Content-Type=application/json")
public #ResponseBody RequestStatus washTransactions(#RequestBody List<ReconPolicy> policiesToWash)throws Exception{
reconciliationService.applyWashToTransactions(policiesToWash,getCurrentUser());
return new RequestStatus(true);
}
You're facing Java's Type Erasure problem. Spring is not able to pass the exact class type to the method so it's actually getting something like List<?> policiesToWash.
A workaround would be to create a class like
public class WashablePolishes extends ArrayList<ReconPolicy>
This way spring will retain the type through the super type chain.
or you could change your method to
public #ResponseBody RequestStatus washTransactions(#RequestBody ReconPolicy[] policiesToWash) throws Exception {...}
Thanks for you reply Varun. Starting from Spring 3.2,There is no type erasure problem. I found the issue after enabling spring debugging, I figure out it is failing on some unknown properties, I had to annotate my class with #JsonIgnoreProperties. Now it works.
Is BindingResult useful to bind just exceptions with view, or something else?
what is the exact use of BindingResult?
Or is it useful in binding model attribute with view.
Particular example: use a BindingResult object as an argument for a validate method of a Validator inside a Controller.
Then, you can check this object looking for validation errors:
validator.validate(modelObject, bindingResult);
if (bindingResult.hasErrors()) {
// do something
}
Basically BindingResult is an interface which dictates how the object that stores the result of validation should store and retrieve the result of the validation(errors, attempt to bind to disallowed fields etc)
From Spring MVC Form Validation with Annotations Tutorial:
[BindingResult] is Spring’s object that holds the result of the
validation and binding and contains errors that may have occurred. The
BindingResult must come right after the model object that is validated
or else Spring will fail to validate the object and throw an
exception.
When Spring sees #Valid, it tries to find the validator for the
object being validated. Spring automatically picks up validation
annotations if you have “annotation-driven” enabled. Spring then
invokes the validator and puts any errors in the BindingResult and
adds the BindingResult to the view model.
It's important to note that the order of parameters is actually important to spring. The BindingResult needs to come right after the Form that is being validated. Likewise, the [optional] Model parameter needs to come after the BindingResult.
Example:
Valid:
#RequestMapping(value = "/entry/updateQuantity", method = RequestMethod.POST)
public String updateEntryQuantity(#Valid final UpdateQuantityForm form,
final BindingResult bindingResult,
#RequestParam("pk") final long pk,
final Model model) {
}
Not Valid:
RequestMapping(value = "/entry/updateQuantity", method = RequestMethod.POST)
public String updateEntryQuantity(#Valid final UpdateQuantityForm form,
#RequestParam("pk") final long pk,
final BindingResult bindingResult,
final Model model) {
}
Well its a sequential process.
The Request first treat by FrontController and then moves towards our own customize controller with #Controller annotation.
but our controller method is binding bean using modelattribute and we are also performing few validations on bean values.
so instead of moving the request to our controller class, FrontController moves it towards one interceptor which creates the temp object of our bean and the validate the values.
if validation successful then bind the temp obj values with our actual bean which is stored in #ModelAttribute otherwise if validation fails it does not bind and moves the resp towards error page or wherever u want.
From the official Spring documentation:
General interface that represents binding results. Extends the
interface for error registration capabilities, allowing for a
Validator to be applied, and adds binding-specific analysis and model
building.
Serves as result holder for a DataBinder, obtained via the
DataBinder.getBindingResult() method. BindingResult implementations
can also be used directly, for example to invoke a Validator on it
(e.g. as part of a unit test).
BindingResult is used for validation..
Example:-
public #ResponseBody String nutzer(#ModelAttribute(value="nutzer") Nutzer nutzer, BindingResult ergebnis){
String ergebnisText;
if(!ergebnis.hasErrors()){
nutzerList.add(nutzer);
ergebnisText = "Anzahl: " + nutzerList.size();
}else{
ergebnisText = "Error!!!!!!!!!!!";
}
return ergebnisText;
}