Перейти к основному содержимому

Весенняя аннотация @PathVariable

· 5 мин. чтения

1. Обзор

В этом кратком руководстве мы рассмотрим аннотацию Spring @PathVariable .

Проще говоря, аннотацию @PathVariable можно использовать для обработки переменных шаблона в отображении URI запроса и установки их в качестве параметров метода.

Давайте посмотрим, как использовать @PathVariable и его различные атрибуты.

2. Простое отображение

Простым вариантом использования аннотации @PathVariable может быть конечная точка, которая идентифицирует объект с помощью первичного ключа:

@GetMapping("/api/employees/{id}")
@ResponseBody
public String getEmployeesById(@PathVariable String id) {
return "ID: " + id;
}

В этом примере мы используем аннотацию @PathVariable для извлечения шаблонной части URI, представленной переменной {id} .

Простой запрос GET к /api/employees/{id} вызовет getEmployeesById с извлеченным значением идентификатора:

http://localhost:8080/api/employees/111 
----
ID: 111

Теперь давайте подробнее изучим эту аннотацию и посмотрим на ее атрибуты.

3. Указание имени переменной пути

В предыдущем примере мы пропустили определение имени переменной пути шаблона, поскольку имена параметра метода и переменной пути были одинаковыми.

Однако, если имя переменной пути отличается, мы можем указать его в аргументе аннотации @PathVariable :

@GetMapping("/api/employeeswithvariable/{id}")
@ResponseBody
public String getEmployeesByIdWithVariableName(@PathVariable("id") String employeeId) {
return "ID: " + employeeId;
}
http://localhost:8080/api/employeeswithvariable/1 
----
ID: 1

Мы также можем определить имя переменной пути как @PathVariable(value="id") вместо PathVariable("id") для ясности.

4. Несколько переменных пути в одном запросе

В зависимости от варианта использования у нас может быть более одной переменной пути в нашем URI запроса для метода контроллера, который также имеет несколько параметров метода :

@GetMapping("/api/employees/{id}/{name}")
@ResponseBody
public String getEmployeesByIdAndName(@PathVariable String id, @PathVariable String name) {
return "ID: " + id + ", name: " + name;
}
http://localhost:8080/api/employees/1/bar 
----
ID: 1, name: bar

Мы также можем обрабатывать более одного параметра @PathVariable , используя параметр метода типа java.util.Map<String, String>:

@GetMapping("/api/employeeswithmapvariable/{id}/{name}")
@ResponseBody
public String getEmployeesByIdAndNameWithMapVariable(@PathVariable Map<String, String> pathVarsMap) {
String id = pathVarsMap.get("id");
String name = pathVarsMap.get("name");
if (id != null && name != null) {
return "ID: " + id + ", name: " + name;
} else {
return "Missing Parameters";
}
}
http://localhost:8080/api/employees/1/bar 
----
ID: 1, name: bar

Однако существует небольшая проблема при обработке нескольких параметров @ PathVariable , когда строка переменной пути содержит символ точки (.). Мы подробно обсудили эти угловые случаи здесь .

5. Дополнительные переменные пути

В Spring параметры метода, аннотированные @PathVariable , требуются по умолчанию:

@GetMapping(value = { "/api/employeeswithrequired", "/api/employeeswithrequired/{id}" })
@ResponseBody
public String getEmployeesByIdWithRequired(@PathVariable String id) {
return "ID: " + id;
}

Судя по тому, как это выглядит, вышеприведенный контроллер должен обрабатывать пути запросов /api/employeeswithrequired и /api/employeeswithrequired/1 . Однако, поскольку параметры метода, аннотированные @PathVariables , являются обязательными по умолчанию, он не обрабатывает запросы, отправленные в /api/employeeswithrequired path:

http://localhost:8080/api/employeeswithrequired 
----
{"timestamp":"2020-07-08T02:20:07.349+00:00","status":404,"error":"Not Found","message":"","path":"/api/employeeswithrequired"}
http://localhost:8080/api/employeeswithrequired/1 
----
ID: 111

Мы можем справиться с этим двумя разными способами.

5.1. Установка @PathVariable как необязательная

Мы можем установить для обязательного свойства @PathVariable значение false , чтобы сделать его необязательным. Таким образом, изменив наш предыдущий пример, мы теперь можем обрабатывать версии URI с переменной пути и без нее:

@GetMapping(value = { "/api/employeeswithrequiredfalse", "/api/employeeswithrequiredfalse/{id}" })
@ResponseBody
public String getEmployeesByIdWithRequiredFalse(@PathVariable(required = false) String id) {
if (id != null) {
return "ID: " + id;
} else {
return "ID missing";
}
}
http://localhost:8080/api/employeeswithrequiredfalse 
----
ID missing

5.2. Использование java.util.Optional

С момента появления Spring 4.1 мы также можем использовать java.util.Optional<T> (доступно в Java 8+) для обработки необязательных переменных пути:

@GetMapping(value = { "/api/employeeswithoptional", "/api/employeeswithoptional/{id}" })
@ResponseBody
public String getEmployeesByIdWithOptional(@PathVariable Optional<String> id) {
if (id.isPresent()) {
return "ID: " + id.get();
} else {
return "ID missing";
}
}

Теперь, если мы не укажем идентификатор переменной пути в запросе, мы получим ответ по умолчанию:

http://localhost:8080/api/employeeswithoptional 
----
ID missing

5.3. Использование параметра метода типа Map<String, String>

Как показано ранее, мы можем использовать один параметр метода типа java.util.Map для обработки всех переменных пути в URI запроса. Мы также можем использовать эту стратегию для обработки случая с необязательными переменными пути:

@GetMapping(value = { "/api/employeeswithmap/{id}", "/api/employeeswithmap" })
@ResponseBody
public String getEmployeesByIdWithMap(@PathVariable Map<String, String> pathVarsMap) {
String id = pathVarsMap.get("id");
if (id != null) {
return "ID: " + id;
} else {
return "ID missing";
}
}

6. Значение по умолчанию для @PathVariable

По умолчанию не предусмотрено определение значения по умолчанию для параметров метода, аннотированных с помощью @PathVariable . Однако мы можем использовать те же стратегии, которые обсуждались выше, чтобы удовлетворить случай значения по умолчанию для @PathVariable, нам просто нужно проверить значение null в переменной пути.

Например, используя java.util.Optional<String, String> , мы можем определить, является ли переменная пути нулевой или нет. Если он равен нулю, то мы можем просто ответить на запрос со значением по умолчанию:

@GetMapping(value = { "/api/defaultemployeeswithoptional", "/api/defaultemployeeswithoptional/{id}" })
@ResponseBody
public String getDefaultEmployeesByIdWithOptional(@PathVariable Optional<String> id) {
if (id.isPresent()) {
return "ID: " + id.get();
} else {
return "ID: Default Employee";
}
}

7. Заключение

В этой статье мы обсудили, как использовать аннотацию Spring @PathVariable . Мы также определили различные способы эффективного использования аннотации @PathVariable для различных вариантов использования, таких как необязательные параметры и работа со значениями по умолчанию.

Пример кода, показанный в этой статье, также доступен на Github .