| 
         此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.1.10!  | 
    
| 
         此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.1.10!  | 
    
本节介绍 Spring Framework 中可用于处理 URI 的各种选项。
UriComponents
Spring MVC 和 Spring WebFlux
UriComponentsBuilder帮助从具有变量的 URI 模板生成 URI,如以下示例所示:
- 
Java
 - 
Kotlin
 
UriComponents uriComponents = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}") (1)
		.queryParam("q", "{q}") (2)
		.encode() (3)
		.build(); (4)
URI uri = uriComponents.expand("Westin", "123").toUri(); (5)
| 1 | 具有 URI 模板的静态工厂方法。 | 
| 2 | 添加或替换 URI 组件。 | 
| 3 | 请求对 URI 模板和 URI 变量进行编码。 | 
| 4 | 构建一个 .UriComponents | 
| 5 | 展开变量并获取 .URI | 
val uriComponents = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}") (1)
		.queryParam("q", "{q}") (2)
		.encode() (3)
		.build() (4)
val uri = uriComponents.expand("Westin", "123").toUri() (5)
| 1 | 具有 URI 模板的静态工厂方法。 | 
| 2 | 添加或替换 URI 组件。 | 
| 3 | 请求对 URI 模板和 URI 变量进行编码。 | 
| 4 | 构建一个 .UriComponents | 
| 5 | 展开变量并获取 .URI | 
前面的例子可以合并成一个链,并用 缩短为 ,
如以下示例所示:buildAndExpand
- 
Java
 - 
Kotlin
 
URI uri = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}")
		.queryParam("q", "{q}")
		.encode()
		.buildAndExpand("Westin", "123")
		.toUri();
val uri = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}")
		.queryParam("q", "{q}")
		.encode()
		.buildAndExpand("Westin", "123")
		.toUri()
你可以通过直接进入 URI(这意味着编码)来进一步缩短它, 如以下示例所示:
- 
Java
 - 
Kotlin
 
URI uri = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}")
		.queryParam("q", "{q}")
		.build("Westin", "123");
val uri = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}")
		.queryParam("q", "{q}")
		.build("Westin", "123")
您可以使用完整的 URI 模板进一步缩短它,如以下示例所示:
- 
Java
 - 
Kotlin
 
URI uri = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}?q={q}")
		.build("Westin", "123");
val uri = UriComponentsBuilder
		.fromUriString("https://example.com/hotels/{hotel}?q={q}")
		.build("Westin", "123")
| 1 | 具有 URI 模板的静态工厂方法。 | 
| 2 | 添加或替换 URI 组件。 | 
| 3 | 请求对 URI 模板和 URI 变量进行编码。 | 
| 4 | 构建一个 .UriComponents | 
| 5 | 展开变量并获取 .URI | 
| 1 | 具有 URI 模板的静态工厂方法。 | 
| 2 | 添加或替换 URI 组件。 | 
| 3 | 请求对 URI 模板和 URI 变量进行编码。 | 
| 4 | 构建一个 .UriComponents | 
| 5 | 展开变量并获取 .URI | 
UriBuilder的
Spring MVC 和 Spring WebFlux
UriComponentsBuilder 实现 。您可以依次创建一个 ,并带有 .一起,并提供一种可插入机制,以基于 URI 模板构建 URI
共享配置,例如基本 URL、编码首选项和其他详细信息。UriBuilderUriBuilderUriBuilderFactoryUriBuilderFactoryUriBuilder
您可以配置 和 来自定义 URI 的准备。 是默认值
在内部使用和
公开共享配置选项。RestTemplateWebClientUriBuilderFactoryDefaultUriBuilderFactoryUriBuilderFactoryUriComponentsBuilder
以下示例演示如何配置:RestTemplate
- 
Java
 - 
Kotlin
 
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode
val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES
val restTemplate = RestTemplate()
restTemplate.uriTemplateHandler = factory
以下示例配置:WebClient
- 
Java
 - 
Kotlin
 
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode
val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES
val client = WebClient.builder().uriBuilderFactory(factory).build()
此外,您也可以直接使用。它类似于 use,但它不是静态工厂方法,而是一个实际实例
它包含配置和首选项,如以下示例所示:DefaultUriBuilderFactoryUriComponentsBuilder
- 
Java
 - 
