1. Обзор
В этом уроке мы узнаем, как сделать переменную пути необязательной в Spring. Во- первых, мы опишем , как Spring связывает параметры @PathVariable
в методе обработчика. Затем мы покажем различные способы сделать переменную пути необязательной в разных версиях Spring.
Краткий обзор переменных пути можно найти в нашей статье Spring MVC .
2. Как Spring связывает параметры @PathVariable
По умолчанию Spring попытается связать все параметры, аннотированные с помощью @PathVariable
, в методе обработчика с соответствующими переменными в шаблоне URI. Если Spring выйдет из строя, он не доставит наш запрос этому методу обработчика.
Например, рассмотрим следующий метод getArticle
, который пытается (безуспешно) сделать переменную пути id
необязательной:
@RequestMapping(value = {"/article", "/article/{id}"})
public Article getArticle(@PathVariable(name = "id") Integer articleId) {
if (articleId != null) {
//...
} else {
//...
}
}
Здесь метод getArticle
должен обслуживать запросы как к /article
, так и к /article/{id}
. Spring попытается привязать параметр articleId
к переменной пути id
, если она присутствует.
Например, отправка запроса на /article/123
устанавливает значение articleId равным
123.
С другой стороны, если мы отправим запрос в /article
, Spring вернет код состояния 500 из-за следующего исключения:
org.springframework.web.bind.MissingPathVariableException:
Missing URI template variable 'id' for method parameter of type Integer
Это произошло потому, что Spring не мог установить значение для параметра articleId
, так как идентификатор
отсутствовал.
Итак, нам нужен какой-то способ сказать Spring игнорировать привязку определенного параметра @PathVariable
, если у него нет соответствующей переменной пути, как мы увидим в следующих разделах.
3. Делаем переменные пути необязательными
3.1. Использование обязательного
атрибута @PathVariable
Начиная с Spring 4.3.3, аннотация @PathVariable
определяет логический атрибут , необходимый
для того, чтобы мы могли указать, является ли переменная пути обязательной для метода обработчика.
Например, следующая версия getArticle
использует обязательный
атрибут:
@RequestMapping(value = {"/article", "/article/{id}"})
public Article getArticle(@PathVariable(required = false) Integer articleId) {
if (articleId != null) {
//...
} else {
//...
}
}
Поскольку атрибут required равен
false
, Spring не будет жаловаться, если в запросе не будет отправлена переменная пути id .
То есть Spring установит для articleId
значение id
, если оно отправлено, или null
в противном случае.
С другой стороны, если бы required
было true
, Spring выдавал бы исключение в случае отсутствия id
.
3.2. Использование дополнительного
типа параметра
Следующая реализация показывает, как Spring 4.1 вместе с классом Optional
из JDK 8 `` предлагает еще один способ сделать articleId
необязательным:
@RequestMapping(value = {"/article", "/article/{id}"}")
public Article getArticle(@PathVariable Optional<Integer> optionalArticleId) {
if (optionalArticleId.isPresent()) {
Integer articleId = optionalArticleId.get();
//...
} else {
//...
}
}
Здесь Spring создает экземпляр Optional<Integer> ,
optionalArticleId
, для хранения значения id
. Если id
присутствует, optionArticleId
будет обертывать его значение, в противном случае optionArticleId
будет обертывать нулевое
значение. Затем мы можем использовать методы isPresent
(),
get()
или orElse() класса Optional
для работы со значением.
3.3. Использование типа параметра карты
Другой способ определить необязательную переменную пути, которая доступна начиная с Spring 3.2, — использовать M
ap
для параметров @PathVariable
:
@RequestMapping(value = {"/article", "/article/{id}"})
public Article getArticle(@PathVariable Map<String, String> pathVarsMap) {
String articleId = pathVarsMap.get("id");
if (articleId != null) {
Integer articleIdAsInt = Integer.valueOf(articleId);
//...
} else {
//...
}
}
В этом примере параметр Map<String, String>
pathVarsMap
собирает все переменные пути, которые находятся в URI, в виде пар ключ/значение. Затем мы можем получить определенную переменную пути, используя метод get()
.
Обратите внимание: поскольку Spring извлекает значение переменной пути как String
, мы использовали метод Integer.valueOf()
для преобразования его в Integer
.
3.4. Использование двух методов обработчика
Если мы использовали устаревшую версию Spring, мы можем разделить метод обработчика getArticle
на два метода.
Первый метод будет обрабатывать запросы к /article/{id}
:
@RequestMapping(value = "/article/{id}")
public Article getArticle(@PathVariable(name = "id") Integer articleId) {
//...
}
В то время как второй метод будет обрабатывать запросы к /article
:
@RequestMapping(value = "/article")
public Article getDefaultArticle() {
//...
}
4. Вывод
Подводя итог, мы обсудили, как сделать переменную пути необязательной в разных версиях Spring.
Как обычно, полный код для этой статьи доступен на GitHub .