REST Web 服务版本控制实践

2024-03-14

我正在创建一个新的 Web 服务,并且我已经阅读了 APIgee 的一些电子书,其中建议对 Web 服务进行版本控制。我知道在 URL 与标头中保留版本控制信息之间存在一些“斗争”。根据我所阅读和理解的内容,我想在标头中使用版本控制。

我的问题是;这在实践中看起来如何?我正在使用 Spring MVC 3.2。您是否只是在同一控制器中创建这样的方法来响应不同的版本?

版本1:

@RequestMapping(method = RequestMethod.GET, produces = "application/vnd.example-v1+json")

版本2:

@RequestMapping(method = RequestMethod.GET, produces = "application/vnd.example-v2+json")

或者这是错误的?或者更常见的是创建包含不同版本控制器的不同包?或者还有其他方法吗?


这里的问题不是关于版本信息所在的位置(URI 与标头),而是更多关于如何组织不同版本的代码。

我怀疑是否存在单一标准方法。这仅取决于版本的差异程度。

简单的格式更改。例如,假设唯一的区别是您从 V1 中的 XML 迁移到 V2 中的 JSON。在这种情况下,您可以使用完全相同的代码,但只需将应用程序配置为全局输出 JSON 即可。不需要不同的包或控制器。 (例如,您可以使用 JAXB 注释来驱动 XML 和 Jackson 生成的 JSON 输出。)

适度的架构更改。假设 V2 引入了少量破坏性架构更改。在这种情况下,在其上创建新包可能没有意义。您的控制器中可能只有简单的条件逻辑来处理/提供版本的正确表示。

主要架构更改。如果您的架构更改很深且范围很广,您可能需要的不仅仅是单独的控制器。您甚至可能需要不同的域模型(实体/服务)。在这种情况下,为控制器提供一组并行的包,一直到实体、存储库甚至数据库表可能是有意义的。

应用这些想法

方法一。将这些想法应用到你的@RequestMapping例如,您可以按照您所说的进行操作,但如果版本之间的响应完全相同,那么它们应该委托给单个共享方法:

@RequestMapping(
    value = "/orders/{id}",
    method = RequestMethod.GET,
    produces = "application/vnd.example-v1")
@ResponseBody
public Order getOrderV1(@PathVariable("id") Long id) {
    return getOrder(id);
}

@RequestMapping(
    value = "/orders/{id}",
    method = RequestMethod.GET,
    produces = "application/vnd.example-v2")
@ResponseBody
public Order getOrderV2(@PathVariable("id") Long id) {
    return getOrder(id);
}

private Order getOrder(Long id) {
    return orderRepo.findOne(id);
}

类似的东西会起作用。如果版本之间的顺序不同,那么您可以直接在方法中实现差异。

方法2。您可能会尝试的另一件事(我自己没有尝试过)是每种资源类型(例如订单、产品、客户等)都有自己的基本控制器,其中带有 HTTP 方法的方法级注释(仅value and method已定义,但未定义produces)。然后使用特定于版本的扩展来扩展基础,其中扩展控制器具有@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")在班级层面。然后仅覆盖版本和基线之间的增量。我不确定这是否有效但如果是这样的话,这将是一种非常干净的组织控制器的方式。这就是我的意思:

// The baseline
public abstract class BaseOrderController {

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Order getOrder(@PathVariable("id") Long id) { ... }
}    

// V1 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")
public class OrderControllerV1 extends BaseOrderController {

    ... no difference from baseline, so nothing to implement ...
}

