在Grails中发布嵌套资源的问题

我在理解Grails Restful控制器如何工作方面遇到了问题。 我正在尝试向嵌套资源发出post请求(见下文)。 我不确定我是否理解我需要更改以使其工作,因为看起来GET请求与其父资源项建立Bid的关联,但是当我尝试POST时,我被警告该项不能为空。

任何帮助表示赞赏!

Item.groovy

class Item { static hasMany = [bids:Bid] } 

Bid.groovy

 class Bid { Integer ownerId Double amount static belongsTo = [item:Item] static constraints = { ownerId nullable: false amount nullable: false } } 

BidController.groovy

 class BidController extends RestfulController { static responseFormats = ['json', 'xml'] BidController() { super(Bid) } @Override def getObjectToBind() { request.parameterMap.put('itemId', params.itemId) return request } } 

ItemController.groovy

 class ItemController extends RestfulController { static responseFormats = ['json', 'xml'] ItemController() { super(Item) } } 

UrlMappings.groovy

 class UrlMappings { static mappings = { "/items"(resources:"item") { "/bids"(resources: "bid") } } } 

URL映射

 Controller: item | GET | /items | Action: index | GET | /items/create | Action: create | POST | /items | Action: save | GET | /items/${id} | Action: show | GET | /items/${id}/edit | Action: edit | PUT | /items/${id} | Action: update | PATCH | /items/${id} | Action: patch | DELETE | /items/${id} | Action: delete Controller: bid | GET | /items/${itemId}/bids | Action: index | GET | /items/${itemId}/bids/create | Action: create | POST | /items/${itemId}/bids | Action: save | GET | /items/${itemId}/bids/${id} | Action: show | GET | /items/${itemId}/bids/${id}/edit | Action: edit | PUT | /items/${itemId}/bids/${id} | Action: update | PATCH | /items/${itemId}/bids/${id} | Action: patch | DELETE | /items/${itemId}/bids/${id} | Action: delete 

发布请求

 POST /AuctionService/items/1/bids HTTP/1.1 Content-Type: application/json Host: localhost:8080 Connection: close Content-Length: 34 { "ownerId": 1, "amount": 3.00 } 

响应

 HTTP/1.1 422 Unprocessable Entity Server: Apache-Coyote/1.1 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 25 Jul 2014 17:44:03 GMT Connection: close {"errors":[{"object":"auctionservice.Bid","field":"item","rejected-value":null,"message":"Property [item] of class [class auctionservice.Bid] cannot be null"}]} 

我认为你可以通过覆盖createResource()方法来完成你想要的。

 @Override protected Bid createResource() { Bid bid=super.createResource(); bid.item=Item.get(params.itemId) return bid; } 

使用嵌套URL时,其他默认控制器操作可能无法按预期工作。 如果要确保只返回属于URL中项目的Bids,您可能还想覆盖queryForResource和index

 @Override protected Stay queryForResource(Serializable id) { def itemId=params.itemId Bid.where { id==id && item.id == itemId }.find() } def index(Integer max) { params.max = Math.min(max ?: 10, 100) def itemId=params.itemId respond Bid.where { item.id==itemId }.list(params) } 

RestfulController的实现有一个方法getObjectToBind() ,它返回请求对象。 我建议覆盖此方法并返回一个包含关键itemId的映射,如此方法的注释中所述。

另一种选择可能是,在http json体中发送itemId。 这有点多余,因为信息已经在url中表示。 但作为一种解决方法,这也可能是一个很好的解决方案。

我建议使用@Resource注释Domain类,即使您实现自己的控制器也是如此。 Grails文档似乎表明你做了一个或另一个,注释域或编写自己的控制器扩展RestfulContoroller。

我发现没有域类注释,请求对象在createResource()方法中没有正确绑定。 所有属性都为null。 一旦我添加域注释,就像我预期的那样发生反绑定。

在您的情况下,我希望/希望Grails能够处理所有关系,而无需您自己管理项目ID。 所以,

 @Resource(uri='items') class Item { static hasMany = [bids:Bid] } 

和…

 @Resource(uri='bids') class Bid { Integer ownerId Double amount static belongsTo = [item:Item] static constraints = { ownerId nullable: false amount nullable: false } } 

希望您不再需要覆盖getObjectToBind()。

 class BidController extends RestfulController { static responseFormats = ['json', 'xml'] BidController() { super(Bid) } //don't override the getObjectTobind } 

当我尝试将对象与一对一映射发布到另一个对象时,这对我有用。