java - 如何使用 spring 管理 REST API 版本控制?

标签 java spring rest spring-mvc versioning

我一直在寻找如何使用 Spring 3.2.x 管理 REST API 版本,但我没有找到任何易于维护的东西。我将首先解释我遇到的问题,然后是解决方案……但我想知道我是否在这里重新发明了轮子。

我想根据Accept header 管理版本,例如如果一个请求有Accept header application/vnd.company.app-1.1+json,我希望spring MVC转发this 到处理这个版本的方法。而且由于并非 API 中的所有方法都在同一个版本中更改,因此我不想转到我的每个 Controller 并更改版本之间未更改的处理程序的任何内容。我也不希望有逻辑来确定在 Controller 本身中使用哪个版本(使用服务定位器),因为 Spring 已经在发现要调用的方法。

因此采用了 1.0 到 1.8 版本的 API,其中在 1.0 版本中引入了处理程序并在 v1.7 中进行了修改,我想通过以下方式处理这个问题。想象一下代码在 Controller 内部,并且有一些代码能够从 header 中提取版本。 (以下在Spring中无效)

@RequestMapping(...)
@VersionRange(1.0,1.6)
@ResponseBody
public Object method1() {
   // so something
   return object;
}

@RequestMapping(...) //same Request mapping annotation
@VersionRange(1.7)
@ResponseBody
public Object method2() {
   // so something
   return object;
}

这在 spring 中是不可能的,因为这 2 个方法具有相同的 RequestMapping 注释并且 Spring 无法加载。这个想法是 VersionRange 注释可以定义一个开放或封闭的版本范围。第一种方法从 1.0 到 1.6 版本有效,而第二种方法适用于 1.7 及以上版本(包括最新版本 1.8)。我知道如果有人决定通过 99.99 版,这种方法就会失效,但我可以接受。

现在,由于没有对 spring 的工作方式进行认真的返工,上述内容是不可能的,我正在考虑修改处理程序与请求匹配的方式,特别是编写我自己的 ProducesRequestCondition,并拥有那里的版本范围。例如

代码:

@RequestMapping(..., produces = "application/vnd.company.app-[1.0-1.6]+json)
@ResponseBody
public Object method1() {
   // so something
   return object;
}

@RequestMapping(..., produces = "application/vnd.company.app-[1.7-]+json)
@ResponseBody
public Object method2() {
   // so something
   return object;
}

通过这种方式,我可以在注释的产生部分中定义封闭或开放的版本范围。我现在正在研究这个解决方案,问题是我仍然需要替换一些核心 Spring MVC 类(RequestMappingInfoHandlerMappingRequestMappingHandlerMappingRequestMappingInfo ),这是我不喜欢的,因为每当我决定升级到新版本的 spring 时,这意味着额外的工作。

如果有任何想法,我将不胜感激……尤其是任何以更简单、更易于维护的方式执行此操作的建议。


编辑

添加赏金。要获得赏金,请回答上面的问题,而不建议在 Controller 本身中使用此逻辑。 Spring 已经有很多逻辑可以选择调用哪个 Controller 方法,我想捎带它。


编辑 2

我在 github 中分享了原始 POC(经过一些改进):https://github.com/augusto/restVersioning

最佳答案

无论是否可以通过向后兼容的更改来避免版本控制(当您受到某些公司准则的约束或您的 API 客户端以错误的方式实现并且即使不应该这样做也会中断时,这可能并不总是可行)抽象的要求很有趣:

如何进行自定义请求映射,对请求中的 header 值进行任意评估,而不在方法主体中进行评估?

this SO answer 中所述你实际上可以拥有相同的@RequestMapping并使用不同的注释来区分运行时发生的实际路由。为此,您必须:

  1. 新建注释VersionRange .
  2. 实现 RequestCondition<VersionRange> .由于您将拥有类似最佳匹配算法的东西,因此您必须检查方法是否用其他 VersionRange 注释。值可以更好地匹配当前请求。
  3. 实现 VersionRangeRequestMappingHandlerMapping基于注释和请求条件(如帖子 How to implement @RequestMapping custom properties 中所述)。
  4. 配置 spring 以评估您的 VersionRangeRequestMappingHandlerMapping在使用默认 RequestMappingHandlerMapping 之前(例如,通过将其顺序设置为 0)。

这不需要对 Spring 组件进行任何 hacky 替换,而是使用 Spring 配置和扩展机制,因此即使您更新 Spring 版本(只要新版本支持这些机制),它也应该可以工作。

关于java - 如何使用 spring 管理 REST API 版本控制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20198275/

相关文章:

java - FileChannel 与 RandomAccessFile

java - 在插件 com.google.appengine :appengine-maven-plugin 中找不到目标 'run'

java - 编译项目时出现错误 : Unable to locate Spring NamespaceHandler

django - 如何将Haystack与Django Rest Framework集成以制作GET REST API进行搜索?

rest - 使用Teamcity REST API获取构建日志

java - 不使用 Windows 任务计划程序来计划可执行文件

java - Spring JPA 自动扫描 jar 文件中的实体

java - Spring Integration SFTP - 从 XML 获取配置

rest - 将 RPC 接口(interface)转换为 REST

java - 对继承感到困惑,有人可以帮助我吗?