Kotlin
 
String baseUrl = "https://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
		.queryParam("q", "{q}")
		.build("Westin", "123");
val baseUrl = "https://example.com"
val uriBuilderFactory = DefaultUriBuilderFactory(baseUrl)
val uri = uriBuilderFactory.uriString("/hotels/{hotel}")
		.queryParam("q", "{q}")
		.build("Westin", "123")
URI 编码
Spring MVC 和 Spring WebFlux
UriComponentsBuilder在两个级别公开编码选项:
- 
UriComponentsBuilder#encode(): 首先对 URI 模板进行预编码,然后在展开时严格编码 URI 变量。
 - 
UriComponents#encode(): 在展开 URI 变量后对 URI 组件进行编码。
 
这两个选项都将非 ASCII 和非法字符替换为转义八位字节。但是,第一种选择 还会替换 URI 变量中显示的具有保留含义的字符。
| 考虑“;”,它在路径中是合法的,但具有保留的含义。第一个选项将 “;” 在 URI 变量中带有“%3B”,但在 URI 模板中则不然。相比之下,第二种选择永远不会 替换“;”,因为它是路径中的合法字符。 | 
在大多数情况下,第一个选项可能会给出预期的结果,因为它处理 URI 变量作为要完全编码的不透明数据,而第二个选项在 URI 时很有用 变量确实有意包含保留字符。第二个选项也很有用 当根本不扩展 URI 变量时,因为这也将编码任何 顺便说一句,看起来像一个 URI 变量。
下面的示例使用第一个选项:
- 
Java
 - 
Kotlin
 
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
		.queryParam("q", "{q}")
		.encode()
		.buildAndExpand("New York", "foo+bar")
		.toUri();
// Result is "/hotel%20list/New%20York?q=foo%2Bbar"
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
		.queryParam("q", "{q}")
		.encode()
		.buildAndExpand("New York", "foo+bar")
		.toUri()
// Result is "/hotel%20list/New%20York?q=foo%2Bbar"
您可以通过直接转到 URI(这意味着编码)来缩短前面的示例, 如以下示例所示:
- 
Java
 - 
Kotlin
 
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
		.queryParam("q", "{q}")
		.build("New York", "foo+bar");
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
		.queryParam("q", "{q}")
		.build("New York", "foo+bar")
您可以使用完整的 URI 模板进一步缩短它,如以下示例所示:
- 
Java
 - 
Kotlin
 
URI uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
		.build("New York", "foo+bar");
val uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
		.build("New York", "foo+bar")
和 展开和编码 URI 模板内部通过
策略。两者都可以使用自定义策略进行配置,
如以下示例所示:WebClientRestTemplateUriBuilderFactory
- 
Java
 - 
Kotlin
 
