处理Spring中的关系(“REST”?)控制器

时间:2017-09-19 22:16:49

标签: spring rest spring-mvc spring-boot spring-rest

我目前正在开发一个具有多个模型对象的应用程序,这些对象之间有很多关系。

例如,我有一个用户对象和一个包含多个用户的组对象。

我们为这些对象公开的端点是:

/users
/users/{uid}
/users/{uid}/groups
/users/{uid}/groups/{gid}

/groups
/groups/{gid}
/groups/{gid}/users
/groups/{gid}/users/{uid}

到目前为止这很容易。现在让我们说每个用户和每个组都可以拥有设置,消息,头像...... ....

现在我们可以公开端点,例如

/users/{uid}/avatar
/groups/{uid}/avatar
/users/{uid}/messages
/users/{uid}/messages/{mid}
/groups/{gid}/messages
/groups/{gid}/messages/{mid}
/users/{uid}/settings
/groups/{gid}/settings

即使只有6个关系(用户 - >头像,群组 - >头像,用户 - >消息,群组 - >消息,用户 - >设置,群组 - >设置),RequestMappings的数量当我们考虑各种CRUD操作(PUT,DELETE,POST,GET,..)时,(端点)会大大增加

如果我添加另一个资源,例如可以包含多个组的groupOfGroups,我将公开的RequestMappings数量将呈指数级增长

/gog/{gogid}/groups
/gog/{gogid}/groups/{gid}
/gog/{gogid}/groups/{gid}/users
/gog/{gogid}/groups/{gid}/users/{uid}
/gog/{gogid}/settings
/gog/{gogid}/messages
/gog/{gogid}/avatar

我还要为CRUD操作添加RequestMappings。

为了避免代码重复,我一直在每个主控制器中使用catch all request mapping。例如,在UserController中,我将有以下requestMappings

GET /users
GET /users/{id}
POST /users
PUT /users/{id}
DELETE /users/{id}
/**

/ **映射会捕获/ users / {uid} / messages / {mid}调用。在/ **映射对应的方法内,我将执行以下操作

  1. Tokenize Request URL获取/ users / {uid}和 restOfTheUrl (在这种情况下,/ message / {mid}但可以是/ settings或/ avatar)
  2. 检查具有该uid的用户是否存在,如果他不
  3. 则返回404
  4. 使用关键用户和值{uid}
  5. 添加requestAttribute
  6. 转发至 restOfTheUrl
  7. 这会将请求转发到MessageController,我可以使用一些QueryDSL构建器来构建QueryDSL,只获取请求attrbitute中的任何内容的消息(在这种情况下,它是具有{uid}的用户,但它可以是一个id为{gid}的组或一个id为{gogid}

    的groupOfGroups

    我想知道这是否是正确的解决方案,或者是否有更好的方式来处理关系而无需转发,但也无需重复代码。

    至少在我看来,有三个终点是不合理的

    /users/{uid}/messages
    /users/{uid}/settings
    /users/{uid}/avatar
    

    检查用户是否存在,并且对group和groupOfGroups执行相同的功能,但唯一的区别是我们正在检查组是否存在或groupOfGroups是否存在。

    重要的是要注意像Swagger这样的工具当然不支持这种方法,甚至转发,@ RestController也不能使用,只能使用更通用的web mvc注释@Controller。

    我想知道最好的方法是遵循这里。

1 个答案:

答案 0 :(得分:0)

在我看来,您正试图在URI路径中表示关系(或者也可能是导航)。 REST中的关系表示为链接,来自https://stackoverflow.com/a/6328171/1536382

  

可以说一个团队有一个文档资源(/ team / {id} / players),这是团队中玩家(/ player / {id})的链接列表,玩家可以拥有一个文档资源(/ player / {id} / teams),是指该玩家所属团队的链接列表

REST不是关于URI的外观,而是关于向客户端发送指向某个州可用操作的链接(例如:如果我在我可以去{{1} })。只要服务器构建链接并且客户端只使用它们,链接的结构就不重要了。

但是,您的一些URI包含他们需要的更多信息(并且可能需要建立uri(而不是休息)的客户端知道它不需要知道的事情):{{1 }和/users/1/users/1/messages相同,因为/gog/{gogid}/groups/{gid}/users/{uid}始终可以检索用户的数据。

另一种可能性是/groups/{gid}/users/{uid}实际上意味着"表示用户和组之间关联的资源"包括例如用户加入组的日期;如果是这种情况,那么对我来说这是一个新资源,例如:/users/{uid},有自己的ID,可以映射到{uid}/groups/{gid}/users/{uid}可以重定向到它。会员资格将列在membership

/membership/{membership-id}/groups/{gid}/users/{uid}可以重定向到/groups/{gid}/memberships。如果共享头像,则在使用HTTP缓存时可能会有好处。