IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> spring框架学习 - Spring MVC 之 URI 链接 -> 正文阅读

[Java知识库]spring框架学习 - Spring MVC 之 URI 链接

接上一篇博客:https://blog.csdn.net/qq_43605444/article/details/122148706?spm=1001.2014.3001.5502

5、URI 链接

本节介绍 Spring Framework 中可用于处理 URI 的各种选项。

5.1 UriComponents

UriComponentsBuilder 帮助从带有变量的 URI 模板构建 URI,如以下示例所示:

UriComponents uriComponents = UriComponentsBuilder
    	// 带有 URI 模板的静态工厂方法。
        .fromUriString("https://example.com/hotels/{hotel}")  
    	// 添加或替换 URI 组件。
        .queryParam("q", "{q}")
    	// 请求对 URI 模板和 URI 变量进行编码。
        .encode() 
    	// 构建一个 UriComponents。
        .build(); 
// 展开变量并获取 URI。
URI uri = uriComponents.expand("Westin", "123").toUri();  

// https://example.com/hotels/Westin?q=123

可以将前面的示例合并为一个链并使用 buildAndExpand 缩短,如下例所示:

URI uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")
        .queryParam("q", "{q}")
        .encode()
        .buildAndExpand("Westin", "123")
        .toUri();

// https://example.com/hotels/Westin?q=123

您可以通过直接转到 URI(这意味着编码)来进一步缩短它,如以下示例所示:

URI uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")
        .queryParam("q", "{q}")
        .build("Westin", "123");

// https://example.com/hotels/Westin?q=123

您仍然可以使用完整的 URI 模板进一步缩短它,如以下示例所示:

URI uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}?q={q}")
        .build("Westin", "123");

// https://example.com/hotels/Westin?q=123

5.2 UriBuilder

UriComponentsBuilder 实现了 UriBuilder。 反过来,您可以使用 UriBuilderFactory 创建 UriBuilderUriBuilderFactoryUriBuilder 共同提供了一种可插拔机制,可根据共享配置(例如基本 URL、编码首选项和其他详细信息)从 URI 模板构建 URI。

您可以使用 UriBuilderFactory 配置 RestTemplateWebClient 来自定义 URI 的准备。 DefaultUriBuilderFactoryUriBuilderFactory 的默认实现,它在内部使用 UriComponentsBuilder 并公开共享配置选项。

以下示例显示了如何配置 RestTemplate

// 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);

以下示例配置了一个 WebClient

// 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();

此外,您还可以直接使用 DefaultUriBuilderFactory。 它类似于使用 UriComponentsBuilder,但它不是静态工厂方法,而是一个包含配置和首选项的实际实例,如以下示例所示:

String baseUrl = "https://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);

URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
        .queryParam("q", "{q}")
        .build("Westin", "123");

5.3 URI 编码

UriComponentsBuilder 公开了两个级别的编码选项:

  • UriComponentsBuilder#encode():先对URI模板进行预编码,然后在展开时对URI变量进行严格编码。
  • UriComponents#encode():在扩展 URI 变量后对 URI 组件进行编码。

这两个选项都用转义的八位字节替换非 ASCII 和非法字符。 但是,第一个选项也会替换出现在 URI 变量中的具有保留含义的字符。

考虑“;”,它在路径中是合法的,但具有保留的含义。 第一个选项替换“;” 在 URI 变量中带有“%3B”但不在 URI 模板中。 相比之下,第二个选项永远不会替换“;”,因为它是路径中的合法字符。

在大多数情况下,第一个选项可能会给出预期的结果,因为它将 URI 变量视为要完全编码的不透明数据,而如果 URI 变量有意包含保留字符,则第二个选项很有用。 当根本不扩展 URI 变量时,第二个选项也很有用,因为这也会对任何看起来像 URI 变量的东西进行编码。

以下示例使用第一个选项:

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"

您可以通过直接转到 URI(这意味着编码)来缩短前面的示例,如以下示例所示:

URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
        .queryParam("q", "{q}")
        .build("New York", "foo+bar");

您仍然可以使用完整的 URI 模板进一步缩短它,如以下示例所示:

URI uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
        .build("New York", "foo+bar");

WebClientRestTemplate 通过 UriBuilderFactory 策略在内部扩展和编码 URI 模板。 两者都可以使用自定义策略进行配置,如以下示例所示:

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();

DefaultUriBuilderFactory实现在内部使用 UriComponentsBuilder 来扩展和编码 URI 模板。 作为一个工厂,它提供了一个单一的地方来配置编码方法,基于以下编码模式之一:

  • TEMPLATE_AND_VALUES:使用 UriComponentsBuilder#encode(),对应于前面列表中的第一个选项,对 URI 模板进行预编码,并在扩展时对 URI 变量进行严格编码。
  • VALUES_ONLY:不对 URI 模板进行编码,而是在将 URI 变量扩展到模板之前通过 UriUtils#encodeUriVariables 对 URI 变量应用严格编码。
  • URI_COMPONENT:使用 UriComponents#encode(),对应前面列表中的第二个选项,在 URI 变量扩展后对 URI 组件值进行编码。
  • NONE:不应用编码。

