18.6 请求参数和路径变量

18.6 请求参数和路径变量

请求参数和路径变量都可以用于发送值给服务器。二者都是URL的一部分。请求参数采用key=value形式,并用“&”分隔。例如,下面的URL带有一个名为productId的请求参数,其值为3

1
http://localhost:8080/app18b/product_retrieve?productId=3

在传统的Servlet编程中,可以使用HttpServletRequestgetParameter方法来获取一个请求参数值:

1
String productId = httpServletRequest.getParameter("productId");

Spring MVC提供了一个更简单的方法来获取请求参数值:通过使用org.springframework.web.bind.annotation.RequestParam注解类型来注解方法参数。例如,下面的方法包含了一个获取请求参数productId值的参数:

1
public void sendProduct(@RequestParam int productId)

正如你所看到的,@RequestParam注解的参数类型不一定是字符串。
路径变量类似请求参数,但没有key部分,只是一个值。例如,在app18b中,product_view动作映射到如下URL

1
/product_view/productId

其中的productId是表示产品标识符的整数。在Spring MVC中,productId被称作路径变量,用来发送一个值到服务器。
下面的viewProduct方法演示了一个路径变量的使用。

使用路径变量

1
2
3
4
5
6
7
8
9
@RequestMapping(
value = "/product_view/{id}"
)
public String viewProduct(@PathVariable Long id, Model model)
{
Product product = productService.get(id);
model.addAttribute("product", product);
return "ProductView";
}

为了使用路径变量,首先需要在RequestMapping注解的值属性中添加一个变量,该变量必须放在花括号之间。例如,下面的RequestMapping注解定义了一个名为id的路径变量:

1
2
3
@RequestMapping(
value = "/product_view/{id}"
)

然后,在方法签名中添加一个同名变量,并加上@PathVariable注解。上面的中viewProduct的方法签名。当该方法被调用时,请求URLid值将被复制到路径变量中,并可以在方法中使用。路径变量的类型可以不是字符串Spring MVC将尽力转换为非字符串类型。这个Spring MVC的强大功能会在第19章中详细讨论。
可以在请求映射中使用多个路径变量。例如,下面定义了userIdorderId两个路径变量:

1
2
3
@RequestMapping(
value = "/product_view/{userId}/{orderId}"
)

请直接将浏览器输入到如下URL,来测试viewProduct方法的路径变量:
http://localhost:8080/app18b/product_view/1
有时,使用路径变量时会遇到一个小问题:在某些情况下,浏览器可能会误解路径变量。考虑下面的URL

1
http://example.com/context/abc

浏览器会(正确)认为abc是一个动作。任何静态文件路径的解析,如CSS文件时,将使用http://example.com/context作为基本路径。这就是说,若服务器发送的网页包含如下`img`元素:

1
<img src="logo.png"/>

该浏览器将试图通过http://example.com/context/logo.png来加载logo.png
然而,若一个应用程序被部署为默认上下文(默认上下文路径是一个空字符串),则对于同一个目标的URL,会是这样的:

1
http://example.com/abc

下面是在带有路径变量的URL

1
http://example.com/abc/1

在这种情况下,浏览器会认为abc是上下文,没有动作。
如果在页面中使用<img src="logo. png"/>,浏览器将试图通过http://example.com/abc/logo.png来寻找图像,最终它将找不到该图像。
幸运的是,我们有一个简单的解决方案,即通过使用JSTL标记的URL(我们已经在第5章中详细讨论了JSTL)。标签会通过正确解析URL来修复该问题。例如,app18b中所有的JSP页面导入的所有CSS,从

1
<style type="text/css">@import url(css/main.css);</style>

修改为

1
2
3
<style type="text/css">
@import url("<c:url value="/css/main.css"/>");
</style>

若程序部署为默认上下文,链接标签会将该URL转换成如下形式:

1
<style type="text/css">@import url("/css/main.css");</style>

若程序不在默认上下文中,则它会被转换成如下形式:

1
<style type="text/css">@import url("/app18b/css/main.css");</style>