在JSON中禁用超文本应用程序语言(HAL)?

时间:2014-04-24 08:46:11

标签: json rest spring-data spring-data-jpa spring-data-rest

在版本2.0.2.RELEASE中使用带有JPA的Spring Data REST。

如何在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"
     }
}
}

感谢您的帮助。

2 个答案:

答案 0 :(得分:36)

(超级)媒体类型

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

  • 无标题 - > application/hal+json - > HAL
  • application/hal+json - > application/hal+json - > HAL
  • 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中引入的projections功能。它基本上允许您通过简单的界面在资源上制作可选视图,这些视图可以与默认视图不同。

您基本上定义了一个界面:

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

  // list all other properties

  Sector getSector();
}

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

This commit一般有关于该功能的更多信息,this commit已定义了一个示例投影。

答案 1 :(得分:2)

所以你想要两件事:

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字段
为此,您可以使用Excerpts(特别是针对此情况)。因为Spring的例子是如此雄辩,将其复制到这里很愚蠢,所以我只指出它:https://docs.spring.io/spring-data/rest/docs/3.1.x/reference/html/#projections-excerpts.excerpting-commonly-accessed-data
但是为了记录和方便起见,我将粘贴春季示例的主要部分:

@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侵入式覆盖)。但是,如果真的也想要这些,他应该开始检查RepositoryRestMvcConfigurationRepositoryEntityController.getCollectionResource

春天在不断发展,所以我认为有必要指出这一点至少适用于:

spring-data-rest-webmvc 3.1.3.RELEASE

或者,如果您喜欢Spring Boot版本:

spring-boot-starter-parent 2.1.1.RELEASE