8.预测和摘要
Spring Data REST提出了一个您正在导出的域模型的默认视图,但是有时候,你需要因为各种各样的理由来更改这些模型的意见。在这个部分,你将会学习到如何 明确预测以及更加简单提供摘要以及减少对资源的一些意见。
8.1.Projections
看下面的域模型
@EntitypublicclassPerson{@Id@GeneratedValueprivateLong id;privateString firstName, lastName;@OneToOneprivateAddress address;…}
这个Person有以下这些属性
- 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资源的细节。预测也会随着细节列出关于GETREST转换,如下
{…"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=…)为了一个库改变默认行为。如果你已经做了一个发布,这个能破坏改变消费者对你的服务。小心使用. | |
|---|---|