2010-08-20 55 views
3

我试图学习如何使用Jersey编写REST风格的应用程序和使用Jersey编写REST风格的应用程序,并且我很努力地理解在将数据发布到资源时如何处理父/子类型 关系。我使用JSON来交换 数据,但我不认为这与我的问题特别相关。REST风格的1-N可选关系

的例子中,我与模型工作的员工和团队 之间的关系。一个雇员可能或可能不,是一个团队的成员:

GET /team/ - returns a list of teams 
POST /team/ - creates a new team 
GET /team/1 - returns a list of employees in the team with the ID 1 

GET /employee/ - returns a list of employees 
POST /employee/ - creates a new employee 
GET /employee/1 - returns details about the employee with the ID 1 

在这背后我有一些休眠注释的POJO:一个用于团队,和一个 为雇员,以两者之间的1-N的关系(请记住, 员工可能不是团队的成员!)。同样的POJO也注释 作为@XmlRootElements使JAXB将允许我将它们传递给/从 客户端为JSON。

两个实体的属性是这样的:

Team 
    Long id; 
    String name; 
    String desc; 
    List<Employee> employees; 

Employee 
    Long id; 
    Team team; 
    String name; 
    String phone; 
    String email; 

所有好为止。但我努力理解如何让雇员通过 正好路过一个团队的ID,而不是 传递嵌套组对象在我的JSON对象中的一个团队在创建时的成员。

例如,我希望能够调用POST /员工/用JSON是 看起来是这样的:

{ 
    "team_id":"1", 
    "name":"Fred Bloggs", 
    "phone":"1234567890", 
    "email":"[email protected]" 
} 

但是,相反,我有这样的事情经过:

{ 
    "team":{ 
     "id":"1", 
     } 
    "name":"Fred Bloggs", 
    "phone":"1234567890", 
    "email":"[email protected]" 
} 

所以,我的问题是,其他人如何处理在JSON/REST中创建关系而不传递整个对象图?

对不起,这是一个粗略的问题,但正如我所说,我刚刚开始 了,在这个阶段术语对我来说是一个问题!

回答

0

REST提供使用的网址作为参考,太,我觉得这真的很酷的可能性。因此,它应该是这样的:

{ 
    "team":"http://myapp.com/team/1", 
    "name":"Fred Bloggs", 
    "phone":"1234567890", 
    "email":"[email protected]" 
} 

可避免只是提供一个

{ 
    "team":"1", 
    "name":"Fred Bloggs", 
    "phone":"1234567890", 
    "email":"[email protected]" 
} 

在这种情况下,通过嵌套的对象,也是你的转换器必须足够聪明地认为,如果值了团队关键字是一个字符串(或整数,无论​​作品),而不是另一个JSON对象,它应该被解释为一个ID。

1

如果你的框架迫使你的表现,包括奇怪的结构,如{ "id":"1" }话,我会说这是时间切换框架!

更重要的是,而不必担心加一分的JSONObject你的代码,我会担心,术语“1”的确不是一个真正的超链接。阅读超媒体约束或HATEOAS(如果需要)。

要在POST传递是什么:

{ 
    "team_href" : "/teams/1", 
    "name":"can'tbebothered" 
} 

所以服务器看到这个的时候,它只是因为它承认的(相对)URI链接与团队#1新创建的员工。

1

我会用一个专用的链接类型,我仿照它在XML的链接标签,但它会映射到以下JSON:

 

{ 
    ... 
    links: 
    [ 
     { 
      "href" : "/teams/1", 
      "rel" : "team" 
     }, 
     { 
      "href" : "/teams/2", 
      "rel" : "team" 
     } 
    ] 
} 
 

我喜欢上面的链接风格,因为它是更通用的(可以定义关系通过rel属性)。对我来说,链接概念在HTTP REST中非常重要,我为它奉献了一种自己的类型。

当心某些情况下,出于性能的考虑(避免网络调用遍历链接的资源),你需要这样的内联关系。为此,您可以提供一个返回内联表示/employee/123?inline=true的开关。但只有提供这样的噱头,如果真的有必要的话。我曾经这样做过,但是实现并不是微不足道的(尽管我的格式是XML,它更受限于模式定义)。

0

有多种方式来处理这个问题的解决方案。它是RESTful Web服务领域中的一个类超链接问题。由于这与Jersey有关,我建议的第一件事是避免JAXB聚集在一起,因为JAXB(在XML或JSON环境中)不是HATEOAS。

越来越少了很多与新泽西州和HATEOAS后,我已经来到了意见,对于一个REST风格的WS最好的表示是Atom联合格式加上JSON。对于你的团队和员工的例子,我会采取以下方法。

GET /team/ - returns a paginated Atom Syndication Feed list of teams 
POST /team/ - creates a new team receiving a JSON representation 
GET /team/1 - returns a paginated Atom Syndication Feed list of employees in the 
       team with the ID 1 with an Link to team's JSON representation too. 

GET /employee/ - returns a paginated Atom Syndication Feed list of employees 
POST /employee/ - creates a new employee using JSON 
GET /employee/1 - returns details about the employee with the ID 1 in JSON 

直到这里我没有改变太多只是指定一些表示的细节。有趣的部分是添加/删除团队中的员工。为此,我想补充的资源与模式

@Path("/team/{id}/employees) 
class TeamEmployees { 

    @Path("/{posId}") 
    @GET 
    @Produces(MediaType.APPLICATION_JSON) 
    public Employee get(@PathParam("posId") int positonId) {} 

    @Path("/{posId}") 
    @DELETE 
    public Employee remove(@PathParam("posId") int positonId) {} 

    @POST 
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 
    //empUri sample is /employee/{id} server knows how to parse it 
    public Employee add(@FormParam("employeeUri") String empUri) {} 

} 

现在是什么位置ID,一个方法 - 这是在所有球队的唯一编号,即在其中将有position_id,TEAM_ID一个表的主键,emp_id为的元组。确保 两个队伍永远不会有2个position_id。这样整个场景可以变成HATEOAS。

除了能够在JSON表示导出的URI的DTO,我采取的是方法,我有DTO代表其持久存储数据模型和我有一个表示表示模型超链接(de)可串行化版本DTO其中我将字符串值存储为超链接。我看表示模型作为API和DTO作为SPI REST风格的WS数据模型。