8.预测和摘要
Spring Data REST提出了一个您正在导出的域模型的默认视图,但是有时候,你需要因为各种各样的理由来更改这些模型的意见。在这个部分,你将会学习到如何 明确预测以及更加简单提供摘要以及减少对资源的一些意见。
8.1.Projections
看下面的域模型
@EntitypublicclassPerson{@Id@GeneratedValueprivateLong id;privateString firstName, lastName;@OneToOneprivateAddress address;…}
这个Perso
n有以下这些属性
id
是主键firstName
和lastName
是数据属性address
是一个链接到另一个域的对象 现在假设我们创建了一个对应的存储,如下
interfacePersonRepositoryextendsCrudRepository<Person,Long>{}
在默认情况下,Spring Data REST 将会输出这个域对象包括里面所有的属性firstName
和 lastName
会被作为清楚的数据对象被输出。这里有两个选择关于这个address属性。一个选择也规定对于address对象的存储如下
interfaceAddressRepositoryextendsCrudRepository<Address,Long>{}
在这种情况下,Person
的资源将会作为一个URI给予Address
属性来对应他的Address
资源,如果我们在这个系统里面要查找“Fordo”,我们可以希望看到的HAL文档如下
{"firstName":"Frodo","lastName":"Baggins","_links":{"self":{"href":"http://localhost:8080/persons/1"},"address":{"href":"http://localhost:8080/persons/1/address"}}}
这里有另一条路线,如果这个address
域对象没有他本身的存储定义,Spring Data REST将会对内部的person资源内联数据字段。
{"firstName":"Frodo","lastName":"Baggins","address":{"street":"Bag End","state":"The Shire","country":"Middle Earth"},"_links":{"self":{"href":"http://localhost:8080/persons/1"}}}
但是如果你不想要address
的所有细节?,再一次,在默认情况下,Spring Data REST将会输出这个的所有属性(除id),你可以为消费者提供你的可替代的REST服务通过定义一个或者多个预测方法
@Projection(name ="noAddresses", types ={Person.class})(1)interfaceNoAddresses{(2)String getFirstName();(3)String getLastName();(4)}
这个规划有以下的细节
| 1 | @Projection
注释标志是一个投影,name
属性提供了投影名称,你将会见识到如何简单的利用。types
属性目标这个投影只试用Person对象.|
| --- | --- |
| 2 |这是一个java接口使其陈述
| 3 |这输出firstname
| 4 |这输出lastname
NoAddress
项目里面只有firsname
和lastname
的getter方法,意味着它不会提供任何地址信息。假设你有一个单独的存储库地址资源,spring Data REST的默认视图有点不同,如下
{"firstName":"Frodo","lastName":"Baggins","_links":{"self":{"href":"http://localhost:8080/persons/1{?projection}",(1)"templated":true(2)},"address":{"href":"http://localhost:8080/persons/1/address"}}}
1 | 对于新的资源这里有一个新的选择清单{?projection} . |
---|---|
2 | self URI是一个URI模板 |
视图应用投影到资源,查找[http://localhost:8080/persons/1?projection=noAddresses](http://localhost:8080/persons/1?projection=noAddresses)
.
提供给投影查询参数的值在Projection 指定 @Projection(name = "noAddress") .一样,这和投影的接口名称无关. |
|
---|---|
也可能可以有多个预测 | |您可以尝试访问预测看一个示例项目Projections | --- | --- | Spring Data REST如何找到投影的定义?
- 任何
@Projection
接口在同一个包中发现作为实体定义(或它的子包)是已登记的 - 您可以手动注册通过
RepositoryRestConfiguration.getProjectionConfiguration().addProjection(…)
. 在这两种情况下,接口与投影一定要用@Projection
注释。8.1.1.发现现有的投影
Spring Data REST显示Application-Level Profile Semantics (ALPS) 文件,一个微元数据格式 。为了查看ALPS的元数据,按照配置文件profile
资源查找。如果你在Person
资源下导航ALPS资源文档(这将是alps/persons
),你将会发现一些person资源的细节。预测也会随着细节列出关于GET
REST转换,如下
{…"id":"get-person",(1)"name":"person","type":"SAFE","rt":"#person-representation","descriptors":[{"name":"projection",(2)"doc":{"value":"The projection that shall be applied when rendering the response. Acceptable values available in nested descriptors.","format":"TEXT"},"type":"SEMANTIC","descriptors":[{"name":"noAddresses",(3)"type":"SEMANTIC","descriptors":[{"name":"firstName",(4)"type":"SEMANTIC"},{"name":"lastName",(4)"type":"SEMANTIC"}]}]}]},…
1 | alps这部分文档显示关于get 和person 资源的细节. |
---|---|
2 | 进一步降低投影的选项. |
3 | 进一步降低你可以看到的noaddress 投影清单. |
4 | 这个投影提供实际的属性包括firstName 和lastName . |
投影的定义会被采用并且为客户提供,如果他们是: | |
--- | --- |
8.1.2.引进隐藏数据
到目前为止,您已经看到了如何使用预测来减少信息呈现给用户。预测还可以引入通常看不见的数据。例如Spring Data REST将忽略数据字段或getter与@JsonIgnore
标记注释,看看下面的域对象:
@EntitypublicclassUser{@Id@GeneratedValueprivateLong id;privateString name;@JsonIgnoreprivateString password;(1)privateString[] roles;…
1 | Jackson 的 @JsonIgnore 用于防止密码字段序列化为JSON. |
---|---|
这个user
类可用于存储用户信息以及集成Spring Security。如果您创建了一个UserRepository
,密码字段通常已经输出。不是很好!
在这个例子中,我们运用jackson 的 @JsonIgnore
预防这样的事情发生在
password
。
| |如果@JsonIgnore
在领域对应getter函数那么jackson也没有序列化这个领域为json
| --- | --- |
然而,预测引入仍为这一领域的能力。可以创建这样的一个投影:
@Projection(name ="passwords", types ={User.class})interfacePasswordProjection{String getPassword();}
如果创建和使用这样一个投影,它将@JsonIgnore
指令放在User.password
.
| |
这个例子似乎有点做作,但有可能与更丰富的领域模型和许多预测.,不小心泄漏这样的细节.因为 Spring Data REST不能辨别这些数据的敏感性,它由开发人员来避免这种情况。
| --- | --- |
预测还可以生成虚拟数据。想象你有以下实体的定义:
@EntitypublicclassPerson{...privateString firstName;privateString lastName;...}
您可以创建一个投影相结合这两个数据字段一起像这样
@Projection(name ="virtual", types ={Person.class})publicinterfaceVirtualProjection{@Value("#{target.firstName} #{target.lastName}")(1)String getFullName();}
Spring的@ value注释让你插入一个SpEL 表达式来获取目标对象,和拼接在一起的FirstName
和LastName
属性为只读FullName。
8.2.摘要
摘录是一个投影,应用于资源自动收集。例如,你可以改变personrepository
,如下:
@RepositoryRestResource(excerptProjection =NoAddresses.class)interfacePersonRepositoryextendsCrudRepository<Person,Long>{}
这指示Spring Data REST来用NoAddresses
投影当Person
的
资源嵌入到集合或相关资源中。
摘录的预测并不适用于单一资源自动,他们必须谨慎被使用,摘录的预测是为了提供一个默认的预览数据采集 但不是在获取个人资源。 See 为什么摘录投影不是Spring data rest自动申请的数据 for 作为一个讨论 | |
---|---|
除了改变缺省呈现,摘录了额外的渲染选项如下所示
8.3.摘录经常访问数据
与REST服务出现常见的情况,当你组成域对象。例如,Person
都存储在一个表及其相关address
存储在另一个地方默认情况下Spring Data REST 将会提供人的address
作为URI客户机必须导航。如果消费者总是拿到这块数据的额外一部分,摘录投影可以继续进行以及内联这个额外的数据模块。
储存你一个额外的GET
。为此,我们定义一个摘录投影:
@Projection(name ="inlineAddress", types ={Person.class})(1)interfaceInlineAddress{String getFirstName();String getLastName();Address getAddress();(2)}
1 | 这个被命名为inlineaddress 投影. |
---|---|
2 | 这个返回address 的投影添加进getAddress .当使用这个投影,这使得信息被内联. |
我们能按照如下插入PersonRepository
定义
@RepositoryRestResource(excerptProjection =InlineAddress.class)interfacePersonRepositoryextendsCrudRepository<Person,Long>{}
这将导致HAL文件出现如下
{"firstName":"Frodo","lastName":"Baggins","address":{(1)"street":"Bag End","state":"The Shire","country":"Middle Earth"},"_links":{"self":{"href":"http://localhost:8080/persons/1"},"address":{(2)"href":"http://localhost:8080/persons/1/address"}}}
这应该会出现在你所看到的东西的组合中
1 | address数据是直接内联,所以你不必导航得到这个. |
---|---|
2 | 连接到Address资源依然被提供,使它仍然可以导航到自己的资源. |
配置@RepositoryRestResource(excerptProjection=…) 为了一个库改变默认行为。如果你已经做了一个发布,这个能破坏改变消费者对你的服务。小心使用. |
|
---|---|