URI 链接
本节介绍 Spring Framework 中可用于处理 URI 的各种选项。 Unresolved directive in mvc-uri-building.adoc - include::partial$web/web-uris.adoc[leveloffset=+1]
相对 Servlet 请求
您可以使用 ServletUriComponentsBuilder
创建相对于当前请求的 URI,
如以下示例所示:
-
Java
-
Kotlin
HttpServletRequest request = ...
// Re-uses scheme, host, port, path, and query string...
URI uri = ServletUriComponentsBuilder.fromRequest(request)
.replaceQueryParam("accountId", "{id}")
.build("123");
val request: HttpServletRequest = ...
// Re-uses scheme, host, port, path, and query string...
val uri = ServletUriComponentsBuilder.fromRequest(request)
.replaceQueryParam("accountId", "{id}")
.build("123")
您可以创建相对于上下文路径的 URI,如以下示例所示:
-
Java
-
Kotlin
HttpServletRequest request = ...
// Re-uses scheme, host, port, and context path...
URI uri = ServletUriComponentsBuilder.fromContextPath(request)
.path("/accounts")
.build()
.toUri();
val request: HttpServletRequest = ...
// Re-uses scheme, host, port, and context path...
val uri = ServletUriComponentsBuilder.fromContextPath(request)
.path("/accounts")
.build()
.toUri()
您可以创建相对于 Servlet 的 URI(例如,/main/*
),
如以下示例所示:
-
Java
-
Kotlin
HttpServletRequest request = ...
// Re-uses scheme, host, port, context path, and Servlet mapping prefix...
URI uri = ServletUriComponentsBuilder.fromServletMapping(request)
.path("/accounts")
.build()
.toUri();
val request: HttpServletRequest = ...
// Re-uses scheme, host, port, context path, and Servlet mapping prefix...
val uri = ServletUriComponentsBuilder.fromServletMapping(request)
.path("/accounts")
.build()
.toUri()
从 5.1 版本开始, |
指向控制器的链接
Spring MVC 提供了一种机制来准备指向控制器方法的链接。例如, 以下 MVC 控制器允许创建链接:
-
Java
-
Kotlin
@Controller
@RequestMapping("/hotels/{hotel}")
public class BookingController {
@GetMapping("/bookings/{booking}")
public ModelAndView getBooking(@PathVariable Long booking) {
// ...
}
}
@Controller
@RequestMapping("/hotels/{hotel}")
class BookingController {
@GetMapping("/bookings/{booking}")
fun getBooking(@PathVariable booking: Long): ModelAndView {
// ...
}
}
您可以通过名称引用方法来准备链接,如以下示例所示:
-
Java
-
Kotlin
UriComponents uriComponents = MvcUriComponentsBuilder
.fromMethodName(BookingController.class, "getBooking", 21).buildAndExpand(42);
URI uri = uriComponents.encode().toUri();
val uriComponents = MvcUriComponentsBuilder
.fromMethodName(BookingController::class.java, "getBooking", 21).buildAndExpand(42)
val uri = uriComponents.encode().toUri()
在前面的示例中,我们提供了实际的方法参数值(在本例中为长整型值:21
)
用作路径变量并插入到 URL 中。此外,我们提供了值 42
,
用于填充任何剩余的 URI 变量,例如从类型级别请求映射继承的 hotel
变量。
如果方法有更多参数,我们可以为 URL 不需要的参数提供 null。
通常,只有 @PathVariable
和 @RequestParam
参数
与构造 URL 相关。
还有其他使用 MvcUriComponentsBuilder
的方法。例如,您可以使用
类似于通过代理进行模拟测试的技术,以避免按名称引用控制器方法,如以下示例所示
(该示例假设静态导入 MvcUriComponentsBuilder.on
):
-
Java
-
Kotlin
UriComponents uriComponents = MvcUriComponentsBuilder
.fromMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);
URI uri = uriComponents.encode().toUri();
val uriComponents = MvcUriComponentsBuilder
.fromMethodCall(on(BookingController::class.java).getBooking(21)).buildAndExpand(42)
val uri = uriComponents.encode().toUri()
当控制器方法签名需要用于
|
前面的示例使用 MvcUriComponentsBuilder
中的静态方法。在内部,它们依赖于
ServletUriComponentsBuilder
,从当前请求的 scheme、host、port、
context path 和 servlet path 准备基本 URL。这在大多数情况下都有效。
但是,有时可能不够。例如,您可能在请求上下文之外
(例如,准备链接的批处理过程),或者您可能需要插入路径
前缀(例如,已从请求路径中删除并需要
重新插入到链接中的语言环境前缀)。
对于这种情况,您可以使用接受 UriComponentsBuilder
的静态 fromXxx
重载方法来使用基本 URL。
或者,您可以创建一个 MvcUriComponentsBuilder
实例,其中包含基本 URL,然后使用基于实例的 withXxx
方法。例如,
以下列表使用 withMethodCall
:
-
Java
-
Kotlin
UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en");
MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);
URI uri = uriComponents.encode().toUri();
val base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en")
val builder = MvcUriComponentsBuilder.relativeTo(base)
builder.withMethodCall(on(BookingController::class.java).getBooking(21)).buildAndExpand(42)
val uri = uriComponents.encode().toUri()
从 5.1 版本开始, |
视图中的链接
在 Thymeleaf、FreeMarker 或 JSP 等视图中,您可以通过引用每个请求映射的隐式或显式分配名称来构建指向带注解控制器的链接。
考虑以下示例:
-
Java
-
Kotlin
@RequestMapping("/people/{id}/addresses")
public class PersonAddressController {
@RequestMapping("/{country}")
public HttpEntity<PersonAddress> getAddress(@PathVariable String country) { ... }
}
@RequestMapping("/people/{id}/addresses")
class PersonAddressController {
@RequestMapping("/{country}")
fun getAddress(@PathVariable country: String): HttpEntity<PersonAddress> { ... }
}
给定前面的控制器,您可以从 JSP 准备一个链接,如下所示:
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
...
<a href="${s:mvcUrl('PAC#getAddress').arg(0,'US').buildAndExpand('123')}">Get Address</a>
前面的示例依赖于 Spring 标签库中声明的 mvcUrl
函数
(即 META-INF/spring.tld),但很容易定义您自己的函数或为其他模板技术准备一个类似的函数。
其工作原理如下。在启动时,每个 @RequestMapping
都通过 HandlerMethodMappingNamingStrategy
分配一个默认名称,
其默认实现使用类名和方法名的大写字母(例如,ThingController
中的 getThing
方法变为 "TC#getThing")。
如果存在名称冲突,您可以使用 @RequestMapping(name="..")
分配显式名称或实现您自己的
HandlerMethodMappingNamingStrategy
。