跳到主要内容

元数据

DeepSeek V3 中英对照 Metadata

本节详细介绍了基于 Spring Data REST 的应用程序提供的各种形式的元数据。

应用级配置文件语义(ALPS)

ALPS 是一种用于定义应用层语义简单描述的数据格式,其复杂度类似于 HTML 微格式。ALPS 文档可以作为配置文件,用于解释具有应用无关媒体类型(如 HTML、HAL、Collection+JSON、Siren 等)的文档的应用语义。这提高了配置文件在不同媒体类型之间的可重用性。

— M. 阿蒙德森 / L. 理查森 / M. 福斯特
https://tools.ietf.org/html/draft-amundsen-richardson-foster-alps-00

Spring Data REST 为每个导出的仓库提供了一个 ALPS 文档。它包含了关于 RESTful 转换以及每个仓库属性的信息。

在 Spring Data REST 应用的根路径下,有一个 profile 链接。假设你有一个包含 persons 及相关 addresses 的应用,根文档将如下所示:

{
"_links" : {
"persons" : {
"href" : "http://localhost:8080/persons"
},
"addresses" : {
"href" : "http://localhost:8080/addresses"
},
"profile" : {
"href" : "http://localhost:8080/profile"
}
}
}
javascript

配置文件链接,如 RFC 6906 中所定义,是一个包含应用级详细信息的地方。ALPS 草案规范旨在定义一种特定的配置文件格式,我们将在本节后续部分进行探讨。

如果你在浏览器中访问 localhost:8080/profile 的 profile 链接,你会看到类似以下的内容:

{
"_links" : {
"self" : {
"href" : "http://localhost:8080/profile"
},
"persons" : {
"href" : "http://localhost:8080/profile/persons"
},
"addresses" : {
"href" : "http://localhost:8080/profile/addresses"
}
}
}
javascript
important

在根级别,profile 是一个单一链接,无法提供多个应用程序配置文件。这就是为什么你必须导航到 /profile 才能找到每个资源的元数据链接。

如果你导航到 /profile/persons 并查看 Person 资源的个人资料数据,你会看到类似于以下示例的内容:

{
"version" : "1.0",
"descriptors" : [ {
"id" : "person-representation", 1
"descriptors" : [ {
"name" : "firstName",
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"type" : "SEMANTIC"
}, {
"name" : "id",
"type" : "SEMANTIC"
}, {
"name" : "address",
"type" : "SAFE",
"rt" : "http://localhost:8080/profile/addresses#address"
} ]
}, {
"id" : "create-persons", 2
"name" : "persons", 3
"type" : "UNSAFE", 4
"rt" : "#person-representation" 5
}, {
"id" : "get-persons",
"name" : "persons",
"type" : "SAFE",
"rt" : "#person-representation"
}, {
"id" : "delete-person",
"name" : "person",
"type" : "IDEMPOTENT",
"rt" : "#person-representation"
}, {
"id" : "patch-person",
"name" : "person",
"type" : "UNSAFE",
"rt" : "#person-representation"
}, {
"id" : "update-person",
"name" : "person",
"type" : "IDEMPOTENT",
"rt" : "#person-representation"
}, {
"id" : "get-person",
"name" : "person",
"type" : "SAFE",
"rt" : "#person-representation"
} ]
}
javascript
  • 详细列出了 Person 资源的属性,标识为 #person-representation,并列出了属性的名称。

  • 支持的操作。此处指示了如何创建一个新的 Person

  • namepersons,这表明(因为是复数形式)POST 请求应应用于整个集合,而不是单个 person

  • typeUNSAFE,因为此操作可能会改变系统的状态。

  • rt#person-representation,这表明返回的资源类型将是 Person 资源。

备注

这个 JSON 文档的媒体类型是 application/alps+json。这与之前的 JSON 文档不同,之前的文档媒体类型是 application/hal+json。这些格式不同,并且由不同的规范管理。

你还可以在检查集合资源时,在 _links 集合中找到 profile 链接,如下例所示:

{
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons" 1
},
... other links ...
"profile" : {
"href" : "http://localhost:8080/profile/persons" 2
}
},
...
}
javascript
  • 此 HAL 文档表示 Person 集合。

  • 它有一个指向相同 URI 的 profile 链接,用于元数据。

同样,默认情况下,profile 链接提供的是 ALPS。然而,如果使用 Accept header,它可以提供 application/alps+json

超媒体控制类型

ALPS 为每个超媒体控件显示类型。它们包括:

表 1. ALPS 类型

类型描述
SEMANTIC一个状态元素(例如 HTML.SPANHTML.INPUT 等)。
SAFE一个触发安全、幂等状态转换的超媒体控件(例如 GETHEAD)。
IDEMPOTENT一个触发不安全、幂等状态转换的超媒体控件(例如 PUTDELETE)。
UNSAFE一个触发不安全、非幂等状态转换的超媒体控件(例如 POST)。

在前面展示的表示部分中,来自应用程序的数据位被标记为 SEMANTICaddress 字段是一个链接,涉及一个安全的 GET 请求来检索。因此,它被标记为 SAFE。超媒体操作本身映射到前表中所示的类型。

带投影的 ALPS

如果你定义了任何投影,它们也会在 ALPS 元数据中列出。假设我们还定义了 inlineAddressnoAddresses,它们将出现在相关的操作中。(有关这两个投影的定义和讨论,请参阅“投影”)。也就是说,GET 将出现在整个集合的操作中,而 GET 也会出现在单个资源的操作中。以下示例展示了 get-persons 子节的替代版本:

