我想使用Grails中的JSON渲染方法渲染复杂类型,类似于下面的JSON输出:
{"authors":[{"id":1,"name":"Author 1","books":[{"id":1,"name":"Book 1"},{"id":2,"name":"Book 2"}]},{"id":2,"name":"Author 2","books":[{"id":1,"name":"Book 1"},{"id":2,"name":"Book 2"}]}]}
我尝试使用以下代码执行此操作,其中Author和Book是包含属性id和name的域类,以及Author hasMany Books(association)。
def results = Authors.list()
render(contentType:"text/json") {
authors = array {
for(a in results) {
author id:a.id, name:a.name, books: array = {
def bookresults = Book.findAllByAuthor(a)
for(b in bookresults) {
book id:b.id, name:b.name
}
}
}
}
}
单独作者可以很好地工作,但是当我尝试遍历每个作者的书籍并渲染它们时,代码就会失败。
有什么想法吗?
使用最终代码更新了问题
感谢Dave的回答,我最终得到了以下能够按预期工作的代码:
def authors = []
for (a in Author.list()) {
def books = []
def author = [id:a.id, name:a.name, books:books]
for (b in Book.findAllByAuthor(a)) {
def book = [id:b.id, name:b.name]
books << book
}
authors << author
}
def items = [authors:[authors]]
render items as JSON
答案 0 :(得分:10)
我发现JSON构建器很难用于获得所需的结果I prefer to generate the results in maps and lists and then render those。
通过以下内容(警告:未经测试的代码!):
def results = []
Authors.list()?.each{ author ->
def authorResult = [id:author.id, name:author.name]
Book.findAllByAuthor(author)?.each { book ->
authorResultput('books', [id:book.id, name:book.name])
}
results << authorResult
}
def authors = [authors: results]
render authors as JSON
我认为你让代码更容易阅读和重用,它应该做你想要的(我的错别字允许)。
如果你总是以相同的JSON格式呈现你的作者和书籍,你可能会考虑registering a custom JSON object marshaller in Bootstrap.groovy。总之类似的工作:
JSON.registerObjectMarshaller(Author) {
def returnArray = [:]
returnArray['id'] = it.id
returnArray['name'] = it.name
return returnArray
}
在您的作者上拥有书籍属性也会让事情变得更容易!