Spring MVC @Requestparam - Binding request parameters
JAVA SPRING MVCIn 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 examples
@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:
/books?category=java
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”.
For this test we’ve quickly setup a Spring Boot project, you can find the pom.xml at the end of this article.
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, since** **both 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:
/books?rate=5&maxprice=150.00
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:
/books?from=2011-01-01
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”.
@Test
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:
/books?authors=martin&authors=tolkien
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:
/books?category=fantasy&author=Tolkien
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:
/books?authors=martin&authors=tolkien&category=top250
Examples without @RequestParam
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()
.
pom.xml
For these tests we’ve quickly setup a Spring Boot project, you can find below the pom.xml.