原标题:Spring认证中国教育管理中心-Spring Data REST框架教程三(Spring中国教育管理中心)
5.2.排序
Spring Data REST 识别使用存储库排序支持的排序参数。
要根据特定属性对结果进行排序,请添加一个sortURL 参数,其中包含要对结果进行排序的属性的名称。您可以通过将逗号 ( ,)附加到属性名称加上asc或来控制排序的方向desc。以下将使用在名称以字母“K”开头的所有实体findByNameStartsWith上定义的查询方法,并添加排序数据,以降序对属性上的结果进行排序:
PersonRepositoryPersonname
curl -v "http://localhost:8080/people/search/nameStartsWith?name=K&sort=name,desc"
要按多个属性对结果进行排序,请sort=PROPERTY根据需要继续添加尽可能多的参数。它们Pageable按照它们在查询字符串中出现的顺序添加到中。结果可以按顶级和嵌套属性排序。使用属性路径表示法来表达嵌套排序属性。不支持按可链接的关联(即顶级资源的链接)排序。
6.领域对象表示(Object Mapping)
Spring Data REST 返回Accept与 HTTP 请求中指定的类型相对应的域对象的表示。
目前,仅支持 JSON 表示。将来可以通过添加适当的转换器并使用适当的内容类型更新控制器方法来支持其他表示类型。
有时,Spring Data REST 的行为ObjectMapper(已专门配置为使用可以将域对象转换为链接并再次返回的智能序列化程序)可能无法正确处理您的域模型。您可以通过多种方式构建数据,以至于您可能会发现自己的域模型没有正确转换为 JSON。在这些情况下,尝试以通用方式支持复杂的域模型有时也是不切实际的。有时,根据复杂性,甚至不可能提供通用解决方案。
6.1.向 Jackson 的 ObjectMapper 添加自定义序列化器和反序列化器
为了适应最大比例的用例,Spring Data REST 非常努力地尝试正确呈现您的对象图。它尝试将非托管 bean 序列化为普通 POJO,并尝试在必要时创建指向托管 bean 的链接。但是,如果您的域模型不容易读取或写入纯 JSON,您可能需要使用您自己的自定义映射、序列化器和反序列化器来配置 Jackson 的 ObjectMapper。
6.1.1.抽象类注册
您可能需要挂钩的一个关键配置点是在域模型中使用抽象类(或接口)时。默认情况下,Jackson 不知道为接口创建什么实现。考虑以下示例:
@Entitypublic class MyEntity { @OneToMany private List<MyInterface> interfaces; }
在默认配置中,Jackson 不知道在向导出器发布新数据时要实例化哪个类。这是您需要通过注释或(更干净地)通过使用Module.
要将您自己的 Jackson 配置添加到ObjectMapperSpring Data REST 使用的配置中,请覆盖该
configureJacksonObjectMapper方法。该方法被传递一个ObjectMapper实例,该实例具有处理序列化和反序列化PersistentEntity对象的特殊模块。您也可以注册自己的模块,如以下示例所示:
@Overrideprotected void configureJacksonObjectMapper(ObjectMapper objectMapper) { objectMapper.registerModule(new SimpleModule("MyCustomModule") { @Override public void setupModule(SetupContext context) { context.addAbstractTypeResolver( new SimpleAbstractTypeResolver() .addMapping(MyInterface.class, MyInterfaceImpl.class)); } }); }
一旦您可以访问 中的SetupContext对象Module,您就可以做各种很酷的事情来配置 Jackson 的 JSON 映射。您可以Module在Jackson 的 wiki上阅读有关实例如何工作的更多信息。
6.1.2.为域类型添加自定义序列化程序
如果您想以特殊方式序列化或反序列化域类型,您可以使用 Jackson 注册您自己的实现,ObjectMapperSpring Data REST 导出器会透明地正确处理这些域对象。要从您的setupModule方法实现中添加序列化程序,您可以执行以下操作:
@Overridepublic void setupModule(SetupContext context) { SimpleSerializers serializers = new SimpleSerializers(); SimpleDeserializers deserializers = new SimpleDeserializers(); serializers.addSerializer(MyEntity.class, new MyEntitySerializer()); deserializers.addDeserializer(MyEntity.class, new MyEntityDeserializer()); context.addSerializers(serializers); context.addDeserializers(deserializers); }
7. 预测和摘录
Spring Data REST 提供了您导出的域模型的默认视图。但是,有时,您可能出于各种原因需要更改该模型的视图。本节介绍如何定义预测和摘录以提供简化和简化的资源视图。
7.1.预测
考虑以下域模型:
@Entitypublic class Person { @Id @GeneratedValue private Long id; private String firstName, lastName; @OneToOne private Address address; … }
Person上例中的对象有几个属性:
id 是主键。
firstName和lastName是数据属性。
address 是指向另一个域对象的链接。
现在假设我们创建了一个对应的仓库,如下:
interface PersonRepository extends CrudRepository<Person, Long> {}
默认情况下,Spring Data REST 导出此域对象,包括其所有属性。firstName并lastName作为它们的纯数据对象导出。关于address属性有两个选项。一种选择是还为Address对象定义一个存储库,如下所示:
interface AddressRepository extends CrudRepository<Address, Long> {}
在这种情况下,Person资源将address属性呈现为其对应Address资源的 URI 。如果我们在系统中查找“Frodo”,我们可能会看到这样的 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 }) interface NoAddresses { String getFirstName(); String getLastName(); }
该@Projection注释将其标记为一个投影。该name属性提供了投影的名称,稍后我们将更详细地介绍它。该types属性的目标这个投影仅适用于Person对象。
它是一个 Java 接口,使其具有声明性。
它导出firstName.
它导出lastName.
该NoAddresses投影只有firstName和 的吸气剂lastName,这意味着它不提供任何地址信息。假设您有一个单独的资源存储库Address,Spring Data REST 的默认视图与之前的表示略有不同,如以下示例所示:
{ "firstName" : "Frodo", "lastName" : "Baggins", "_links" : { "self" : { "href" : "http://localhost:8080/persons/1{?projection}", "templated" : true }, "address" : { "href" : "http://localhost:8080/persons/1/address" } } }
此资源有一个新选项:{?projection}。
该selfURI是URI模板。
要查看资源的投影。
提供给projection查询参数的值与 中指定的值相同@Projection(name = "noAddress")。它与投影界面的名称无关。
您可以有多个投影。
请参阅投影以查看示例项目。我们鼓励您尝试使用它。
Spring Data REST 查找投影定义如下:
@Projection在与您的实体定义(或其子包之一)相同的包中找到的任何接口都已注册。
您可以使用 手动注册投影
RepositoryRestConfiguration.getProjectionConfiguration().addProjection(…)。
无论哪种情况,投影界面都必须有@Projection注释。
7.1.1.寻找现有的预测
Spring Data REST 公开了Application-Level Profile Semantics (ALPS)文档,这是一种微元数据格式。要查看 ALPS 元数据,请遵循profile根资源公开的链接。如果您向下导航到Person资源的 ALPS 文档(将是/alps/persons),您可以找到有关Person资源的许多详细信息。GET在类似于以下示例的块中列出了预测以及有关REST 转换的详细信息:
{ … "id" : "get-person", "name" : "person", "type" : "SAFE", "rt" : "#person-representation", "descriptors" : [ { "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" : "noAddresses", "type" : "SEMANTIC", "descriptors" : [ { "name" : "firstName", "type" : "SEMANTIC" }, { "name" : "lastName", "type" : "SEMANTIC" } ] } ] } ] }, …
的ALPS文件显示这部分有关详细信息GET和Person资源。
这部分包含projection选项。
这部分包含noAddresses投影。
此投影提供的实际属性包括firstName和lastName。
如果客户符合以下条件,则会选取投影定义并提供给客户:
用@Projection注解标记并位于域类型的同一包(或子包)中,或
使用
RepositoryRestConfiguration.getProjectionConfiguration().addProjection(…).