【问题标题】:Handling Relationships in Spring ("REST"?) controllers在 Spring(“REST”?)控制器中处理关系
【发布时间】:2018-02-28 20:01:05
【问题描述】:

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

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

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

/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 个关系(user->avatar、group->avatar、user->messages、group->messages、user->setting、group->settings),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。

为了避免代码重复,我一直在每个主控制器中使用捕获所有请求映射。例如,在 UserController 中,我会有以下 requestMappings

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

/** 映射将捕获 /users/{uid}/messages/{mid} 调用。在/**映射对应的方法里面,我会做如下操作

  1. 令牌化请求 URL 以获取 /users/{uid} 和 restOfTheUrl(在本例中为 /message/{mid} 但可以是 /settings 或 /avatar)
  2. 检查具有该 uid 的用户是否存在,如果不存在则返回 404
  3. 添加一个 requestAttribute,其中包含关键用户和值 {uid}
  4. 转发到 restOfTheUrl

这会将请求转发到 MessageController,在那里我可以使用一些 QueryDSL 构建器来构建 QueryDSL,以仅获取请求属性中的任何消息(在这种情况下,它是具有 {uid} 的用户,但它可以是 ID 为 {gid} 的组或 ID 为 {gogid} 的 groupOfGroups

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

至少在我看来,拥有三个端点是没有意义的

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

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

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

我想知道这里最好的方法是什么。

【问题讨论】:

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


    【解决方案1】:

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

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

    REST 不是关于 URI(s) 的外观,更多的是关于向客户端发送从某个状态可用的操作的链接(例如:如果我在/users/1,我可以转到/users/1/messages)。只要服务器构建链接并且客户端只是使用它们,链接的结构就无关紧要了。

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

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

    /users/{uid}/avatar/groups/{gid}/avatar 可以重定向到他们的/avatar/{avatar-id}。如果头像是共享的,这在使用 HTTP 缓存时可能会有好处。

    【讨论】:

      猜你喜欢
      • 2016-01-27
      • 1970-01-01
      • 2020-12-06
      • 2023-03-27
      • 2022-11-29
      • 2016-08-20
      • 1970-01-01
      • 2017-02-24
      • 1970-01-01
      相关资源
      最近更新 更多