...
{
"id" : "get-persons",
"name" : "persons",
"type" : "SAFE",
"rt" : "#person-representation",
"descriptors" : [ { 1
"name" : "projection",
"doc" : {
"value" : "The projection that shall be applied when rendering the response. Acceptable values available in nested descriptors.",
"format" : "TEXT"
},
"type" : "SEMANTIC",
"descriptors" : [ {
"name" : "inlineAddress", 2
"type" : "SEMANTIC",
"descriptors" : [ {
"name" : "address",
"type" : "SEMANTIC"
}, {
"name" : "firstName",
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"type" : "SEMANTIC"
} ]
}, {
"name" : "noAddresses", 3
"type" : "SEMANTIC",
"descriptors" : [ {
"name" : "firstName",
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"type" : "SEMANTIC"
} ]
} ]
} ]
}
...
javascript
  • 出现了一个新属性 descriptors,它包含一个数组,数组中有一个条目 projection

  • projection.descriptors 中,我们可以看到 inLineAddress。它渲染了 addressfirstNamelastName。在投影结果中渲染的关系会导致数据字段被内联包含。

  • noAddresses 提供了一个包含 firstNamelastName 的子集。

有了这些信息,客户端不仅可以推断出可用的 RESTful 转换,还能在一定程度上了解与后端交互所需的数据元素。

为您的 ALPS 描述添加自定义详细信息

你可以在 ALPS 元数据中创建自定义消息。为此,按照以下方式创建 rest-messages.properties 文件:

rest.description.person=A collection of people
rest.description.person.id=primary key used internally to store a person (not for RESTful usage)
rest.description.person.firstName=Person's first name
rest.description.person.lastName=Person's last name
rest.description.person.address=Person's address
properties

这些 rest.description.* 属性定义了用于显示 Person 资源的详细信息。它们会修改 person-representation 的 ALPS 格式,如下所示:

...
{
"id" : "person-representation",
"doc" : {
"value" : "A collection of people", 1
"format" : "TEXT"
},
"descriptors" : [ {
"name" : "firstName",
"doc" : {
"value" : "Person's first name", 2
"format" : "TEXT"
},
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"doc" : {
"value" : "Person's last name", 3
"format" : "TEXT"
},
"type" : "SEMANTIC"
}, {
"name" : "id",
"doc" : {
"value" : "primary key used internally to store a person (not for RESTful usage)", 4
"format" : "TEXT"
},
"type" : "SEMANTIC"
}, {
"name" : "address",
"doc" : {
"value" : "Person's address", 5
"format" : "TEXT"
},
"type" : "SAFE",
"rt" : "http://localhost:8080/profile/addresses#address"
} ]
}
...
javascript
  • rest.description.person 的值映射到整个表示中。

  • rest.description.person.firstName 的值映射到 firstName 属性。

  • rest.description.person.lastName 的值映射到 lastName 属性。

  • rest.description.person.id 的值映射到 id 属性,这是一个通常不显示的字段。

  • rest.description.person.address 的值映射到 address 属性。

提供这些属性设置会导致每个字段都有一个额外的 doc 属性。

备注

Spring MVC(这是 Spring Data REST 应用的核心)支持多语言环境,这意味着你可以将多个包含不同消息的属性文件打包在一起。

JSON 模式

JSON Schema 是 Spring Data REST 支持的另一种元数据形式。根据其官网,JSON Schema 具有以下优势:

  • 描述您现有的数据格式

  • 清晰、人类和机器均可阅读的文档

  • 完整的结构验证,适用于自动化测试和验证客户端提交的数据

前一节所示,您可以通过从根 URI 导航到 profile 链接来访问此数据。

{
"_links" : {
"self" : {
"href" : "http://localhost:8080/profile"
},
"persons" : {
"href" : "http://localhost:8080/profile/persons"
},
"addresses" : {
"href" : "http://localhost:8080/profile/addresses"
}
}
}
javascript

这些链接与之前显示的相同。要检索 JSON Schema,你可以使用以下 Accept 头信息来调用它们:application/schema+json

在这种情况下,如果你运行 curl -H 'Accept:application/schema+json' [localhost:8080/profile/persons](http://localhost:8080/profile/persons),你会看到类似如下的输出:

{
"title" : "org.springframework.data.rest.webmvc.jpa.Person", 1
"properties" : { 2
"firstName" : {
"readOnly" : false,
"type" : "string"
},
"lastName" : {
"readOnly" : false,
"type" : "string"
},
"siblings" : {
"readOnly" : false,
"type" : "string",
"format" : "uri"
},
"created" : {
"readOnly" : false,
"type" : "string",
"format" : "date-time"
},
"father" : {
"readOnly" : false,
"type" : "string",
"format" : "uri"
},
"weight" : {
"readOnly" : false,
"type" : "integer"
},
"height" : {
"readOnly" : false,
"type" : "integer"
}
},
"descriptors" : { },
"type" : "object",
"$schema" : "https://json-schema.org/draft-04/schema#"
}
javascript
  • 导出的类型

  • 属性列表

如果您的资源链接到其他资源,将有更多详细信息。

在检查集合资源时,您还可以在 _links 集合中找到 profile 链接,如下例所示:

{
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons" 1
},
... other links ...
"profile" : {
"href" : "http://localhost:8080/profile/persons" 2
}
},
...
}
javascript
  • 这份 HAL 文档代表 Person 集合。

  • 它有一个指向相同 URI 的 profile 链接用于元数据。

再次,profile 链接默认提供 ALPS 服务。如果你提供一个值为 application/schema+jsonAccept 头,它将渲染 JSON Schema 表示。