我们正在构建一个类似于spring.io指南“Accessing JPA Data with REST”的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"
}
}
}
但是,鉴于保罗的父亲存有ID 2,我们期望的结果将是其关系的规范网址:
// ...
"father" : {
"href" : "http://localhost:8080/people/2"
}
// ...
如果某些人父为空,这当然会导致问题(好的,这在这里没有多大意义......;)),但在这种情况下我们不想渲染JSON中的链接。
我们已经尝试实现 ResourceProcessor 来实现这一目标,但似乎在调用处理器时尚未填充链接。我们设法添加指向所需规范网址的其他链接,但未能修改以后添加的链接。
问题:是否有通用方法来自定义所有资源的链接生成?
澄清我们对规范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
}
答案 0 :(得分: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;
}
}
上述解决方案仅在father
值与Person
一起急切获取时才有效。否则,您需要拥有属性fatherId
并使用它而不是father
属性。不要忘记使用杰克逊@ignore...
来隐藏fatherId
以回应JSON。
注意:我自己没有测试过,但猜测它会起作用
答案 1 :(得分:1)
由于我遇到同样的问题,我在spring-data-rest创建了一个Jira问题: https://jira.spring.io/browse/DATAREST-682
如果有足够的人投票支持它,也许我们可以说服一些开发者实施它: - )。
答案 2 :(得分:0)
你正在努力展示规范链接,这很奇怪。一旦检索到/ father的资源,自我链接应该是规范的...但是真的没有理由强迫父亲关系成为规范...也许是一些缓存方案?
针对您的具体问题......您依赖自动生成的控制器,因此您放弃了对许多链接做出决策的权利。如果您拥有自己的PersonController,那么您将更多地负责链接结构。如果您创建了自己的控制器,则可以将EntityLinks https://github.com/spring-projects/spring-hateoas#entitylinks与父亲的ID一起使用.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
似乎需要付出很多努力