Spring @RequestParam

In this article, we will understand what is @RequestParam annotation in Spring, what is it used for, and its arguments along with examples and their explanation.
This article is relevant both for Spring and Spring boot applications.


Request parameters
A simple URL looks like

http://127.0.0.1/springapp/employees

This URL fetches the details of all the employees. But if you want to fetch the details of an employee based on id and name, you will create a URL of the form

http://127.0.0.1/springapp/employees?id=1&name=xyz

Here, id and name are called Request parameters also known as Query Parameters.
Request parameters begin with a ? after the desired URL and multiple parameters are separated with an ampersand(&) symbol.
Also, each request parameter is followed by its value assigned using =.
Refer below image for a better understanding of request parameters.
@RequestParam annotation example
@RequestParam annotation
Now you know what is a request parameter and how it is sent to the server. But how it is retrieved in a Spring or Spring boot application.
The answer is using @RequestParam annotation.
@RequestParam is applied before a controller method argument whose value is populated from the request parameter.
Now the question arises, how is the method argument populated with request parameter value. That is, if there are 4 request parameters and 4 method arguments, then how will the arguments be populated with those parameters.

There are three ways to specify method argument and request parameter mapping.

1. Same method arguments and parameter names
This is the simplest method where controller method arguments are given the same names as the request parameters.
This way they are automatically initialized with the values of the corresponding parameters when the request arrrives. Example,

@GetMapping("/users)
public void getUser(@RequestParam String name, @RequestParam Integer id) {
   // fetch user
}

In this example, when a request arrives with URL http://127.0.0.1/appname/users?name=abc&id=1, the corresponding method arguments are automatically populated.

Note that request parameters are always in String format and they are converted to the type of method argument such as Integer in above example.
2. Using name attribute
Many times the name of request parameters can not be the same as the name of controller method arguments.
In this case, name property of @RequestParam is used. This property is set to the name of request parameter as shown below.

@GetMapping("/users)
public void getUser(@RequestParam(name="uname") String name, @RequestParam(name="uid") Integer id) {
   // fetch user
}

For this example, the request URL would be http://127.0.0.1/appname/users?uname=abc&uid=1.
3. Using value attribute
This is the same as above but in place of name, value is used. Example,

@GetMapping("/users)
public void getUser(@RequestParam(value="uname") String name, @RequestParam(value="uid") Integer id) {
   // fetch user
}

Request URL for this example would be http://127.0.0.1/appname/users?uname=abc&uid=1.

Making the parameters optional
If you have annotated a method argument with @RequestParam and it does not arrive in the request, then it will be an error.
Thus, if there is a controller method such as

@GetMapping("/users)
public void getUser(@RequestParam String name) {
   // fetch user
}

then the request http://127.0.0.1/appname/users?id=1 will be an error since it does not contain the name request parameter.

A solution for this is to mark request parameters as optional using required attribute and setting it to false.
So, the above controller method may be modified as

@GetMapping("/users)
public void getUser(@RequestParam(required=false) String name) {
   // fetch user
}

Now, even if the request does not contain a request parameter name, it will still reach controller.
Using Java 8 Optional
Another way of specifying optional request parameters is by using Java 8 Optional.
For using this, you need to define controller method argument of type java.util.Optional as shown below.

@GetMapping("/users)
public void getUser(@RequestParam Optional<String> name) {
   // fetch user
}

This is the same as using required=false.

Default values for parameters
It is also possible to set a default value for method argument using defaultValue property of @RequestParam.
In this case, if a request parameter with this name does not arrive, then the method argument is initialized to this default value. Example,

@GetMapping("/users)
public void getUser(@RequestParam(defaultValue=1) Integer id) {
   // fetch user
}

So, the request http://127.0.0.1/appname/users will set id argument to 1.
Using defaultValue implicitly sets required to false since it does not matter if the request parameter is sent or not.
Mapping multiple request parameters
If there are many request parameters, then it is not suitable to define arguments for all of those in controller method.
Example, if the request is of the format
http://127.0.0.1/app/users?id=1&fname=abc&lname=xyz&guid=av34e,
then you need to write a controller method as

@GetMapping("/users)
public void getUser(@RequestParam String fname, @RequestParam String lname, 
       @RequestParam String guid, @RequestParam Integer id) {
   // fetch user
}

This looks too ugly and in case an extra parameter is added, then you need to modify the controller method.

To tackle this, there is a provision to use a method argument of type java.util.Map along with @RequestParam. This map will be populated with request parameter names as keys and their values as its values.

Example, above controller method may be written as

@GetMapping("/users)
public void getUser(@RequestParam Map<String, String> params) {

}

If you print this map, then it will output

{id=1, fname=abc, lname=xyz, guid=av34e}

Thus, it contains all the request parameter names and their values.

Hope this article was useful in explaining the concept of @RequestParam annotation in Spring and Spring boot.