1. Overview
1.概述
In this tutorial, we’ll learn how to make a path variable optional in Spring. First, we’ll describe how Spring binds @PathVariable parameters in a handler method. Then, we’ll show different ways of making a path variable optional in different Spring versions.
在本教程中,我们将学习如何在Spring中使路径变量成为可选项。首先,我们将描述Spring如何在处理方法中绑定@PathVariable参数。然后,我们将展示在不同的Spring版本中使路径变量可选的不同方法。
For a quick overview of path variables, please read our Spring MVC article.
有关路径变量的快速概述,请阅读我们的 Spring MVC 文章。
2. How Spring Binds @PathVariable Parameters
2.Spring如何绑定@PathVariable参数
By default, Spring will try to bind all parameters annotated with @PathVariable in a handler method with the corresponding variables in the URI template. If Spring fails, it’ll not deliver our request to that handler method.
默认情况下,Spring会尝试将处理方法中所有用@PathVariable注释的参数与URI模板中的相应变量绑定。如果Spring失败了,它就不会将我们的请求传递给该处理方法。
For instance, consider the following getArticle method that attempts (unsuccessfully) to make the id path variable optional:
例如,考虑以下getArticle方法,该方法试图使id路径变量成为可选项(未成功)。
@RequestMapping(value = {"/article", "/article/{id}"})
public Article getArticle(@PathVariable(name = "id") Integer articleId) {
if (articleId != null) {
//...
} else {
//...
}
}
Here, the getArticle method is supposed to serve requests to both /article and /article/{id}. Spring will try to bind the articleId parameter to the id path variable if present.
这里,getArticle方法应该为/article和/article/{id}提供请求。Spring会尝试将articleId参数与id路径变量绑定,如果存在的话。
For instance, sending a request to /article/123 sets the value of articleId to 123.
例如,向/article/123发送一个请求,将articleId的值设置为123。
On the other hand, if we send a request to /article, Spring return status code 500 due to the following exception:
另一方面,如果我们向/article发送请求,Spring返回状态代码500,因为有以下异常。
org.springframework.web.bind.MissingPathVariableException:
Missing URI template variable 'id' for method parameter of type Integer
This was because Spring couldn’t set a value for the articleId parameter as id was missing.
这是因为Spring无法为articleId参数设置一个值,因为id丢失了。
So, we need some way to tell Spring to ignore binding a specific @PathVariable parameter if it has no corresponding path variable, as we’ll see in the following sections.
因此,我们需要一些方法来告诉Spring,如果一个特定的@PathVariable参数没有相应的路径变量,就忽略它的绑定,我们将在下面的章节中看到。
3. Making Path Variables Optional
3.让路径变量成为可选项
3.1. Using the required Attribute of @PathVariable
3.1.使用 @PathVariable 的 required 属性
Since Spring 4.3.3, the @PathVariable annotation defines the boolean attribute required for us to indicate if a path variable is mandatory to a handler method.
从Spring 4.3.3开始,@PathVariable注解定义了布尔属性required,以便我们表明路径变量对处理方法是否是强制性的。
For example, the following version of getArticle uses the required attribute:
例如,以下版本的getArticle使用required属性。
@RequestMapping(value = {"/article", "/article/{id}"})
public Article getArticle(@PathVariable(required = false) Integer articleId) {
if (articleId != null) {
//...
} else {
//...
}
}
Since the required attribute is false, Spring will not complain if the id path variable is not sent in the request. That is, Spring will set articleId to id if it’s sent, or null otherwise.
由于required属性是false,如果请求中没有发送id路径变量,Spring不会抱怨。也就是说,如果发送了articleId,Spring将把它设置为id,否则就设置为null。
On the other hand, if required was true, Spring would throw an exception in case id was missing.
另一方面,如果required是true,Spring会在id丢失时抛出一个异常。
3.2. Using an Optional Parameter Type
3.2.使用一个可选的参数类型
The following implementation shows how Spring 4.1, along with JDK 8’s Optional class, offers another way to make articleId optional:
下面的实现展示了Spring 4.1以及JDK 8的Optional类如何提供另一种使articleId可选的方法。
@RequestMapping(value = {"/article", "/article/{id}"}")
public Article getArticle(@PathVariable Optional<Integer> optionalArticleId) {
if (optionalArticleId.isPresent()) {
Integer articleId = optionalArticleId.get();
//...
} else {
//...
}
}
Here, Spring creates the Optional<Integer> instance, optionalArticleId, to hold the value of id. If id is present, optionalArticleId will wrap its value, otherwise, optionalArticleId will wrap a null value. Then, we can use Optional‘s isPresent(), get(), or orElse() methods to work with the value.
在这里,Spring创建了Optional<Integer>实例,optionalArticleId,以保持id的值。如果id存在,optionalArticleId将包裹其值,否则,optionalArticleId将包裹一个null值。然后,我们可以使用Optional的isPresent()、get()、或orElse()方法来处理这个值。
3.3. Using a Map Parameter Type
3.3.使用Map参数类型
Another way to define an optional path variable that is available since Spring 3.2 is with a Map for @PathVariable parameters:
另一种定义可选路径变量的方式是用@PathVariable参数的Map来定义,这种方式从Spring 3.2开始可用。
@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 {
//...
}
}
In this example, the Map<String, String> pathVarsMap parameter collects all path variables that are in the URI as a key/value pairs. Then, we can get a specific path variable using the get() method.
在这个例子中,Map<String, String> pathVarsMap参数收集了URI中的所有路径变量,作为一个键/值对。然后,我们可以使用get()方法获得一个特定的路径变量。
Note that because Spring extracts the value of a path variable as a String, we used the Integer.valueOf() method to convert it to Integer.
注意,由于Spring将路径变量的值提取为String,我们使用Integer.valueOf()方法将其转换成Integer。
3.4. Using Two Handler Methods
3.4.使用两个处理程序方法
In case we were using a legacy Spring version, we can split the getArticle handler method into two methods.
如果我们使用的是传统的Spring版本,我们可以将getArticle处理方法分成两个方法。
The first method will handle requests to /article/{id}:
第一个方法将处理对/article/{id}的请求。
@RequestMapping(value = "/article/{id}")
public Article getArticle(@PathVariable(name = "id") Integer articleId) {
//...
}
While the second method will handle requests to /article:
而第二个方法将处理对/article的请求。
@RequestMapping(value = "/article")
public Article getDefaultArticle() {
//...
}
4. Conclusion
4.总结
To sum up, we’ve discussed how to make a path variable optional in different Spring versions.
综上所述,我们已经讨论了如何在不同的Spring版本中使路径变量成为可选项。
As usual, the complete code for this article is available over on GitHub.
像往常一样,本文的完整代码可以在GitHub上找到。