我使用Grails和AngularJS制作一个RESTful twitter / facebook克隆,所以它是一个标准用户可以发帖,用户可以喜欢发帖,用户也可以关注其他用户。
我正在使用JSON对象marshallers,以便域类的hasMany
或belongsTo
的属性将在JSON中呈现。
我已在User
和Post
域之间插入了相似功能的必要关系,以及我在Bootstrap.groovy
中实施这些关系时是否发送GET
请求到api/posts/
一切正常,但问题是当我使用按钮实现它们时。
此按钮向PUT
发送api/posts/:id
请求,这将转到我update()
的{{1}}方法。类似的内容正在插入到数据库中,但如果我再向PostController
发送另一个GET
请求,则会收到此错误
api/posts
这些是我的代码
User.groovy
....Error
|
2015-09-26 00:54:35,986 [http-bio-8090-exec-9] ERROR
errors.GrailsExceptionResolver
- JSONException occurred when processing request: [GET] /restsocnet/api/posts
Misplaced endArray.. Stacktrace follows:
Message: Misplaced endArray.
Line | Method
->> 202 | value in grails.converters.JSON
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 162 | convertAnother in ''
| 202 | value . . . . . . in ''
| 134 | render in ''
| 150 | render . . . . . . in ''
| 19 | index in com.patrickjuen.restsocnet.PostController
| 198 | doFilter . . . . . in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 118 | processFilterChain in grails.plugin.springsecurity.rest.RestTokenValidationFilter
| 84 | doFilter in ''
| 53 | doFilter . . . . . in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
| 143 | doFilter in grails.plugin.springsecurity.rest.RestAuthenticationFilter
| 62 | doFilter . . . . . in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
| 82 | doFilter in com.brandseye.cors.CorsFilter
| 1142 | runWorker . . . . in java.util.concurrent.ThreadPoolExecutor
| 617 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run . . . . . . . in java.lang.Thread
Post.groovy
package com.patrickjuen.restsocnet
class User implements Serializable {
private static final long serialVersionUID = 1
transient springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static hasMany = [posts: Post, likedPost: Post]
static mappedBy = [posts: "user"]
User(String username, String password) {
this()
this.username = username
this.password = password
}
@Override
int hashCode() {
username?.hashCode() ?: 0
}
@Override
boolean equals(other) {
is(other) || (other instanceof User && other.username == username)
}
@Override
String toString() {
username
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this)*.role
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}
static transients = ['springSecurityService']
static constraints = {
username blank: false, unique: true
password blank: false
likedPost nullable: true
}
static mapping = {
password column: '`password`'
posts lazy: false, sort: 'dateCreated', order: 'desc'
likedPost lazy: false
}
}
package com.patrickjuen.restsocnet
import grails.converters.JSON
//import grails.plugin.springsecurity.annotation.Secured
import org.springframework.security.access.annotation.Secured
@Secured(['isFullyAuthenticated()'])
class PostController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def springSecurityService
def index() {
render Post.list(sort: "dateCreated", order: "desc") as JSON
}
def save(){
def newPost = new Post(request.JSON)
if(!newPost.hasErrors()){
def currentUser = User.get(springSecurityService.principal.id)
println currentUser
newPost.user = currentUser
newPost.save(failOnError: true)
// currentUser.addToPosts(newPost)
render (['success': true] as JSON)
}
}
def show(){
def post = Post.get(params.id)
render post as JSON
}
def update(){
def post = Post.findById(params.id)
if(!post.hasErrors()){
def currentUser = User.get(springSecurityService.principal.id)
post.addToLikers(currentUser)
post.save(flush: true)
render(['success': true] as JSON)
}
}
}
BootStrap.groovy中
package com.patrickjuen.restsocnet
class Post {
String content
Date dateCreated
User user
static belongsTo = User
static hasMany = [likers: User]
// static mappedBy = [likers: "likedPost"]
static constraints = {
likers nullable: true
}
static mapping = {
likers lazy: false
}
}
PostController.groovy
import com.patrickjuen.restsocnet.Post
import com.patrickjuen.restsocnet.Role
import com.patrickjuen.restsocnet.User
import com.patrickjuen.restsocnet.UserRole
import grails.converters.JSON
class BootStrap {
def init = { servletContext ->
JSON.registerObjectMarshaller(User) {
def returnArray = [:]
returnArray['id'] = it.id
returnArray['username'] = it.username
returnArray['posts'] = it.posts
return returnArray
}
JSON.registerObjectMarshaller(Post) {
def returnArray = [:]
returnArray['id'] = it.id
returnArray['content'] = it.content
returnArray['dateCreated'] = it.dateCreated
returnArray['user'] = it.user
returnArray['likers'] = it.likers
return returnArray
}
def role = new Role(authority: "ROLE_USER")
def user1 = new User(username: "user1", password: "password")
def user2 = new User(username: "user2", password: "password")
role.save()
user1.save()
user2.save()
def post1 = new Post(content: "new post number 1")
def post2 = new Post(content: "new post number 2")
def post3 = new Post(content: "one more ")
def post4 = new Post(content: "i am user2 guys hehehe")
post1.save()
post2.save()
post3.save()
post4.save()
user1.addToPosts(post1)
user1.addToPosts(post2)
user1.addToPosts(post3)
user2.addToPosts(post4)
post2.addToLikers(user2)
post2.addToLikers(user1)
post1.addToLikers(user1)
UserRole.create(user1, role, true)
UserRole.create(user2, role, true)
}
def destroy = {
}
}
我尝试删除JSON对象marshallers并且它不再发出错误但我将无法访问package com.patrickjuen.restsocnet
import grails.converters.JSON
//import grails.plugin.springsecurity.annotation.Secured
import org.springframework.security.access.annotation.Secured
@Secured(['isFullyAuthenticated()'])
class PostController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def springSecurityService
def index() {
render Post.list(sort: "dateCreated", order: "desc") as JSON
}
def save(){
def newPost = new Post(request.JSON)
if(!newPost.hasErrors()){
def currentUser = User.get(springSecurityService.principal.id)
println currentUser
newPost.user = currentUser
newPost.save(failOnError: true)
// currentUser.addToPosts(newPost)
render (['success': true] as JSON)
}
}
def show(){
def post = Post.get(params.id)
render post as JSON
}
def update(){
def post = Post.findById(params.id)
if(!post.hasErrors()){
def currentUser = User.get(springSecurityService.principal.id)
post.addToLikers(currentUser)
post.save(flush: true)
render(['success': true] as JSON)
}
}
}
的属性。所以我猜主要的问题是JSON对象marshallers。我错误地执行了它们吗?或者是否有使用JSON对象marshallers的替代方法?但是,当我在hasMany
中实现它时,它再次正常工作
此外,我尝试将Bootstrap.groovy
更改为仅post.save(flush:true)
它没有发出错误,但未在数据库中保存。
以防您对正在呈现的JSON感兴趣。
这是对post.save()
GET
请求
没有JSON对象marshallers
api/posts/
使用JSON对象marshallers
[
{
"class": "com.patrickjuen.restsocnet.Post",
"id": 4,
"content": "i am user2 guys hehehe",
"dateCreated": "2015-09-25T17:39:10Z",
"likers": [],
"user": {
"class": "com.patrickjuen.restsocnet.User",
"id": 2
}
},
{
"class": "com.patrickjuen.restsocnet.Post",
"id": 3,
"content": "one more",
"dateCreated": "2015-09-25T17:39:10Z",
"likers": [],
"user": {
"class": "com.patrickjuen.restsocnet.User",
"id": 1
}
},
{
"class": "com.patrickjuen.restsocnet.Post",
"id": 2,
"content": "new post number 2",
"dateCreated": "2015-09-25T17:39:10Z",
"likers": [
{
"class": "com.patrickjuen.restsocnet.User",
"id": 1
},
{
"class": "com.patrickjuen.restsocnet.User",
"id": 2
}
],
"user": {
"class": "com.patrickjuen.restsocnet.User",
"id": 1
}
},
{
"class": "com.patrickjuen.restsocnet.Post",
"id": 1,
"content": "new post number 1",
"dateCreated": "2015-09-25T17:39:10Z",
"likers": [
{
"class": "com.patrickjuen.restsocnet.User",
"id": 1
}
],
"user": {
"class": "com.patrickjuen.restsocnet.User",
"id": 1
}
}
]
答案 0 :(得分:1)
我刚刚找到了解决方案。此代码只需插入Config.groovy
grails.converters.json.circular.reference.behaviour = "INSERT_NULL"