In this article, we will understand the usage of @PathVariable annotation in Spring. This is a very commonly used annotation when creating a web application.
This web application may be an MVC application or a REST web service. Also, this article is relevant for Spring and Spring boot applications both.

Overview
Suppose you have a URL of below form

http://localhost:8080/user/12

Here,
1. URL till http://localhost:8080/user is a resource URL that is used to fetch a resource, a user in this case,
2. URL portion after this is used to identify the resource, in this case, it might be a user with id 12. This part is dynamic and its value may vary for different requests.

In a Spring application, how would you retrieve the dynamic value in the request URL, it is where @PathVariable annotation comes handy.
Scenario
In order to handle URLs that map to a resource such as that shown in the previous section, you need to create a method in a Spring controller which looks as below.

@GetMapping("/user/{id}")
public User getUser(Integer userId) {
  // fetch user
}

Here, the dynamic part is enclosed between curly braces. Its name need not be id, it can be any string.
It is called path variable or template variable as shown below.
Path variable mapping with controller
Any request of the format http://<approot>/user/<something> will be handled by this controller method.

Now, how do you get the value of template variable from the request URL inside the controller method. This is where @PathVariable comes into picture.

@PathVariable annotation
@PathVariable annotation is applied before a method argument and it populates the argument with the value sent in the URL parameter.
@PathVariable accepts a String argument which matches with the template variable given in the controller URL enclosed between curly braces as shown in the below image.
@PathVariable annotation example
@PathVariable binds the method variable that follows it with the value in the request URL.
@PathVariable example
Below is an example of @PathVariable annotation.

@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Integer userId) {
  // fetch user
}

In above example, userId variable is populated with the value in request URL after /user.
So, for the URL, http://localhost:9090/user/12, the variable userId will be populated with 12.

@PathVariable("id") can also be written as @PathVariable(name="id") or @PathVariable(value = "id") since name and value are the attributes of @PathVariable.

Omitting @PathVariable argument
Argument supplied to @PathVariable can be omitted if the template variable in controller URL matches with the method argument annotated with @PathVariable.
Example,

@GetMapping("/user/{id}")
public User getUser(@PathVariable Integer id) {
  // fetch user
}

In this example, @PathVariable does not have any argument since the controller method parameter(annotated with @PathVariable) and template variable are the same.

Multiple @PathVariable
A controller URL may be of the format, http://localhost:8080/app/user/{id}/{name}.
This URL contains two template variables and we need to assign them to different method arguments.

So, we can write a controller method with more than one @PathVariable annotations as shown below.

@GetMapping("/user/{id}/{name}")
public User getUser(@PathVariable Integer id, @PathVariable String name) {
  // fetch user on id and name
}

Map all template variables
There may be multiple template variables such as in the example above.
Instead of defining method arguments for each template variable and annotating them with @PathVariable, we can define a java.util.Map<String, String> and it will automatically be populated with all template variables and their values as its key and value respectively, when the request arrives.
Example,

@GetMapping("/user/{uid}/{uname}")
public User getUser(@PathVariable Map<String, String> map) {
  String id = map.get("uid");
  String name="map.get("uname")
  // fetch user on id and name
}

If the request URL is http://localhost:8080/appname/12/abc, then id will be “12” and name will be “abc”.
Optional template variable
A controller URL of the form /user/{id} will only accept requests that end with /user/something.
That is, it is mandatory to supply path variable in the incoming request or else it will fail with a 404 Not Found error.

However, this can be avoided using required attribute of @PathVariable as shown below.

@GetMapping("/user/{name}")
public User getUser(@PathVariable(required = false) String name) {
  // fetch user
}

Now, this method can handle requests of the form
http://localhost:8080/appname/user, and
http://localhost:8080/appname/user/12.

Default value of required is true.
Using Java 8 optional
There is another method of specifying optional path variables apart from required attribute. It is by using Java 8 optional.
Simply make the type of method argument java.util.Optional as shown below.

@GetMapping("/user/{name}")
public User getUser(@PathVariable Optional<String> name) {
  // fetch user
}

@PathVariable are of immense use when designing api in a Spring application since they easily map dynamic request URLs to controller methods.
That was all on this annotation. Hope the article was useful and informative.