spring 如何从REST API响应中删除循环引用?

cbjzeqam  于 2023-06-28  发布在  Spring
关注(0)|答案(1)|浏览(73)

当返回一个json,它有一个引用父对象的子对象时,会有一个循环引用问题,因为循环永远不会结束,所以会导致错误。
例如,假设我在User实体和Roles实体之间有一个关系,我想在json中返回它们。
GetUsers

{
    "userId": "1",
    "userName": "USER1",
    "roles": [
        {
            "roleId": "5",
            "role": "ADMIN",
            "users": [
                    {   /*CIRCULAR REFERENCE HERE*/
                        "userId": "1",
                        "userName": "USER1",
                        "roles": [...]
                    },
                    {
                        "userId": "2",
                        "userName": "USER2",
                        "roles": [...]
                    }
                ]

        },
        {
            "roleId": "6",
            "role": "MANAGER"
            "users": [...]
        }
    ]
}

GetRoles

{
    "roleId": "5",
    "role": "ADMIN",
    "users": [
        {
            "userId": "1",
            "userName": "USER1",
            "roles": [
                    {   /*CIRCULAR REFERENCE HERE*/
                        "roleId": "5",
                        "role": "ADMIN",
                        "users": [...]
                    },
                    {
                        "roleId": "6",
                        "role": "MANAGER",
                        "users": [...]
                    }
                ]

        },
        {
            "userId": "2",
            "userName": "USER2",
            "roles": [...]
        }
    ]
}

解决这个问题的最佳方法是什么?
我知道我可以在Users实体中使用@JsonIgnore for Roles属性,并在Roles实体中使用@JsonIgnore for Users属性。
但是GetUsers不会返回角色数据,GetRoles也不会返回用户数据。
我想要一个返回这些的解决方案,但不是循环引用。像这样:
GetUsers

{
    "userId": "1",
    "userName": "USER1",
    "roles": [
        {
            "roleId": "5",
            "role": "ADMIN"
        },
        {
            "roleId": "6",
            "role": "MANAGER"
        }
    ]
}

GetRoles

{
    "roleId": "5",
    "role": "ADMIN",
    "users": [
        {
            "userId": "1",
            "userName": "USER1"
        },
        {
            "userId": "2",
            "userName": "USER2"
        }
    ]
}
jtoj6r0c

jtoj6r0c1#

一种方法是返回对标识符的引用,而不是完整的对象:

{
  "users": [ 
     {
        "userId": "1",
        "userName": "USER1",
        "roleIds": ["5, 6"]
     },
     {
         "userId": "2",
         "userName": "USER2",
         "roleIds": ["5, 6"]
     }
  ],

  "roles": [
     {
        "roleId": "5",
        "role": "ADMIN",
        "userIds": ["1", "2"]
     },
     {
        "roleId": "6",
        "role": "MANAGER",
        "userIds": ["1", "2"]
     }
  ]
}

您还可以使用Falcor中描述的更通用的方法:

{
    "usersById": {
        "1": {
            userName: "USER1",
            roles: [
              { $type: "ref", value: ["rolesById", "5"] },
              { $type: "ref", value: ["rolesById", "6"] }
            ]
        },
        "2": {
            userName: "USER2",
            roles: [
              { $type: "ref", value: ["rolesById", "5"] },
              { $type: "ref", value: ["rolesById", "6"] }
            ]
        }
    },
    "rolesById": {
        "5": {
           role: "ADMIN",
           users: [
              { $type: "ref", value: ["usersById", "1"] },
              { $type: "ref", value: ["usersById", "2"] }
           ]
        },
        "6": {
           role: "MANAGER",
           users: [
              { $type: "ref", value: ["usersById", "1"] },
              { $type: "ref", value: ["usersById", "2"] }
           ]
        }

    },
    "users": [
        { $type: "ref", value: ["usersById", "1"] },
        { $type: "ref", value: ["usersById", "2"] }       
    ],
    "roles": [
        { $type: "ref", value: ["rolesById", "5"] },
        { $type: "ref", value: ["rolesById", "6"] }       
    ]
}

编辑

获取用户

只需创建没有循环引用的DTO:

{
    "userId": "1",
    "userName": "USER1",
    "roles": [
        {
            "roleId": "5",
            "role": "ADMIN"
        },
        {
            "roleId": "6",
            "role": "MANAGER"
        }
    ]
}

相关问题