Vert.x URI/资源标识符模版

URI 模版意见稿 的一个实现。

此次实现了级别 4 的规范。

警告
这个模块处于 Tech Preview 阶段,这意味着在不同版本之间API可能会不太一样。

使用 URI 模版

要使用此组件,请将以下依赖项添加到构建描述符的依赖项部分:

  • Maven(在您的`pom.xml`中):

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

compile io.vertx:vertx-uri-template:4.4.0

模版

您可以轻松创建一个模版

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

只能创建有效的模板,任何无效的模板都会在创建时被拒绝并出现异常:

UriTemplate template = UriTemplate.of("{!invalid}}"); // Will throw an exception

模版扩展

您可以使用带有变量列表的 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<String, String> query = new HashMap<>();
query.put("firstName", "Dale");
query.put("lastName", "Cooper");
variables.set("query", query);

如上所述,变量通过在模板中用大括号括起来的名称引用,例如 {host} 引用 host 变量, 该扩展称为 简单字符串扩展

注意
还有其他的扩展样式,它们与简单的字符串扩展的区别在于它们的格式和编码。

列表扩展为逗号分隔值

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

同样,映射值扩展为逗号分隔值,例如 { "firstName": "Dale", "lastName": "Cooper" } 扩展为 "firstName,Dale,lastName,Cooper" , 除非它们是带有 星号 修饰符的 展开值

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

模板编码

预留集以及非预留集以外的文字字符则采用 百分比编码

assertEquals("http://server.com/currency/%E2%82%AC", UriTemplate.of("http://server.com/currency/€").expandToString(variables));

简单的字符串扩展则将 非预留 集合之外的任何字符编码为其百分比编码等效项:

Variables variables = Variables.variables();
variables.set("currency", "€")
assertEquals("http://server.com/currency/%E2%82%AC", UriTemplate.of("http://server.com/currency/{currency}").expandToString(variables));

扩展样式

除了简单的字符串扩展,你还可以使用其他扩展方式,扩展遵循语法 '{' 运算符?变量名'}'

简单的字符串扩展

未给出运算符时的默认扩展样式。

  • 语法:{变量名}

  • 允许的字符:非预留

变量 模版 URI/资源标识符

{ "who": "fred" }

{who}

fred

{ "unreserved": "_" }

{unreserved}

_

{ "reserved": "/" }

{reserved}

%2F

{ "pct_encoded": "%2F" }

{pct_encoded}

%252F

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

{x,y}

1024/y768

{ "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

路径段扩展

路径段扩展对于创建分层 URI 路径很有用。

  • 语法:{/变量名}

  • 允许的字符:非预留

变量 模版 URI/资源标识符

{ "who": "fred" }

{/who}

/fred

{ "unreserved": "_" }

{/unreserved}

/_

{ "reserved": "/" }

{/reserved}

/%2F

{ "pct_encoded": "%2F" }

{/pct_encoded}

/%252F

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

{/x,y}

/1024/y768

{ "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

表单式查询扩展

表单式查询扩展对于创建查询字符串很有用。

  • 语法: {?变量名}

  • 允许的字符:非预留

变量 模版 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&y768

{ "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

表单式查询延续

表单样式的查询延续对于追加到查询字符串很有用。

  • 语法: {&变量名}

  • 允许的字符:非预留

变量 模版 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&y768

{ "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

预留扩展

将简单字符串扩展的允许字符集扩展到预留集和 pct 编码序列。

  • 语法: {+变量名}

  • 允许的字符: 预留 集, 非预留 集以及 pct 编码序列。

变量 模版 URI/资源标识符

{ "who": "fred" }

{+who}

fred

{ "unreserved": "_" }

{+unreserved}

_

{ "reserved": "/" }

{+reserved}

/

{ "pct_encoded": "%2F" }

{+pct_encoded}

%2F

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

{+x,y}

1024,y768

{ "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

片段扩展

像预留扩展一样以 # 为前缀。

  • 语法: {#变量名}

  • 允许的字符: 预留 集, 非预留 集以及 pct 编码序列。

变量 模版 URI/资源标识符

{ "who": "fred" }

{#who}

#fred

{ "unreserved": "_" }

{#unreserved}

#_

{ "reserved": "/" }

{#reserved}

#/

{ "pct_encoded": "%2F" }

{#pct_encoded}

#%2F

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

{#x,y}

#1024,y768

{ "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

带点前缀的标签扩展

  • 语法: {.变量名}

  • 允许的字符:非预留

变量 模版 URI/资源标识符

{ "who": "fred" }

{.who}

.fred

{ "unreserved": "_" }

{.unreserved}

._

{ "reserved": "/" }

{.reserved}

.%2F

{ "pct_encoded": "%2F" }

{.pct_encoded}

.%252F

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

{.x,y}

.1024.y768

{ "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

路径样式参数扩展

  • 语法: {.变量名}

  • 允许的字符:非预留

变量 模版 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=y768

{ "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

字符集备忘单

预留集

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

非预留集

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~