标准规范 (Standards)
你当前正在浏览历史版本 Vert.x 5.1.10 的文档。 访问本页面的 最新版本。

Vert.x URI Template 模板引擎 (vertx-uri-template)

该组件是针对 RFC 6570 URI Template 标准的响应式高性能实现。

完整支持 RFC 6570 规范定义的 Level 4 全部语法。

引入依赖

要在项目中使用该组件,请在构建描述文件中添加以下依赖:

  • Maven(在 pom.xml 中):

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-uri-template</artifactId>
  <version>5.1.10</version>
</dependency>
  • Gradle(在 build.gradle 文件中):

compile '''io.vertx:vertx-uri-template:5.1.10'''

创建模板

创建 URI 模板极其简单直观:

UriTemplate template = UriTemplate.of("http://{host}/product/{id}{?sort}");

系统在创建时会对模板合法性进行严格静态校验,任何不合法的模板表达式将在创建时立即抛出异常:

UriTemplate template = UriTemplate.of("{!invalid}}"); // 将抛出解析异常

模板变量展开 (Template Expansion)

调用 expandToString 并传入变量集,即可求值生成规范合法的 URI 字符串:

UriTemplate template = UriTemplate.of("http://{host}/product/{id}{?sort}");
String uri = template.expandToString(Variables
  .variables()
  .set("host", "localhost")
  .set("id", "12345")
  .set("sort", "price")
);

Variables 负责承载模板展开所需的键值字典:

  • 设置单值普通变量:

variables.set("server", "localhost");
variables.set("port", "8080");
  • 设置列表集合变量:

variables.set("ids", Arrays.asList("123", "456"));
  • 设置 Map 键值对字典变量:

Map<String, String> query = new HashMap<>();
query.put("firstName", "Dale");
query.put("lastName", "Cooper");
variables.set("query", query);

如前所述,模板中的变量由花括号包围声明(如 {host} 引用变量 host),此展开方式称为 简单字符串展开(Simple String Expansion)。

规范还支持其他丰富的 展开风格,它们在格式组织和编码策略上各具特性。

列表在展开时默认转换为以逗号分隔的字符串:

UriTemplate template = UriTemplate.of("http://server.com/products?sort={sort}");
Variables variables = Variables.variables().set("sort", Arrays.asList("price", "name"));
assertEquals("http://server.com/products?sort=price,name", template.expandToString(variables));

同样,Map 默认展开为逗号分隔的键值对序列(例如 { "firstName": "Dale", "lastName": "Cooper" } 展开为 "firstName,Dale,lastName,Cooper");但若追加了 * 修饰符(Explode 展开),则会展开为规范的键值对:

UriTemplate template = UriTemplate.of("http://server.com/?details={details*}");
Map<String, String> details = new HashMap<>();
details.put("firstName", "Dale");
details.put("lastName", "Cooper");
Variables variables = Variables.variables().set("details", details);
assertEquals("http://server.com/?firstName=Dale,lastName=Cooper", template.expandToString(variables));

RFC 6570 展开风格速查表

1. 表单查询参数展开 (Form-Style Query Expansion)

常用于生成带 ? 前缀的 HTTP GET Query 参数。

变量输入 模板表达式 生成 URI 结果

{ "who": "fred" }

{?who}

?who=fred

{ "unreserved": "_" }

{?unreserved}

?unreserved=_

{ "reserved": "/" }

{?reserved}

?reserved=%2F

{ "pct_encoded": "%2F" }

{?pct_encoded}

?pct_encoded=%252F

{ "x": "1024", "y" : "768" }

{?x,y}

?x=1024&y=768

{ "list": [ "red", "green", "blue" ] }

{?list}

?list=red,green,blue

{ "list": [ "red", "green", "blue" ] }

{?list*}

?list=red&list=green&list=blue

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{?map}

?map=firstName,Dale,lastName,Cooper

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{?map*}

?firstName=Dale&lastName=Cooper

2. 表单查询参数延续 (Form-Style Query Continuation)

用于在已有 Query 参数的 URL 末尾继续追加参数(带 & 前缀)。

变量输入 模板表达式 生成 URI 结果

{ "who": "fred" }

{&who}