String baseUrl = "https://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
// Customize the RestTemplate..
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
val baseUrl = "https://example.com"
val factory = DefaultUriBuilderFactory(baseUrl).apply {
	encodingMode = EncodingMode.TEMPLATE_AND_VALUES
}
// Customize the RestTemplate..
val restTemplate = RestTemplate().apply {
	uriTemplateHandler = factory
}
// Customize the WebClient..
val client = WebClient.builder().uriBuilderFactory(factory).build()
该实现在内部使用
展开并编码 URI 模板。作为工厂,它提供了一个单一的配置位置
基于以下编码模式之一的编码方法:DefaultUriBuilderFactoryUriComponentsBuilder
- 
TEMPLATE_AND_VALUES:用途,对应于 前面列表中的第一个选项,用于对 URI 模板进行预编码,并在以下情况下严格编码 URI 变量 扩大。UriComponentsBuilder#encode() - 
VALUES_ONLY:不对 URI 模板进行编码,而是应用严格的编码 到 URI 变量,然后将它们扩展到 模板。UriUtils#encodeUriVariables - 
URI_COMPONENT:使用对应于前面列表中的第二个选项的 在 URI 变量展开后对 URI 组件值进行编码。UriComponents#encode() - 
NONE:不应用编码。 
设置为历史
原因和向后兼容性。依赖于默认值
in ,从 in 更改而来
5.0.x 到 5.1 中。RestTemplateEncodingMode.URI_COMPONENTWebClientDefaultUriBuilderFactoryEncodingMode.URI_COMPONENTEncodingMode.TEMPLATE_AND_VALUES
| 考虑“;”,它在路径中是合法的,但具有保留的含义。第一个选项将 “;” 在 URI 变量中带有“%3B”,但在 URI 模板中则不然。相比之下,第二种选择永远不会 替换“;”,因为它是路径中的合法字符。 | 
相对 Servlet 请求
您可以使用创建相对于当前请求的 URI,
如以下示例所示:ServletUriComponentsBuilder
- 
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 开始,忽略来自 和 标头的信息,这些标头指定客户端源自地址。请考虑使用 ForwardedHeaderFilter 提取并使用或丢弃
这样的标头。ServletUriComponentsBuilderForwardedX-Forwarded-* | 
从 5.1 开始,忽略来自 和 标头的信息,这些标头指定客户端源自地址。请考虑使用 ForwardedHeaderFilter 提取并使用或丢弃
这样的标头。ServletUriComponentsBuilderForwardedX-Forwarded-* | 
控制器链接
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()
在前面的示例中,我们提供了实际的方法参数值(在本例中为 long 值:)
用作路径变量并插入到 URL 中。此外,我们还提供
value, 填充任何剩余的 URI 变量,例如继承的变量
从类型级请求映射。如果该方法有更多的参数,我们可以为
URL 不需要参数。一般来说,只有和参数
与构造 URL 相关。2142hotel@PathVariable@RequestParam
还有其他方法可以使用 .例如,您可以使用一种技术
类似于通过代理进行模拟测试,以避免按名称引用控制器方法,如以下示例所示
(该示例假设静态导入:MvcUriComponentsBuilderMvcUriComponentsBuilder.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()
控制器方法签名在其设计中受到限制,而它们应该可用于
使用 .除了需要适当的参数签名外,
返回类型(即生成运行时代理)存在技术限制
),因此返回类型不能为 。特别
视图名称的通用返回类型在这里不起作用。您应该改用甚至普通(带有返回值)。fromMethodCallfinalStringModelAndViewObjectString | 
前面的示例在 中使用 的静态方法。在内部,他们依赖
on 从方案、主机、端口、
上下文路径和当前请求的 servlet 路径。这在大多数情况下效果很好。
但是,有时,它可能是不够的。例如,您可能不在上下文中
请求(例如准备链接的批处理),或者可能需要插入路径
前缀(例如从请求路径中删除的区域设置前缀,需要
重新插入到链接中)。MvcUriComponentsBuilderServletUriComponentsBuilder
对于这种情况,可以使用接受 的静态重载方法来使用基 URL。或者,您可以使用基 URL 创建实例,然后使用基于实例的方法。例如,
以下列表用途:fromXxxUriComponentsBuilderMvcUriComponentsBuilderwithXxxwithMethodCall
- 
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 开始,忽略来自 和 标头的信息,这些标头指定客户端源自地址。请考虑使用 ForwardedHeaderFilter 提取并使用或丢弃
这样的标头。MvcUriComponentsBuilderForwardedX-Forwarded-* | 
控制器方法签名在其设计中受到限制,而它们应该可用于
使用 .除了需要适当的参数签名外,
返回类型(即生成运行时代理)存在技术限制
),因此返回类型不能为 。特别
视图名称的通用返回类型在这里不起作用。您应该改用甚至普通(带有返回值)。fromMethodCallfinalStringModelAndViewObjectString | 
从 5.1 开始,忽略来自 和 标头的信息,这些标头指定客户端源自地址。请考虑使用 ForwardedHeaderFilter 提取并使用或丢弃
这样的标头。MvcUriComponentsBuilderForwardedX-Forwarded-* | 
视图中的链接
在 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 标记库中声明的函数
(即 META-INF/spring.tld),但很容易定义自己的函数或准备一个
其他模板技术也类似。mvcUrl
这是如何工作的。在启动时,每个都会被分配一个默认名称
through ,其默认实现使用
类和方法名称的大写字母(例如,中的方法变为“TC#getThing”)。如果存在名称冲突,则可以使用来分配显式名称或实现自己的名称。@RequestMappingHandlerMethodMappingNamingStrategygetThingThingController@RequestMapping(name="..")HandlerMethodMappingNamingStrategy