使用 Spring HATEOAS 的规范 _links [英] Canonical _links with Spring HATEOAS

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

问题描述

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

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"
    }
  }
}

但是,鉴于 Paul 的父亲存储的 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 对某些人来说是 null,这当然会导致问题(好吧,这在这里没有多大意义......;)),但在这种情况下我们不想渲染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 来实现这一点,但似乎在调用处理器时链接尚未填充.我们设法添加了指向所需规范网址的附加链接,但未能修改后来添加的链接.

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 属性.不要忘记使用 Jackson @ignore... 在响应 JSON 中隐藏 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 的规范 _links的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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