spring-request-param
Spring @RequestParam Annotation
1. Overview
Simply put, we can use @RequestParam to extract query parameters, form parameters and even files from the request.
We’ll discuss how to use @RequestParam and its attributes. We’ll also discuss the differences between @RequestParam and @PathVariable.
Further reading:
Spring @RequestMapping New Shortcut Annotations
In this article, we introduce different types of @RequestMapping shortcuts for quick web development using traditional Spring MVC framework.
The Spring @Controller and @RestController Annotations
Learn about the differences between @Controller and @RestController annotations in Spring MVC.
2. A Simple Mapping
@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam String id) {
return "ID: " + id;
}
In this example, we used @RequestParam to extract the id query parameter.
A simple GET request would invoke getFoos:
http://localhost:8080/api/foos?id=abc
ID: abc
Next, *let's have a look at the annotation's attributes: _name,_ _value, required_ and _defaultValue._* === *3. Specifying the Request Parameter Name* [[specifying-the-request-parameter-name]]In the previous example, both variable name and the parameter name are the same. *Sometimes we want these to be different, though.* Or, if we aren't using Spring Boot, we may need to do special compile-time configuration or the parameter names won't actually be in the bytecode. *But what's nice is that we can configure the _@RequestParam_ name using the _name_ attribute:* [source,java,gutter:,true]
@PostMapping(“/api/foos”)
@ResponseBody
public String addFoo(@RequestParam(name = “id”) String fooId, @RequestParam String name) {
return “ID: ” + fooId + ” Name: ” + name;
}
We can also do _@RequestParam(value = “id”)_ or just _@RequestParam(“id”)._ === *4. Making an Optional Request Parameter* [[making-an-optional-request-parameter]]Method parameters annotated with _@RequestParam_ are required by default. This means that if the parameter isn’t present in the request, we'll get an error: [source,bash,gutter:,true]
GET /api/foos HTTP/1.1
400 Bad Request
Required String parameter 'id' is not present
----
We can configure our _@RequestParam_ to be optional, though, with the __required __attribute:
[source,java,gutter:,true]
----
@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(required = false) String id) {
return "ID: " + id;
}
----
In this case, both:
[source,bash,gutter:,true]
----
http://localhost:8080/api/foos?id=abc
----
ID: abc
----
and
[source,bash,gutter:,true]
----
http://localhost:8080/api/foos
----
ID: null
----
will correctly invoke the method.
*When the parameter isn't specified, the method parameter is bound to _null_.*
=== *5. A Default Value for the Request Parameter*
[[a-default-value-for-the-request-parameter]]We can also set a default value to the _@RequestParam_ by using the _defaultValue_ attribute:
[source,java,gutter:,true]
----
@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(defaultValue = "test") String id) {
return "ID: " + id;
}
----
*This is like __required=false, __in that the user no longer needs to supply the parameter:*
[source,bash,gutter:,true]
----
http://localhost:8080/api/foos
----
ID: test
----
Though, we are still okay to provide it:
[source,bash,gutter:,true]
----
http://localhost:8080/api/foos?id=abc
----
ID: abc
----
Note that when we set the __defaultValue __attribute, _required_ is, indeed, set to false.
=== *6. Mapping All Parameters*
[[mapping-all-parameters]]*We can also have multiple parameters without defining their names* or count by just using _Map:_
[source,java,gutter:,true]
----
@PostMapping("/api/foos")
@ResponseBody
public String updateFoos(@RequestParam Map<String,String> allParams) {
return "Parameters are " + allParams.entrySet();
}
----
Which will then reflect back any parameters sent:
[source,bash,gutter:,true]
----
curl -X POST -F 'name=abc' -F 'id=123' http://localhost:8080/api/foos
Parameters are {[name=abc], [id=123]}
=== *7. Mapping a Multi-Value Parameter* [[mapping-a-multi-value-parameter]]A single _@RequestParam_ can have multiple values: [source,java,gutter:,true]
@GetMapping(“/api/foos”)
@ResponseBody
public String getFoos(@RequestParam List<String> id) {
return “IDs are ” + id;
}
*And Spring MVC will map a comma-delimited __id __parameter:* [source,bash,gutter:,true]
IDs are [1,2,3]
Or a list of separate id parameters:
http://localhost:8080/api/foos?id=1&id=2
IDs are [1,2]
=== *8. _@RequestParam_ vs _@PathVariable_* [[requestparam-vs-pathvariable]]_@RequestParam_ and _@PathVariable_ can both be used to extract values from the request URI, but they are a bit different. [[query-parameter-vs-uri-path]] ==== *8.1. Query Parameter vs URI Path* [[query-parameter-vs-uri-path]]While __@RequestParam__s extract values from the query string, _@PathVariables_ extract values from the URI path: [source,java,gutter:,true]
@GetMapping(“/foos/{id}”)
@ResponseBody
public String getFooById(@PathVariable String id) {
return “ID: ” + id;
}
Then, we can map based on the path: [source,bash,gutter:,true]
ID: abc
And for @RequestParam, it will be:
@GetMapping("/foos")
@ResponseBody
public String getFooByIdUsingQueryParam(@RequestParam String id) {
return "ID: " + id;
}
Which would give us the same response, just a different URI:
http://localhost:8080/foos?id=abc
ID: abc
[[encoded-vs-exact-value]] ==== *8.2. Encoded vs Exact Value* [[encoded-vs-exact-value]]Because _@PathVariable_ is extracting values from the URI path, it’s not encoded. On the other hand, _@RequestParam_ is. Using the previous example, _ab+c_ will return as-is: [source,bash,gutter:,true]
ID: ab+c
But for a @RequestParam request, the parameter is URL decoded:
http://localhost:8080/foos?id=ab+c
ID: ab c
[[optional-values]] ==== *8.3. Optional Values* [[optional-values]]*Both _@RequestParam_ and _@PathVariable_ can be optional.* We can make _@PathVariable_ optional by using the _required_ attribute starting with Spring 4.3.3: [source,java,gutter:,true]
@GetMapping({“/myfoos/optional”, “/myfoos/optional/{id}”})
@ResponseBody
public String getFooByOptionalId(@PathVariable(required = false) String id){
return “ID: ” + id;
}
Which, then, we can do either: [source,bash,gutter:,true]
ID: abc
or:
http://localhost:8080/myfoos/optional
ID: null
For @RequestParam, we can also use the _required_ attribute as we saw in a previous section. Note that *we should be careful when making _@PathVariable_ optional, to avoid conflicts in paths.* === *9. Conclusion* [[conclusion]]In this article, we learned how to use _@RequestParam_ and the difference between _@RequestParam_ and _@PathVariable_. The full source code for the examples can be found in the https://github.com/eugenp/tutorials/tree/master/spring-mvc-simple[GitHub project].