介绍
在本教程中,我们将重点介绍 Spring UriComponentsBuilder。更具体地说,我们将介绍各种实际的实现示例。
UriComponentsBuilder 是 Spring 提供的一个 UriComponents 类的构建类,通过它可以方便的构建 URI 地址。
Maven 依赖
为了使用构建器,我们需要在 pom.xml 的依赖项中添加以下部分:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
最新版本可以在这里找到:https://search.maven.org/search?q=a:spring-web%20AND%20g:org.springframework
这种依赖关系仅涵盖 Spring Web,因此请不要忘记为完整的 Web 应用程序添加 spring-context。
实例化方法
public static UriComponentsBuilder newInstance();
public static UriComponentsBuilder fromPath(String path);
public static UriComponentsBuilder fromUri(URI uri);
public static UriComponentsBuilder fromUriString(String uri);
public static UriComponentsBuilder fromHttpUrl(String httpUrl);
public static UriComponentsBuilder fromHttpRequest(HttpRequest request);
public static UriComponentsBuilder fromOriginHeader(String origin);
UriComponentsBuilder 提供了 7 种实例化的方法,根据不同的需求选择对应的方法实例化 UriComponentsBuilder 对象。
- newInstance():实例化一个没有任何参数的 UriComponentsBuilder 对象;
- fromUri():通过 URI 参数来创建 UriComponentsBuilder 实例;
- fromUriString():通过 URI 字符串来创建 UriComponentsBuilder 实例,比如可以传 https://www.baidu.com/、www.baidu.com 等,只需要满足源码中的正则表达式(org.springframework.web.util.UriComponentsBuilder#URI_PATTERN);
- fromHttpUrl():通过 HTTP URL 字符串来创建 UriComponentsBuilder 实例,比如可以传 https://www.baidu.com/,只需要满足源码中的正则表达式(org.springframework.web.util.UriComponentsBuilder#HTTP_URL_PATTERN);
- fromHttpRequest():通过 HttpRequest 参数来创建 UriComponentsBuilder 实例;
- fromOriginHeader():通过解析 HTTP 请求的“ Origin”标头来创建 UriComponentsBuilder 实例。
对于 fromHttpRequest() 和 fromOriginHeader() 方法的使用参考如下案例:
public static boolean isSameOrigin(HttpRequest request) {
String origin = request.getHeaders().getOrigin();
if (origin == null) {
return true;
}
UriComponents actualUrl = UriComponentsBuilder.fromHttpRequest(request).build();
UriComponents originUrl = UriComponentsBuilder.fromOriginHeader(origin).build();
return (actualUrl.getHost().equals(originUrl.getHost()) && getPort(actualUrl) == getPort(originUrl));
}
使用案例
UriComponentsBuilder 有许多实际的用例,从对应的 URI 组件中不允许的字符的上下文编码开始,到动态替换 URL 的各个部分为止。
UriComponentsBuilder 的最大优点之一是我们可以将其直接注入到 Controller 方法中:
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity createCustomer(UriComponentsBuilder builder) {
// implementation
}
让我们开始一个一个地描述示例,我们将使用 JUnit 框架立即测试我们的实现。
构建一个简单的 URI
让我们从最简单的开始,使用 UriComponentsBuilder 创建一个简单的链接:
@Test
public void constructUri() {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("http").host("www.baeldung.com").path("/junit-5").build();
assertEquals("/junit-5", uriComponents.toUriString());
}
如我们所见,我们创建了一个新的 UriComponentsBuilder 实例,然后提供了 scheme 类型,host 和到请求目标的路径。
构建一个编码的 URI
除了构建简单的链接外,我们可能还希望对最终结果进行编码。让我们看看下面这个例子:
@Test
public void constructUriEncoded() {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("http").host("www.baeldung.com").path("/junit 5").build().encode();
assertEquals("/junit%205", uriComponents.toUriString());
}
这个例子的不同之处在于,我们要在 junit 和数字 5 之间添加空格。根据 RFC 3986,这是不可能的。我们需要使用 encode()
方法对链接进行编码,以达到有效的结果。
从模板构建一个 URI
URI 模板允许在 URI 的大多数组件中使用,但其值仅限于特定的元素,我们将其作为模板。让我们看看下面这个例子:
@Test
public void constructUriFromTemplate() {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("http").host("www.baeldung.com").path("/{article-name}")
.buildAndExpand("junit-5");
assertEquals("/junit-5", uriComponents.toUriString());
}
在这个例子中,不同之处在于我们声明路径的方式和构建最终 URI 的方式。在 path()
方法里面,将被关键字替换的模板用括号 {…} 表示。在名为 buildAndExpand()
的方法中使用了用于生成最终链接的关键字。
请注意,可能有多个关键字要被替换。另外,URI 的路径可以是相对的。
使用查询参数构建 URI
另一个非常有用的情况是构建带有查询参数的 URI。
我们需要使用 UriComponentsBuilder 的 query()
方法来指定 URI 的查询参数。让我们看看下面的例子:
@Test
public void constructUriWithQueryParameter() {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("http").host("www.google.com")
.path("/").query("q={keyword}").buildAndExpand("baeldung");
assertEquals("http://www.google.com/?q=baeldung", uriComponents.toUriString());
}
该查询将被添加到链接的主要部分。我们可以提供多个查询参数,使用括号 {…}。它们将在名为 buildAndExpand()
的方法中被关键字替换。
使用正则表达式扩展 URI
最后一个例子展示的是一个带有 regex 验证的 URI 的构造。只有在 regex 验证成功的情况下,我们才能扩展 uriComponents。
@Test
public void expandWithRegexVar() {
String template = "/myurl/{name:[a-z]{1,5}}/show";
UriComponents uriComponents = UriComponentsBuilder.fromUriString(template)
.build();
uriComponents = uriComponents.expand(Collections.singletonMap("name", "test"));
assertEquals("/myurl/test/show", uriComponents.getPath());
}
在上述例子中,我们可以看到,链接的中间部分只能添加 a-z 的字母,长度在1-5之间。
另外,我们还使用了 singletonMap,将关键字名替换为值。
当我们允许用户动态地指定链接,但我们想提供一种安全保障,只有有效的链接才能在我们的 Web 应用程序中工作时,这个例子特别有用。
转载
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/uup1gh 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。