出于历史原因和向后兼容性,将 RestTemplate 设置为 EncodingMode.URI_COMPONENTWebClient 依赖于 DefaultUriBuilderFactory 中的默认值,该值从 5.0.x 中的 EncodingMode.URI_COMPONENT 更改为 5.1 中的 EncodingMode.TEMPLATE_AND_VALUES

5.4 响应 Servlet 请求

您可以使用 ServletUriComponentsBuilder 创建相对于当前请求的 URI,如以下示例所示:

HttpServletRequest request = ...

// Re-uses host, scheme, port, path and query string...

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromRequest(request)
        .replaceQueryParam("accountId", "{id}").build()
        .expand("123")
        .encode();

您可以创建相对于上下文路径的 URI,如以下示例所示:

// Re-uses host, port and context path...

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromContextPath(request)
        .path("/accounts").build()

您可以创建相对于 Servlet(例如,/main/*)的 URI,如以下示例所示:

// Re-uses host, port, context path, and Servlet prefix...

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromServletMapping(request)
        .path("/accounts").build()

从 5.1 开始,ServletUriComponentsBuilder 会忽略来自 ForwardedX-Forwarded-* 标头的信息,这些标头指定了源自客户端的地址。 考虑使用 ForwardedHeaderFilter 来提取和使用或丢弃此类标头。

5.5 链接到控制器

Spring MVC 提供了一种机制来准备指向控制器方法的链接。 例如,以下 MVC 控制器允许创建链接:

@Controller
@RequestMapping("/hotels/{hotel}")
public class BookingController {

    @GetMapping("/bookings/{booking}")
    public ModelAndView getBooking(@PathVariable Long booking) {
        // ...
    }
}

您可以通过按名称引用方法来准备链接,如下例所示:

UriComponents uriComponents = MvcUriComponentsBuilder
    .fromMethodName(BookingController.class, "getBooking", 21).buildAndExpand(42);

URI uri = uriComponents.encode().toUri();

在前面的示例中,我们提供了实际的方法参数值(在这种情况下,长值:21)用作路径变量并插入到 URL 中。 此外,我们提供值 42 来填充任何剩余的 URI 变量,例如从类型级请求映射继承的 hotel 变量。 如果该方法有更多参数,我们可以为 URL 不需要的参数提供 null。 通常,只有 @PathVariable@RequestParam 参数与构造 URL 相关。

还有其他方法可以使用 MvcUriComponentsBuilder。 例如,您可以使用类似于通过代理进行模拟测试的技术来避免通过名称引用控制器方法,如下例所示(该示例假定静态导入 MvcUriComponentsBuilder.on):

UriComponents uriComponents = MvcUriComponentsBuilder
    .fromMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);

URI uri = uriComponents.encode().toUri();

控制器方法签名在其设计中受到限制,因为它们应该可用于使用 fromMethodCall 创建链接。 除了需要正确的参数签名外,返回类型还存在技术限制(即,为链接构建器调用生成运行时代理),因此返回类型不能是final 的。 特别是,视图名称的常见 String返回类型在这里不起作用。 您应该改用 ModelAndView 甚至普通 Object(带有 String 返回值)。

前面的示例在 MvcUriComponentsBuilder中使用静态方法。 在内部,它们依靠 ServletUriComponentsBuilder 从当前请求的方案、主机、端口、上下文路径和 servlet 路径准备基本 URL。 这在大多数情况下效果很好。 然而,有时,它可能是不够的。例如,您可能在请求的上下文之外(例如准备链接的批处理),或者您可能需要插入路径前缀(例如从请求路径中删除并需要重新插入链接的区域设置前缀)。

对于这种情况,您可以使用接受 UriComponentsBuilder 的静态 fromXxx 重载方法来使用基本 URL。 或者,您可以使用基本 URL 创建 MvcUriComponentsBuilder 的实例,然后使用基于实例的 withXxx 方法。 例如,以下清单使用 withMethodCall

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();

从 5.1 开始,MvcUriComponentsBuilder 会忽略来自 ForwardedX-Forwarded-* 标头的信息,这些标头指定了源自客户端的地址。 考虑使用 ForwardedHeaderFilter 来提取和使用或丢弃此类标头。

5.6 视图中的链接

在 Thymeleaf、FreeMarker 或 JSP 等视图中,您可以通过为每个请求映射引用隐式或显式分配的名称来构建到带注解的控制器的链接。

考虑以下示例:

@RequestMapping("/people/{id}/addresses")
public class PersonAddressController {

    @RequestMapping("/{country}")
    public HttpEntity<PersonAddress> getAddress(@PathVariable String country) { ... }
}

给定前面的控制器,您可以从 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 函数,但是很容易定义自己的函数或为其他模板技术准备一个类似的函数。

这是它的工作原理。 启动时,每个 @RequestMapping 通过 HandlerMethodMappingNamingStrategy 分配一个默认名称,其默认实现使用类的大写字母和方法名称(例如 ThingController 中的 getThing 方法变为“TC#getThing”)。 如果存在名称冲突,您可以使用 @RequestMapping(name="..") 来分配显式名称或实现您自己的 HandlerMethodMappingNamingStrategy

文章参考:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-uri-building

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-26 22:00:25  更:2021-12-26 22:01:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:14:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码