我试图学习如何使用Jersey和Java在Java中编写RESTful应用程序 Hibernate,我很难理解如何处理父/子类型 将数据发布到资源时的关系。我正在使用JSON进行交换 数据,但我认为这与我的问题无关。
我正在使用的示例模拟员工与员工之间的关系 团队。员工可能是也可能不是一个团队的成员:
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
在这背后我有一些Hibernate注释的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对象中传入嵌套的团队对象。
例如,我希望能够使用JSON调用POST / employee / 看起来像这样:
{
"team_id":"1",
"name":"Fred Bloggs",
"phone":"1234567890",
"email":"test@example.com"
}
但是,相反,我必须传递这样的东西:
{
"team":{
"id":"1",
}
"name":"Fred Bloggs",
"phone":"1234567890",
"email":"test@example.com"
}
所以,我的问题是,其他人如何处理在JSON / REST中创建关系而不传递整个对象图?
对不起,这是一个粗略的问题,但正如我所说,我刚开始 在这个阶段,术语对我来说是一个问题!
答案 0 :(得分:1)
如果您的框架强制您的表示包含奇怪的结构,如{ "id":"1" }
,那么我会说是时候切换框架了!
更重要的是,我担心术语“1”确实不是真正的超链接,而不是担心在代码中添加子JSONObject。如果需要,请阅读超媒体约束或HATEOAS。
你想在POST中传递的是:
{
"team_href" : "/teams/1",
"name":"can'tbebothered"
}
所以当服务器看到这个时,它只是因为它识别(相对)URI而将新创建的员工与团队#1链接起来。
答案 1 :(得分:1)
我会使用专用链接类型,我在xml-link标签中建模,但它会映射到以下json:
{
...
links:
[
{
"href" : "/teams/1",
"rel" : "team"
},
{
"href" : "/teams/2",
"rel" : "team"
}
]
}
我更喜欢上面的链接样式,因为它更通用(通过rel属性定义关系)。对我来说,链接概念在HTTP REST中非常重要,我为它专门设置了一个类型。
在某些情况下请注意性能原因(避免网络调用遍历链接资源),您需要内联此类关系。为此,您可以提供一个开关来返回内联表示/employee/123?inline=true
。但是,如果真的有必要,只提供这样的噱头。我曾经不得不这样做,但实现并不简单(尽管我的格式是XML,它更受模式定义的限制)。
答案 2 :(得分:0)
REST提供了使用URL作为参考的可能性,我觉得这很酷。所以它看起来像这样:
{
"team":"http://myapp.com/team/1",
"name":"Fred Bloggs",
"phone":"1234567890",
"email":"test@example.com"
}
您也可以通过提供
来避免传递嵌套对象{
"team":"1",
"name":"Fred Bloggs",
"phone":"1234567890",
"email":"test@example.com"
}
在这种情况下,你的转换器必须足够智能,以确定如果团队密钥的值是一个字符串(或整数,无论什么工作),而不是另一个JSON对象,它应该被解释为id。
答案 3 :(得分:0)
有多种方法可以解决此问题。它是RESTful Web服务领域中的类超链接问题。由于这与Jersey有关,我建议首先避免JAXB,因为JAXB(在XML或JSON的上下文中)不是HATEOAS。
在使用Jersey和HATEOAS逐渐减少之后,我发现RESTful WS的最佳表示形式是Atom Syndication Format和JSON。对于Team和Employee的示例,我将采用以下方法。
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支队伍永远不会有2个position_id相同。这样整个场景就可以变成HATEOAS。
除了能够将JSON表示中的URI导出到DTO之外,我采用的方法是, DTO 代表其持久性存储的数据模型我有表示模型表示 DTO 的超链接(可)序列化版本,其中我将字符串值存储为超链接。我将表示模型视为API,将 DTO 视为RESTful WS数据模型的SPI。