In this article, we are going to see several examples on how to get request parameters with Spring MVC, how to bind them to different objects, how to use @RequestParam annotation and when the annotation is not needed.
@RequestParam is an annotation which indicates that a method parameter should be bound to a web request parameter.
1. Biding method parameter with web request parameter
Let’s say we have our /books URL that requires a mandatory parameter named category:
we just need to add @RequestParam("parameterName") annotation before the method parameter that we will use for biding the web request parameter.
Let’s see an example:
In the snippet above we’ve captured value of request parameter “category” into String cat method argument and we put its value into a Model object so that we can easily test it.
In the test above we are using Spring MVC test library to perform an HTTP GET request to /books with a parameter - category - which has value “java”. Then we verify that the response status is OK (code: 200) and that the model contains an attribute named category and that its value is “java”.
Please note that category _is considered a mandatory parameter if we don’t pass _category parameter in our call as in the test below we receive a 400: BadRequestException.
2. Request parameter match method parameter name
If both variable and request parameter name matches we don’t need to specify the parameter name in the @RequestParam annotation.
In the example above, sinceboth variable and request parameter name is ‘category’, binding is performed automatically.
3. Auto type conversion
If the request parameter is not a String but - for example - a number we can bind it to the corresponding type. Let’s say we have a call like this:
In order to bind rate and maxprice respectively with an int and a BigDecimal, we just need to specify the target type after the annotation.
Similarly, if we want to pass a date like:
We need to bind it with respective object:
Since dates have different formats, it’s necessary to specify which one should be used in order to parse the value parameter correctly. In our example, we’ve used @DateTimeFormat to specify iso DateTimeFormat.ISO.DATE that is the most common ISO: yyyy-MM-dd.
All simple types such as int,long, Date, etc. are supported.
The conversion process can be configured and customized according to your needs using WebBinder or by registering Formatters.
4. @RequestParam with not mandatory parameters
When we add@RequestParam annotation, as we’ve seen, by default we are assuming that request parameter is mandatory. In case we want to specify that is not, we can just add required=false.
In this case, if we call just /books _without parameter, we won’t receive a 400 as before. String category in this case will remain _null.
5. @RequestParam with Default value
It’s also possible to specify a default value that will be applied if the parameter is not sent. Let’s say our default value is “fantasy” we can add defaultValue = "fantasy" in the annotation as follows:
Let’s then perform our test in which we don’t pass category request parameter, expected value it’s gonna be “fantasy”.
When request parameter is sent, the value should be, of course, the one sent and not our default.
6. @RequestParam with List or array
We can also perform a call in which we specify several values for a parameter, like:
In this case, we can bind it using a List or an array_ - _this is with a List:
and with an array:
7. @RequestParam with Map
It’s also possible to bind all request parameters in a Map just by adding a Map object after the annotation:
In this example we’ve added a Map<String,String>, the key is the request parameter name, so we just get the parameters from the Map using their name. I think it’s worth highlight that with this approach you can’t specify which parameters are mandatory and which not and that the code can be insidious to read since might need to read it all in order to figure out which are the possible parameters used by this method.
In order to validate the snippet let’s perform a little test:
Note that if you have multiple values for the same parameter name, you should use MultiValueMap. In the example below, we use@RequestParam with MultiValueMap<String,List<String>> so that we can store multiple values for the same parameter in a List.
Let’s test it passing two authors and one category:
Based on the list of HandlerMethodArgumentResolver configured in your application, @RequestParam can also be omitted.
If you have a look at the code of method getDefaultArgumentResolvers() of RequestMappingHandlerAdapter there is the following piece of code at the end:
Basically, it’s added to the resolvers a RequestParamMethodArgumentResolver
with useDefaultResolution set to true. Looking at the documentation we can see that this means that method argument that is a simple type, as defined in _BeanUtils.isSimpleProperty(java.lang.Class<?>), is treated as a request parameter even if it isn’t annotated. The request parameter name is derived from the method parameter name.
Let’s see in the next example what it means.
8. Binding without annotation
We define our controller without adding the usual @RequestParam annotation before the method argument String category
If we run our usual test we will see that it pass!
This happens because both variable and request parameter name is category and in the list of default handlers, we have RequestParamMethodArgumentResolver with useDefaultResolution set to true.
Despite it might look convenient, I prefer to always specify the annotation since it clearly states that the argument represents a request parameter.
9. Bind with a field of an object
In a similar way, if we pass as argument a simple pojo object that has a field - with getter and setter - named like the request parameter, the value of the request parameter will be stored in this field.
Let’s define our pojo class:
then our Controller:
and we run our usual test, we will see that also in this case value of request parameter is correctly stored into myForm.getCategory().
For these tests we’ve quickly setup a Spring Boot project, you can find below the pom.xml.