【问题标题】:How to remove the "_embedded" property in Spring HATEOAS如何删除 Spring HATEOAS 中的“_embedded”属性
【发布时间】: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 对象很大。我也没有找到克服这个问题的好方法。

标签: spring rest spring-boot spring-hateoas


【解决方案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 并带有以下消息:“找不到可接受的表示”
      猜你喜欢
      • 2018-11-11
      • 2020-05-11
      • 2015-11-30
      • 1970-01-01
      • 2015-02-08
      • 2019-12-05
      • 1970-01-01
      • 2016-10-15
      • 2019-06-02
      相关资源
      最近更新 更多