&who=fred

{ "unreserved": "_" }

{&unreserved}

&unreserved=_

{ "reserved": "/" }

{&reserved}

&reserved=%2F

{ "pct_encoded": "%2F" }

{&pct_encoded}

&pct_encoded=%252F

{ "x": "1024", "y" : "768" }

{&x,y}

&x=1024&y=768

{ "list": [ "red", "green", "blue" ] }

{&list}

&list=red,green,blue

{ "list": [ "red", "green", "blue" ] }

{&list*}

&list=red&list=green&list=blue

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{&map}

&map=firstName,Dale,lastName,Cooper

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{&map*}

&firstName=Dale&lastName=Cooper

3. 保留字符展开 (Reserved Expansion)

允许保留字符(如 /)不被转义,常用于动态拼接完整子路径。

变量输入 模板表达式 生成 URI 结果

{ "who": "fred" }

{+who}

fred

{ "unreserved": "_" }

{+unreserved}

_

{ "reserved": "/" }

{+reserved}

/

{ "pct_encoded": "%2F" }

{+pct_encoded}

%2F

{ "x": "1024", "y" : "768" }

{+x,y}

1024,768

{ "list": [ "red", "green", "blue" ] }

{+list}

red,green,blue

{ "list": [ "red", "green", "blue" ] }

{+list*}

red,green,blue

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{+map}

firstName,Dale,lastName,Cooper

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{+map*}

firstName=Dale,lastName=Cooper

4. 片段标识展开 (Fragment Expansion)

用于生成 URL 锚点 Hash(带 # 前缀)。

变量输入 模板表达式 生成 URI 结果

{ "who": "fred" }

{#who}

#fred

{ "unreserved": "_" }

{#unreserved}

#_

{ "reserved": "/" }

{保留}

#/

{ "pct_encoded": "%2F" }

{#pct_encoded}

#%2F

{ "x": "1024", "y" : "768" }

{#x,y}

#1024,768

{ "list": [ "red", "green", "blue" ] }

{#list}

#red,green,blue

{ "list": [ "red", "green", "blue" ] }

{#list*}

#red,green,blue

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{#map}

#firstName,Dale,lastName,Cooper

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{#map*}

#firstName=Dale,lastName=Cooper

5. 点前缀标签展开 (Dot-Prefix Label Expansion)

常用于文件后缀或以 . 隔开的分段命名。

变量输入 模板表达式 生成 URI 结果

{ "who": "fred" }

{.who}

.fred

{ "unreserved": "_" }

{.unreserved}

._

{ "reserved": "/" }

{.reserved}

.%2F

{ "pct_encoded": "%2F" }

{.pct_encoded}

.%252F

{ "x": "1024", "y" : "768" }

{.x,y}

.1024.768

{ "list": [ "red", "green", "blue" ] }

{.list}

.red,green,blue

{ "list": [ "red", "green", "blue" ] }

{.list*}

.red.green.blue

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{.map}

.firstName,Dale,lastName,Cooper

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{.map*}

.firstName=Dale.lastName=Cooper

6. 路径分号参数展开 (Path-Style Parameter Expansion)

常用于 Matrix URI 风格矩阵参数(带 ; 前缀)。

变量输入 模板表达式 生成 URI 结果

{ "who": "fred" }

{;who}

;who=fred

{ "unreserved": "_" }

{;unreserved}

;unreserved=_

{ "reserved": "/" }

{;reserved}

;reserved=%2F

{ "pct_encoded": "%2F" }

{;pct_encoded}

;pct_encoded=%252F

{ "x": "1024", "y" : "768" }

{;x,y}

;x=1024;y=768

{ "list": [ "red", "green", "blue" ] }

{;list}

;list=red,green,blue

{ "list": [ "red", "green", "blue" ] }

{;list*}

;list=red;list=green;list=blue

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{;map}

;map=firstName,Dale,lastName,Cooper

{ "map": { "firstName": "Dale", "lastName": "Cooper" } }

{;map*}

;firstName=Dale;lastName=Cooper

RFC 字符集对照速查

保留字符集 (Reserved Set)

!*'();:@&=+$,/?#[]

非保留字符集 (Unreserved Set)

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~