47

在 2.0.2.RELEASE 版本中将 Spring Data REST 与 JPA 一起使用。

如何在 JSON 中禁用超文本应用程序语言 (HAL)?http://stateless.co/hal_specification.html

我已经尝试了很多东西,但无济于事。例如,我已将 Accept 和 Content-type 标头设置为“application/json”而不是“application/hal+json”,但我仍然收到带有超链接的 JSON 内容。

例如,我想得到类似的东西:

{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"sector" : {
     "description" : "Marketing",
     "average profit": 545656665,
     "average employees": 75,
     "average profit per employee": 4556
     }
}

代替:

{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"_links" : {
     "self" : {
          "href" : "http://localhost:8080/app/companies/1"
     },
     "sector" : {
          "href" : "http://localhost:8080/app/companies/1/sector"
     }
}
}

谢谢你的帮助。

4

2 回答 2

42

(超)媒体类型

Spring Data REST 的默认设置使用 HAL 作为默认的超媒体表示格式,因此服务器将为给定的Accept标头返回以下内容:

  • 没有标题 -> application/hal+json-> HAL
  • application/hal+json-> application/hal+json-> 哈尔
  • application/json-> application/json-> HAL(这是默认配置)
  • application/x-spring-data-verbose+json-> application/x-spring-data-verbose+json-> 一种 Spring Data 特定格式(links用于链接容器和content作为集合项的包装器。

如果您配置RepositoryRestConfiguration.setDefaultMediaType(…)为非 HAL 格式,则服务器将返回 Spring Data 特定的 JSON 格式,除非您明确要求application/hal+json. 诚然,配置选项可能有点误导,所以我提交了 DATAREST-294来改进它。该问题已在 2.1 RC1 (Dijkstra) 2014 中得到解决。

请注意,我们实际上需要一种超媒体格式,以便能够表达托管资源之间的关系并启用服务器的可发现性。所以你不可能完全摆脱它。这主要是因为如果您公开具有双向关系的实体或组成一个巨大的对象图,您很容易使服务器崩溃。

内联相关实体

如果您永远不想将扇区链接到它们并始终将它们内联,那么一种选择是首先简单地将扇区排除在SectorRepository导出为 REST 资源之外。您可以通过使用@RepositoryRestResource(exported = false).

要获得您在下例中发布的表示返回,请查看Spring Data REST 2.1 M1 中引入的投影功能。它基本上允许您通过简单的界面在资源上制作与默认视图不同的可选视图。

你基本上会定义一个接口:

@Projection(name = "foo", types = YourDomainClass.class)
interface Inlined {

  // list all other properties

  Sector getSector();
}

如果您将此接口放入域类的(子)包中或通过RepositoryRestConfiguration.projectionConfiguration()资源手动注册它,则公开YourDomainClass将接受请求参数projection,以便foo在此示例中传入将按照您的需要呈现内联表示。

此提交通常包含有关该功能的更多信息,此提交定义了示例投影。

于 2014-04-25T07:52:42.497 回答
4

所以你想要两件事:

1)摆脱_links领域
2)包括相关sector领域

可能的解决方案(对我有用:D)

1)摆脱_links
为此创建以下类:

[... package declaration, imports ...]
public class MyRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
    public MyRepositoryRestMvcConfiguration(ApplicationContext context, ObjectFactory<ConversionService> conversionService) {
        super(context, conversionService);
    }

    @Bean
    protected LinkCollector linkCollector() {
        return new LinkCollector(persistentEntities(), selfLinkProvider(), associationLinks()) {
            public Links getLinksFor(Object object, List<Link> existingLinks) {
                return new Links();
            }
        };
    }
}

并使用它,例如:

[... package declaration, imports ...]
@SpringBootApplication
@Import({MyRepositoryRestMvcConfiguration.class})
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

我很确定(99%,但未经测试)你不需要这个类来删除_links相关实体/实体,包括下一点 (2) 的显示方式。

2)包括相关sector字段
为此,您可以使用摘录(特别是为此场景制作的)。因为 Spring 示例非常雄辩,在这里复制它很愚蠢,我将指出它:https ://docs.spring.io/spring-data/rest/docs/3.1.x/reference/html/#projections -excerpts.excerpting-commonly-accessed-data
但为了记录和您的方便,我将粘贴 spring 示例的主要部分:

@Projection(name = "inlineAddress", types = { Person.class }) 
interface InlineAddress {
  String getFirstName();
  String getLastName();
  Address getAddress(); 
}

请参阅Projection javadoc,这types意味着投影类型绑定到的类型摘录可以这样使用

@RepositoryRestResource(excerptProjection = InlineAddress.class)
interface PersonRepository extends CrudRepository<Person, Long> {}

为了得到这个(当也使用MyRepositoryRestMvcConfiguration时):

{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "address" : { 
    "street": "Bag End",
    "state": "The Shire",
    "country": "Middle Earth"
  }
}

对你sector来说,相当于address.

最后的笔记

返回数组时,该_links字段不会被删除(这样做太麻烦了);最后你会得到这样的东西:

{
    "_embedded" : {
        "persons" : [ {person1}, {person2}, ..., {personN} ]
    },
    "_links" : {
        e.g. first, next, last, self, profile
    },
    "page" : {
      "size" : 1,
      "totalElements" : 10,
      "totalPages" : 10,
      "number" : 0
    }
}

正如你所看到的,即使我们已经_links删除了这仍然不够;一个人可能还想要_embedded替换它,persons这会导致代码的可维护性降低(太多的 spring 侵入式覆盖)。但是,如果一个人真的也想要这些,他应该开始检查RepositoryRestMvcConfigurationand RepositoryEntityController.getCollectionResource

Spring 正在发展,所以我觉得有必要指出这至少适用于:

spring-data-rest-webmvc 3.1.3.RELEASE

或者,如果您更喜欢弹簧靴版本:

spring-boot-starter-parent 2.1.1.RELEASE
于 2018-12-12T20:25:35.273 回答