// V2 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v2")
public class OrderControllerV2 extends BaseOrderController {

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    @Override
    public Order getOrder(@PathVariable("id") Long id) {
        return orderRepoV2.findOne(id);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

REST Web 服务版本控制实践 的相关文章

  • GET 请求的 Spring 注解

    这两种spring GET方法有什么区别呢 哪一种是首选方法 Component Scope request Path public class TestComponent GET Path hello public String prin
  • 项目缺少所需的注释处理库

    我的 Eclipse IDE 突然在问题视图中显示 xxxx 项目缺少所需的注释处理库 xxxx M2 REPO 中的一些旧 jar 我用谷歌搜索 没有找到任何答案 为什么我的项目使用旧的 jar 以及错误来自哪里 To remove th
  • 具有 CRUD 功能的基于 Spring Web 的管理工具

    在 PHP Symfony 世界里有一个工具叫 Sonata Adminhttps sonata project org https sonata project org 基于 AdminLTE 模板 这是一款一体化管理工具 具有登录 菜单
  • java中的单链表和双向链表?

    在java中 哪个集合接口可以有效地实现单链表和双向链表 请问代码示例吗 毫不奇怪 实现双向链表的正确接口是 LinkedList 看Java文档 http docs oracle com javase 8 docs api java ut
  • 需要正则表达式帮助

    我正在尝试替换两次或多次出现的 br like br br br 标签与两个一起 br br 具有以下模式 Pattern brTagPattern Pattern compile lt s br s s gt s 2 Pattern CA
  • 当 JMS Prod 位于辅助 POJO 类中时,如何在事务中包含 JMS Producer

    简短的问题 有没有办法强制无状态 EJB 调用的 POJO 存在于 EJB 的上下文中 以便事务和资源注入可以在 POJO 中工作 具体来说 在我想要做的事情的上下文中 如何在 EJB 的事务中包含 POJO JMS 生产者 该生产者在调用
  • 有什么方法可以处理 ASP.Net MVC 中的 Put 和 Delete 动词吗?

    只是想知道是否有人知道真正宁静的 Put delete 实现 asp net mvc Preview 5 最好 查看 mvccontrib 项目 http www mvccontrib org http www mvccontrib org
  • Java - JPanel 内有边距和 JTextArea

    我想创建这样的东西 主面板有其边距 x 并且 TextArea 位于该面板的中心 几乎填满了面板 底部是另一个具有自定义尺寸 高度 y 的面板 可以使用某些快捷方式将其切换为可见和不可见 底部面板有 FlowLayout 和几个元素 问题是
  • 如何使用 Spring Boot 传输音频

    我想让用户能够播放声音 我的实现在 Firefox 上运行良好 在 Safari 上 不播放声音 我验证了音频控制可以在 Safari 中与其他网站一起使用 所以 我认为我必须更改控制器中的某些内容 控制器 RequestMapping v
  • Java 中的 ExecuteUpdate sql 语句不起作用

    我正在学习如何将 SQL 与 Java 结合使用 我已成功安装 JDBC 驱动程序 并且能够从数据库读取记录并将其打印在屏幕上 我的问题发生在尝试执行更新或插入语句时 没有任何反应 这是我的代码 问题所在的方法 public static
  • 将现有 eclipse 项目导出到 war 文件时出现“模块名称无效”

    我正在尝试将现有 Eclipse 项目导出到 war 文件 但无论我在 WAR Export 对话框页面中输入什么 系统总是返回 模块名称无效 我不知道如何解决这个问题 谢谢您的帮助 我有同样的问题 我修复了它 请按照以下步骤操作 您可以创
  • 如何使用 swagger-codegen-plugin (maven) 生成客户端代码?

    我需要使用 swagger codegen plugin for maven 在 eclipse 中生成服务器存根代码 你能帮忙怎么做吗 以及需要什么配置 在 pom xml 中 我找到了这个答案 您只需要像下面这样更改 pom xml 即
  • 多线程——更快的方法?

    我有一堂有吸气剂的课程getInt 和一个二传手setInt 在某个领域 比如说领域 Integer Int 一个类的一个对象 比如说SomeClass The setInt 这里是同步的 getInt isn t 我正在更新的值Int来自
  • JAXB 编组器无参数默认构造函数

    我想从 java 库中编组一个 java 对象 当使用 JAXB marschaller 编组 java 对象时 我遇到了一个问题 A 类没有无参数默认构造函数 我使用Java Decompiler来检查类的实现 它是这样的 public
  • Java8:流映射同一流中的两个属性

    我有课Model带有以下签名 class Model private String stringA private String stringB public Model String stringA String stringB this
  • Java 中处理异步响应的设计模式

    我读过类似问答的答案 如何在 JAVA 中创建异步 HTTP 请求 https stackoverflow com questions 3142915 how do you create an asynchronous http reque
  • 传递 Android DialogFragment 参数时,onCreateDialog 捆绑参数意外为 null

    我正在尝试使用 DialogFragment 在 Android 中显示一个基本对话框 并使用对话框消息的参数 如中所述StackOverflow线程 https stackoverflow com questions 15459209 p
  • 如何将库添加到 LIBGDX 项目的依赖项 gradle

    一切都在问题中 我已经尝试了在 SO 和其他网站中找到的所有答案 但没有运气 这就是我迄今为止尝试过的 adding compile fileTree dir lib include jar 到我的 build gradle adding
  • 使用 AmazonSNSClient 发送短信时的授权

    aws 官方文档如何发送短信 http docs aws amazon com sns latest dg sms publish to phone html使用 java 中的 aws SDK 非常简单 但是 当发送如底部示例所示的消息时
  • 将数组值导出到 csv 文件 java

    我只需要帮助将数组元素导出到 csv 文件 我不知道我的代码有什么问题 任何帮助将不胜感激 谢谢 for int index 0 index lt cols length index FileWriter fw new FileWriter

随机推荐

  • Java:非静态嵌套类和instance.super()

    我很难理解 Java 中的非静态嵌套类 考虑以下示例 它先打印 Inner 然后打印 Child class Outer class Inner Inner System out println Inner public class Chi
  • 在 SQL Server 2005 中使用 TABLOCK 和 HOLDLOCK 提示是否会完全阻止插入直到事务结束?

    我需要检索 SQL Server 2005 生成的标识字段 通常我只使用 SCOPE IDENTITY 或向插入添加 OUTPUT CLAUSE 但是这些方法在这种情况下都没有帮助 因为表附加了 INSTEAD OF 触发器 接下来我考虑了
  • C++20 中概念的语法

    在这个问题中我们如何转换需求link https stackoverflow com questions 67133581 check if type has certain value types and the keyword valu
  • 如何管理扩展方法的名称空间?

    您是否为所有扩展方法使用全局的 包罗万象的命名空间 或者是否将扩展方法放在与其扩展的类相同的命名空间中 或者您是否使用其他方法 例如应用程序或特定于库的命名空间 我问是因为我需要延长System Security Principal IId
  • MaterialContainerTransform 转换在返回时不起作用

    我的 MaterialContainerTransform 转换是从源 gt 目标进行的 但反之则不然 我的情况非常标准 我试图提供从 RecyclerView 项目 源片段 到 详细信息 片段 目标片段 的简单转换 RecyclerVie
  • 完全合格的域名是否需要句点?

    我对 FQDN 完全合格域名 感到困惑 FQDN 是否需要以句点结尾 喜欢sun or sun tuc noao edu or sun tuc noao edu 有什么不同 IT 的工作原理 域名 系统 https technet micr
  • Android:IllegalArgumentException:无法找到包含/data/data/的配置根目录

    刚刚进入 Android 的 Glide 图像加载库 使用这里的代码 https github com bumptech glide issues 459 https github com bumptech glide issues 459
  • 有人可以向我解释一下 Flutter 中 Builder 类的作用吗?

    该文档非常混乱和模糊 它是这样说的 建造者类 一个柏拉图式的小部件 它调用闭包来获取其子小部件 这是我的问题 他们所说的 柏拉图式 是什么意思 他们所说的 关闭 是什么意思 这堂课的目的到底是什么 经过长时间在互联网上进行的大量令人费解的研
  • Web 服务请求身份验证

    我们真的被困在这里所以我决定寻求你的帮助 昨天 我被要求帮助使用 Web 服务 获取 WSDL 的 URL 以及要使用的用户凭据 我从未真正与 Web 服务有任何关系 但对它们有一个总体了解并看到了一些示例 我认为它不会那么糟糕 显然我错了
  • 使用 nvcc 编译给出“没有这样的文件或目录”

    我正在尝试在 Ubuntu 上使用 nvcc 编译 CUDA 代码 但是 当我这样做时 我得到以下输出 gt make usr local cuda bin nvcc m64 ptxas options v gencode arch com
  • “main.cpp”在 Qt 项目中的作用

    在Qt项目中我们通常会找到一个project pro文件 该main cpp和几个标题 源和 ui文件 包含为应用程序 项目注入生命和功能的所有资源 如果还有更多的话 按下按钮即可显示 你好 世界 可能存在用于存储数据和配置文件等的目录 我
  • 有人知道我可以嵌入 WPF 窗口或 Windows 窗体中的代码编辑器吗? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我想创建自己的 IDE 但我想要一个代码编辑器 语法高亮 我想将它作为控件嵌入到 WPF 窗口中 Malcolm The 夏普开发IDE
  • 在更新语句中获取最新的行版本/时间戳值 - Sql Server

    我正在使用 rowversion 列来处理乐观并发 并希望在完成更新后获取新的 rowversion 值 以便我的数据层具有最新值 并且可以通过获取并发异常来执行另一次更新 除非记录有已被其他人更新 我只是在更新后进入数据层 但这不是很有效
  • MVVM-light + RIA 服务最佳实践 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何使 angular.js 路由长路径

    我正在使用 angular js 制作一个文件浏览器 所以 我会处理一些长网址 eg mydomain folder1 sub1 grand sub1 我只是学习 Angular 并发现 Angular 有 routeProvider 但是
  • Android:表没有名为“变量名称”的列 MySql 数据库错误

    当我尝试在数据库中添加新条目时 出现如下所示的错误 我现在已经搜索了几个小时 但无法发现问题所在 任何输入都会很棒 这里是来自 LogCat 的错误 02 27 23 02 51 451 E SQLiteLog 6777 1 table d
  • 如何在 phpstorm 中使用 phalcon-devtools\ide\phpstorm?

    我正在尝试将 Phalcon 开发人员工具与 phpstorm 集成 有一个视频在这里 http docs phalconphp com en 0 5 0 reference tools html integrating tools wit
  • 从 Visual Studio Code 调试 vue-cli 3 生成的应用程序

    我使用 vue cli 3 0 0 rc 3 生成了一个应用程序 现在我想使用 Visual Studio Code Chrome 调试器 对其进行调试 但是我似乎找不到打开 sourceMaps 的选项 我在 VSCode 中设置了断点
  • 单击按钮后重新绘制 JPanel

    我是 Java Swing 的新手 我有一个奇怪的问题需要刷新我的JPanel 我创建一个静态的JPanel我的框架中的组件 我从一个调用静态方法FileListenner重新粉刷我的JPanel public static void re
  • REST Web 服务版本控制实践

    我正在创建一个新的 Web 服务 并且我已经阅读了 APIgee 的一些电子书 其中建议对 Web 服务进行版本控制 我知道在 URL 与标头中保留版本控制信息之间存在一些 斗争 根据我所阅读和理解的内容 我想在标头中使用版本控制 我的问题