5

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

// ...

@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 请求会产生:

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

但是,鉴于 Paul 的父亲存储的 ID 为 2,我们想要的结果将是其关系的规范 url:

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

如果某些人的父亲为空,这当然会导致问题(好吧,这在这里没有多大意义......;)),但在这种情况下,我们根本不想在 JSON 中呈现链接。

我们已经尝试实现ResourceProcessor来实现这一点,但似乎在调用处理器时链接还没有填充。我们设法添加了指向所需规范 url 的附加链接,但未能修改后来添加的链接。

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

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

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

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

3 回答 3

2

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

@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 类看起来像

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

}

上述解决方案仅在fathervalue 与Person. 否则,您需要拥有财产fatherId并使用它而不是father财产。不要忘记使用 Jackson@ignore...来隐藏fatherId响应 JSON。

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

于 2014-07-09T17:54:10.813 回答
1

由于我遇到了同样的问题,我在 spring-data-rest 创建了一个 Jira 问题: https ://jira.spring.io/browse/DATAREST-682

如果有足够多的人投票支持它,也许我们可以说服一些开发人员来实现它:-)。

于 2015-11-26T08:19:46.003 回答
0

您正在推动显示规范链接,这很奇怪。一旦检索到 /father 处的资源,self 链接应该是规范的……但实际上没有充分的理由强制父亲关系规范……也许是一些缓存方案?

对于您的具体问题...您依赖于自动生成的控制器,因此您放弃了对许多链接做出决定的权利。如果您拥有自己的 PersonController,那么您将更多地负责链接结构。如果您创建了自己的控制器,则可以使用带有父亲 ID 的EntityLinks https://github.com/spring-projects/spring-hateoas#entitylinks..IE

@Controller
@ExposesResourceFor(Person.class)
@RequestMapping("/people")
class PersonController {

  @RequestMapping
  ResponseEntity people(…) { … }

  @RequestMapping("/{id}")
  ResponseEntity person(@PathVariable("id") … ) {
    PersonResource p = ....
    if(p.father){
      p.addLink(entityLinks.linkToSingleResource(Person.class, orderId).withRel("father");
    }
  }
}

但这似乎需要做很多工作来更改 URL

于 2014-07-08T22:59:33.383 回答