Spring HATEOAS的规范链接 [英] Canonical _links with Spring HATEOAS

查看:105
本文介绍了Spring HATEOAS的规范链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在构建类似于spring.io指南的RESTful Web服务"使用REST访问JPA数据".要重现下面的示例输出,只需将 ManyToOne -Relation添加到 Person ,如下所示:

We're building a RESTful web service similiar to the spring.io guide "Accessing JPA Data with REST". To reproduce the sample outputs below, it suffices to add a ManyToOne-Relation to Person as follows:

// ...

@Entity
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String firstName;
  private String lastName;

  @ManyToOne
  private Person father;

  // getters and setters
}

添加一些示例数据后的GET请求:

A GET request after adding some sample data yields:

{
  "firstName" : "Paul",
  "lastName" : "Mustermann",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/1"
    },
    "father" : {
      "href" : "http://localhost:8080/people/1/father"
    }
  }
}

但是,考虑到保罗的父亲的ID为2,我们期望的结果将是其关系的规范网址:

But, given Paul's father is stored with ID 2, our desired result would be the canonical url for its relation:

// ...
    "father" : {
      "href" : "http://localhost:8080/people/2"
    }
// ...

如果某些人的 father 为空,这当然会引起问题(好吧,这在这里没有多大意义……;)),但是在这种情况下,我们不想渲染完全是JSON中的链接.

This of course will cause problems if father is null on some persons (OK, this does not make much sense here... ;)), but in this case we would like to not render the link in JSON at all.

我们已经尝试实现 ResourceProcessor 来实现此目的,但是看来在调用处理器时,链接尚未填充.我们设法添加了指向所需规范URL的其他链接,但未能以某种方式修改以后添加的链接.

We already tried to implement a ResourceProcessor to achieve this, but it seems that by the time the processor is called the links are not populated yet. We managed to add additional links pointing to the desired canonical url, but failed to modify the somehow later added links.

问题:是否存在一种通用方法来自定义所有资源的链接生成?

Question: Is there a generic approach to customize the link generation for all resources?

要阐明我们对规范URL的需求,:我们使用SproutCore Javascript框架来访问RESTful Web服务.它使用数据源的类ORM"抽象,为此我们实现了Spring产生的JSON输出的通用处理程序.当查询所有人时,我们将需要发送n *(1 + q)个请求(而不是仅n个)给与其他人有q关系的n个人,以将其同步到客户端数据源.这是因为默认的非规范"链接绝对不包含有关正在设置的父亲或父亲的ID的信息.似乎这会导致大量不必要的请求,如果初始响应首先包含更多信息,则可以轻松避免这些不必要的请求.

To clarify our need for canonical URLs: We use the SproutCore Javascript framework to access the RESTful web service. It uses an "ORM-like" abstraction of data sources for which we've implemented a generic handler of the JSON output Spring produces. When querying for all persons, we would need to send n*(1+q) requests (instead of just n) for n persons with q relations to other persons to sync them to the client side data source. This is because the default "non-canonical" link contains absolutely no information about a father being set or the father's id. It just seems that this causes a huge amount of unnecessary requests which could be easily avoided if the initial response would contain a little more information in the first place.

另一种解决方案是将父亲的ID添加到该关系中,例如:

Another solution would be to add the father's id to the relation, e.g.:

"father" : {
  "href" : "http://localhost:8080/people/1/father",
  "id" : 2
}

推荐答案

Spring Data Rest团队在某处进行了讨论,解释了为什么将属性以这种方式呈现为链接.话虽如此,您仍然可以通过抑制SDR生成的链接并实现ResourceProcessor来实现所需的功能.因此,您的Person类将如下所示.请注意注释@RestResource(exported = false)以禁止链接

There is a discussion somewhere Spring Data Rest team explained why properties are rendered as links that way. Having said you could still achieve what you like by suppressing link generated by SDR and implementing ResourceProcessor. So your Person class would look like below. Note the annotation @RestResource(exported = false) to suppress link

@Entity
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String firstName;
  private String lastName;

  @ManyToOne
  @RestResource(exported = false)
  private Person father;

  // getters and setters
}

您的ResourceProcessor类类似于

Your ResourceProcessor class would look like

public class EmployeeResourceProcessor implements
        ResourceProcessor<Resource<Person>> {

    @Autowired
    private EntityLinks entityLinks;

    @Override
    public Resource<Person> process(Resource<Person> resource) {
        Person person = resource.getContent();
        if (person.getFather() != null) {
            resource.add(entityLinks.linkForSingleResour(Person.class, person.getFather().getId())
                .withRel("father"));
        }
        return resource;
    }

}

仅当急切地将father值与Person一起获取时,上述解决方案才有效.否则,您需要具有属性fatherId并使用它代替father属性.不要忘记在响应JSON中使用Jackson @ignore...隐藏fatherId.

The above solution works only if father value is eagerly fetched along with Person. Otherwise you need to have property fatherId and use it instead of father property. Don't forget to use Jackson @ignore... to hide fatherId in response JSON.

注意:我自己尚未测试过,但猜测它会起作用

Note: I haven't tested this myself but guessing it would work

这篇关于Spring HATEOAS的规范链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