如何删除 Spring HATEOAS 中的“_embedded”属性

Posted

技术标签:

【中文标题】如何删除 Spring HATEOAS 中的“_embedded”属性【英文标题】:How to remove the "_embedded" property in Spring HATEOAS 【发布时间】:2015-05-02 17:05:30 【问题描述】:

我正在使用 Spring Boot 和 HATEOAS 构建一个 REST API,当我的 API 返回一个集合时,它被包装在一个“_embedded”属性中,如下所示:


   "_links":
      "self":
         "href":"http://localhost:8080/technologies"
      
   ,
   "_embedded":
      "technologies":[
         
            "id":1,
            "description":"A",
            "_links":
               "self":
                  "href":"http://localhost:8080/technologies/1"
               
            
         ,
         
            "id":2,
            "description":"B",
            "_links":
               "self":
                  "href":"http://localhost:8080/technologies/2"
               
            
         
      ]
   

我希望回复是这样的:


   "_links":
      "self":
         "href":"http://localhost:8080/technologies"
      
   ,
   "technologies":[
      
         "id":1,
         "description":"A",
         "_links":
            "self":
               "href":"http://localhost:8080/technologies/1"
            
         
      ,
      
         "id":2,
         "description":"B",
         "_links":
            "self":
               "href":"http://localhost:8080/technologies/2"
            
         
      
   ]

我的技术控制器:

@RestController
@ExposesResourceFor(Technology.class)
@RequestMapping(value = "/technologies")
public class TechnologiesController 
    ...
    @ResquestMapping(method = RequestMethod.GET, produces = "application/vnd.xpto-technologies.text+json")
    public Resources<Resource<Technology>> getAllTechnologies() 
        List<Technology> technologies = technologyGateway.getAllTechnologies();
        Resources<<Resource<Technology>> resources = new Resources<Resource<Technology>>(technologyResourceAssembler.toResources(technologies));
        resources.add(linkTo(methodOn(TechnologiesController.class).getAllTechnologies()).withSelfRel());
        return resources;
    

配置类有注解@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)。

在没有“_embedded”的情况下产生响应的最佳方法是什么?

【问题讨论】:

如果您从响应中删除 _embedded,则响应将不再是有效的 HAL。您要么需要坚持使用_embedded,要么使用其他媒体类型。 HAL 草案显示“保留的“_embedded”属性是可选的” 它是可选的,因为资源不必具有任何嵌入式资源。但是,如果确实如此,那么它们应该在_embedded 之下。 我也遇到了同样的问题。我在一个对象上有一个投影,并将其限制为仅显示名称。问题是有超过 20 个关系,所以 _embedded 对象很大。我也没有找到克服这个问题的好方法。 【参考方案1】:

您在生成的和预期的结果中描述的内容在语义上是不同的。前者是Collection&lt;Technology&gt; 的 HAL 表示。后者,您期望的是:

class Wrapper 
  Resources<Technology> technologies;

请注意,我们实际上是如何创建您希望在回复中看到的*** technologies 属性的。您不会在控制器中创建任何后者。***Resourcesinstance 基本上是一个集合,在HAL 中表示*** 集合的唯一方法是_embedded。显然你不想这样,但这就是你在控制器方法中写的。

假设你有Wrapper,这样的东西应该可以工作(未经测试):

Wrapper wrapper = new Wrapper(assembler.toCollectionModel(technologies);
EntityModel<Wrapper> model = EntityModel.of(wrapper);
model.add(linkTo(…));

PS:从 Spring HATEOAS 1.0 开始,ResourcesCollectionModelResourceEntityModel

【讨论】:

【参考方案2】:

对于那些使用 Spring Data,并将其视为问题的人 - 解决方案是设置

spring.data.rest.defaultMediaType = application/json

在应用程序属性中。 仍有链接可用,但不再有_embedded。

【讨论】:

这对我没有任何改变。 这从请求中删除了 _embedded ,而是添加了“内容”。真正的休息界面应该返回“技术”。没有?【参考方案3】:

您可以在服务中使用此代码

  constructor(
    private httpClient: HttpClient
  )  

  retrieveAllStudents()
    return this.httpClient.get<any[]>(`http://localhost:8080/students`);
  

这将处理 Json 的 _embedded 部分并提取所需的数据。

export class ListStudentsComponent implements OnInit 

 // declaring variables to be used
  student: Student;
  students: Student[];
  message: string;

  // injecting student service into the constuctor
   constructor(
    private studentService: StudentService,
  )  

  ngOnInit() 
    this.refreshStudents();
  
refreshStudents()
  this.studentService.retrieveAllStudents().subscribe(
     response => 
       console.log(response);
      this.students = response._embedded.students as Student[];
     
   );
 

【讨论】:

【参考方案4】:

我关闭了 HAL 功能,因为restTemplate 很难使用Resources/Resource。我通过以下代码禁用此功能:

public class SpringRestConfiguration implements RepositoryRestConfigurer 
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) 

        config.setDefaultMediaType(MediaType.APPLICATION_JSON);
        config.useHalAsDefaultJsonMediaType(false);
    

它对我有用。如果有更多对 restTemplate 的支持,HAL 会很好。

【讨论】:

它有效,但实际上根本没有解决问题。它不是在_embedded 字段中返回数据,而是创建一个更好的content 字段,但不会创建作者所需的technologies 字段;【参考方案5】:

正如documentation 所说

application/hal+json 响应应该发送给接受的请求 应用程序/json

为了在您的回复中省略_embedded,您需要添加

spring.hateoas.use-hal-as-default-json-media-type=false

application.properties

【讨论】:

我做到了。但不幸的是,它仍然存在【参考方案6】:

将此Accept 标头添加到请求中:

Accept : application/x-spring-data-verbose+json

【讨论】:

对我来说,这会返回一个 406 并带有以下消息:“找不到可接受的表示”

以上是关于如何删除 Spring HATEOAS 中的“_embedded”属性的主要内容,如果未能解决你的问题,请参考以下文章

删除 Spring RepositoryRestResource 中的“_embedded”属性

将 Zuul、Hystrix(和 Feign)与 Spring Cloud HATEOAS 一起使用时如何转发标头?

带有 RepositoryRestResource-s 和常规控制器的 Spring REST HATEOAS 中的根请求的自定义响应

Spring Boot:HATEOAS 和自定义 JacksonObjectMapper

强制spring hateoas生成https链接而不是http

Spring HATEOAS 与 Spring Data Rest