当前位置: 首页 > news >正文

6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口?

第6章 构建 RESTful 服务

6.1 RESTful 简介
6.2 构建 RESTful 应用接口
6.3 使用 Swagger 生成 Web API 文档
6.4 实战:实现 Web API 版本控制
6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口?

6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口?

〇、背景

在上一节 6.4 实战:实现 Web API 版本控制 中,我们实现了 Web API 版本控制,但是有一个问题:我们在原始版本上增加了版本控制之后(假设原始版本没有版本号,现在做版本控制之后,V1对应了原始版本),可以正常访问有版本号的接口,但是却无法访问没有版本号的原始接口。如下:

  • 原始版本(无版本控制)删除订单接口:http://localhost:8080/api/order/delete/20011(无法返回数据)
    原始版本(无版本控制)删除订单接口

  • 原始版本(无版本控制)获取订单详情接口:http://localhost:8080/api/order/detail/20011(无法返回数据)
    原始版本(无版本控制)获取订单详情接口

一、需求

假设原始 Web API 接口没有实现版本控制,那么,如何升级接口才能在实现版本控制的同时,无版本控制的原始接口不受影响。

1、背景
假设 原始接口(无版本控制) 和 升级后的接口(有版本控制) 如下所示。

  • 原始接口(无版本控制):
    api/order/接口名称

  • 升级后的接口(有版本控制):
    api/v1/order/接口名称
    api/v2/order/接口名称

2、核心需求:
(1)升级接口,进行 Web API 版本控制。
(2)原始接口可以正常访问,不受接口升级影响。
(3)原始接口和升级后的V1接口等价(即api/order/接口名称api/v1/order/接口名称等价)。

二、解决方案

Spring Boot 对 RESTful 的支持非常全面,因而实现 RESTful API 非常简单,同样对于 API 版本控制也有相应的实现方案,实现步骤如下:

1、API版本控制配置

(1)创建自定义的 @ApiVersion 注解。

(2)创建自定义 URL 匹配规则 ApiVersionCondition 类(实现 RequestCondition 接口)。

(3)创建自定义的映射处理程序 ApiRequestMappingHandlerMapping 类(继承 RequestMappingHandlerMapping 类)。

(4)创建 WebMvcRegistrationsConfig 配置类(实现 WebMvcRegistrations 接口),将自定义的映射处理程序 ApiRequestMappingHandlerMapping 注册到系统中。

2、配置实现接口

编写测试的控制器,实现相关接口的测试。

假设升级后的接口为V1(版本1)、V2(版本2)。
实现方法:

  • 原始接口:原始接口不需要做任何操作。(保证原始接口不受任何影响)
  • V1接口:V1接口不需要实现任何接口,直接继承原始接口,然后添加版本注解@ApiVersion 和 URL中添加版本标志{version} 实现版本控制即可。(保证原始接口和升级后的V1接口等价)
  • V2接口:V2接口根据业务需求的变化实现相关接口,然后添加版本注解@ApiVersion 和 URL中添加版本标志{version} 实现版本控制。

三、具体实现

1、API版本控制配置

关于 API版本控制配置,可以直接参考上一节 6.4 实战:实现 Web API 版本控制 。

2、配置实现接口

配置完成之后,接下来编写测试的控制器(Controller),实现相关接口的测试。在 Controller 目录下分别创建 OrderV1Controller 和 OrderV2Controller,原始接口控制器 OrderController 不做任何改动。示例代码如下:

OrderController.java

package com.example.restfulproject.controller;import com.example.restfulproject.comm.utils.JSONResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 原始版本的接口定义*/
@RestController
@RequestMapping("/api/order")
public class OrderController {@GetMapping("/delete/{orderId}")public JSONResult deleteOrderById(@PathVariable String orderId) {System.out.println("V1 删除订单成功:" + orderId);return JSONResult.ok("V1 删除订单成功");}@GetMapping("/detail/{orderId}")public JSONResult queryOrderById(@PathVariable String orderId) {System.out.println("V1 获取订单详情成功:" + orderId);return JSONResult.ok("V1 获取订单详情成功");}
}

OrderV1Controller.java

package com.example.restfulproject.controller;import com.example.restfulproject.comm.annotation.ApiVersion;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** V1 版本的接口定义*/
@ApiVersion(value = 1)
@RestController
@RequestMapping("/api/{version}/order")
public class OrderV1Controller extends OrderController {
}

OrderV2Controller.java

package com.example.restfulproject.controller;import com.example.restfulproject.comm.annotation.ApiVersion;
import com.example.restfulproject.comm.utils.JSONResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** V2 版本的接口定义*/
@ApiVersion(value = 2)
@RestController
@RequestMapping("/api/{version}/order")
public class OrderV2Controller {@GetMapping("/detail/{orderId}")public JSONResult queryOrderById(@PathVariable String orderId) {System.out.println("V2 获取订单详情成功:" + orderId);return JSONResult.ok("V2 获取订单详情成功");}@GetMapping("/list")public JSONResult list() {System.out.println("V2 新增list订单列表接口");return JSONResult.ok(200, "V2 新增list订单列表接口");}
}

3、验证测试

启动项目,查看版本控制是否生效。同时检查无版本控制的原始接口是否不受影响。

(1)删除订单接口:

原始接口(无版本控制):http://localhost:8080/api/order/delete/20011
原始版本删除订单接口.png

V1接口(有版本控制):http://localhost:8080/api/v1/order/delete/20011
V1删除订单接口.png

V2接口(有版本控制):http://localhost:8080/api/v2/order/delete/20011
V2删除订单接口.png

(2)获取订单详情接口:

原始接口(无版本控制):http://localhost:8080/api/order/detail/20011
原始版本获取订单详情接口.png

V1接口(有版本控制):http://localhost:8080/api/v1/order/detail/20011
V1获取订单详情接口.png

V2接口(有版本控制):http://localhost:8080/api/v2/order/detail/20011
V2获取订单详情接口.png

(3)新增订单列表接口:

原始接口(无版本控制):http://localhost:8080/api/order/list
原始版本新增订单列表接口
V1接口(有版本控制):http://localhost:8080/api/v1/order/list
V1新增订单列表接口.png

V2接口(有版本控制):http://localhost:8080/api/v2/order/list
V2新增订单列表接口.png

来源:《Spring Boot 从入门到实战》学习笔记

相关文章:

6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口?

第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战:实现 Web API 版本控制 6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口? 6.5 拓展&#…...

Springboot依赖注入Bean的三种方式,final+构造器注入Bean

文章目录Springboot依赖注入Bean的方式一、Field 注入/属性注入二、set注入三、构造器注入Springboot依赖注入Bean的方式 一、Field 注入/属性注入 Autowired注解的一大使用场景就是Field Injection。 Controller public class UserController {Autowiredprivate UserServic…...

【java】Spring Cloud --Spring Cloud Alibaba 微服务解决方案

文章目录1、Spring Cloud Alibaba 是什么先说说 Spring CloudSpring Cloud Alibaba和Spring Cloud 的区别和联系Spring Cloud Alibaba2、Spring Cloud Alibaba 包含组件阿里开源组件阿里商业化组件集成 Spring Cloud 组件3、Spring Cloud Alibaba 功能服务注册与发现支持多协议…...

CSS 6种选择器(超详细)

CSS6大种选择器(超详细) 一、常用的css基本选择器(4种) 1、标签选择器 结构: 标签名{css属性名:属性值} 作用:通过标签名,找到页面中所有的这类标签,设置样式 注意:1.标签选择器选择的是一类标签&#…...

mysql8.0.32-手动配置安装-具体流程步骤

文章目录1.下载mysql压缩编译版2.修改配置文件3.数据库初始化,安装windows服务,启动服务4.修改root密码5.作者答疑1.下载mysql压缩编译版 作者从官方下载:https://download.csdn.net/download/m0_67316550/87485720 2.修改配置文件 修改my…...

【项目】Vue3+TS 退出登录 menu header搭建

💭💭 ✨:【项目】Vue3TS 退出登录 menu header搭建   💟:东非不开森的主页   💜: 今天永远比昨天更好💜💜   🌸: 如有错误或不足之处,希望可以指正&#x…...

LoRaWAN模块在车辆跟踪定位中的应用

目前 GPS已经在资产的管理中得到了越来越多的运用,如车辆跟踪、车队跟踪、资产监控等;人员跟踪,宠物跟踪,等等。在所有追踪装置中,最重要的是它的电池期望和监视距离。鉴于 LoRaWAN的功率消耗很小,而且能在…...

软件测试分类

软件测试分类 从上图我们发现软件测试根据不同的分类条件会有不同的结果. 1. 按照阶段进行划分 1.1 单元测试(Unit Testing) 单元测试是对软件组成单元进行测试。其目的是检验软件基本组成单位的正确性。测试的对象是软件设计的最小单位:模块。 测试阶段&#x…...

外置的媒体查询,对性能又一次的优化提升

通常情况下我们写媒体查询都是写在一个样式文件中,对于浏览器加载的时候,会解析到最后一行样式时才会渲染页面,这样就会造成页面的白屏时间过长。 但是通常情况下大量的媒体查询样式都是无用的,现在浏览器允许我们在引用样式文件…...

【Galois工具开发之路】关于IDEA的gradle工程执行两次premain的bug~

文章目录关于premain方法问题记录解决方式关于premain方法 是Java Agent技术的一种,通过 -javaagent: 的方式,添加外部代理,代理入口方法为 premain 。另一种Java Agent技术则是动态attach到java进程的方式,这种方式则是使用 age…...

云计算 概念与技术

如果我倡导的计算机在未来得到使用,那么有一天,计算也可能像电话一样成为共用设施。计算机应用将成为一全新的、重要的产业的基础。 ——John McCarthy 云计算的概念 定义 Garther公司的定义 一种计算方式,能通过Internet技术将可扩展的和…...

基于追踪标记的WAF设计思路

一 相关背景 目前,市面上的WAF产品通常采用”发现即阻断“的策略,以防护针对业务系统的Web攻击行为。虽然该策略可及时阻断攻击,但形式上过于简单,并不能有效掌握攻击者进一步的攻击意图,也不能有效提高攻击者的成本投…...

Java StringBuffer StringBuilder,超详细整理,适合新手入门

目录 一、StringBuffer和StringBuilder的区别是什么? 二、StringBuffer的示例 三、StringBuilder的示例 四、为什么StringBuffer和StringBuilder比String更适合在循环中使用? 五、如何将String对象转换为StringBuilder或StringBuffer对象&#xff1…...

数据结构—堆(完全解析)

数据结构—堆(完全解析) 数据结构——堆(Heap)大根堆、小根堆 详解数据结构——堆 堆的基本存储 【从堆的定义到优先队列、堆排序】 10分钟看懂必考的数据结构——堆 【堆/排序】堆排序的两种建堆方法 【算法】排序算法之堆排序 C…...

深度卷积对抗神经网络 进阶 第三部分 GANs Unpaired Translation with Cycle GAN 模型

非配对的图像转换应用 Unpaired Image-to-Image Translation Unpaired image-to-image translation 主要用于学习两组图像之间的对应关系,检查和寻找两堆数据中的共同内容(content)以及每堆独有的特点(style)。而这个…...

常见的排序算法 | 直接插入排序 | 希尔排序 | 选择排序 | 堆排序 | 冒泡排序 | 快速排序 | 归并排序 |(详解,附动图,代码)

思维导图: 一.插入排序 1.直接插入排序(InsertSort) ①手机通讯录时时刻刻都是有序的,新增一个电话号码时,就是使用插入排序的方法将其插入原有的有序序列。 ②打扑克 步骤: ①如果一个序列只有一个数&am…...

深入浅出 MySQL 索引(一)

MySQL 索引(基础篇) 你好,我是悟空。 本文目录如下: 一、前言 最近在梳理 MySQL 核心知识,刚好梳理到了 MySQL 索引相关的知识,我的文章风格很多都是原理 实战的方式带你去了解知识点,所以…...

FinClip 的 2022 与 2023

相比往年,今年复盘去年与展望新年的文章来的稍慢一点。不过也希望能够借这篇文章,和关注 FinClip 的用户朋友们一起聊聊,我们在去年和今年的想法与计划。 2022 在过去的一年中,我们的身边发生了很多事情,这些事情在不…...

Python 泛型 - 如何在实例方法中获取泛型参数T的类型?

先上解决方法:https://stackoverflow.com/questions/57706180/generict-base-class-how-to-get-type-of-t-from-within-instance 再来简单分析下源码。 talk is cheap, show me the code. from typing import Dict Dict[str, int]Dict只是一个类型,并不…...

Shell语法基础总结

Shell 变量使用变量只读变量删除变量变量类型Shell 字符串单引号与双引号字符串获取字符串长度提取子字符串拼接字符串Shell 数组定义数组读取数组获取数组的长度Shell 传递参数Shell 基本运算符算术运算符关系运算符布尔运算符逻辑运算符字符串运算符Shell 信息输出命令Shell …...

ZjDroid命令大全:从DEX内存dump到Lua脚本注入的完整教程

ZjDroid命令大全:从DEX内存dump到Lua脚本注入的完整教程 【免费下载链接】ZjDroid Android app dynamic reverse tool based on Xposed framework. 项目地址: https://gitcode.com/gh_mirrors/zj/ZjDroid ZjDroid是一款基于Xposed框架的Android应用动态逆向分…...

亚马逊卖家公开信息数据提取:反爬攻防战与 Python 批量采集实战

摘要: 批量获取亚马逊(Amazon)第三方卖家的商业名称、信用代码和注册地址等信息,对于跨境 B2B 拓客和供应链分析具有重要意义。然而,亚马逊的 Cloudflare 盾和 Robot 验证码构成了极高的反爬门槛。本文将深度解析亚马逊…...

ROS Noetic实战:从bag包里‘抠’出雷达点云和IMU数据的保姆级教程(Ubuntu 20.04)

ROS Noetic实战:从bag包里提取雷达点云和IMU数据的完整指南(Ubuntu 20.04)在机器人开发中,ROS bag文件就像是一个装满珍贵数据的宝箱,而雷达点云和IMU数据则是其中最闪亮的宝石。作为一名长期与ROS打交道的开发者&…...

开源 AI Agent Harness Engineering 框架全览:LangChain, AutoGPT, CrewAI 孰优孰劣?

开源 AI Agent Harness Engineering 框架全览:LangChain, AutoGPT, CrewAI 孰优孰劣? 关键词 AI Agent Harness Engineering、大语言模型编排(LLM Orchestration)、LangChain、AutoGPT、CrewAI、工具调用(Tool Calling)、多Agent协作、自主任务规划 摘要 随着大语言模型…...

Go开发者必备:circuitbreaker API全解析与最佳实践指南 [特殊字符]

Go开发者必备:circuitbreaker API全解析与最佳实践指南 🚀 【免费下载链接】circuitbreaker Circuit Breakers in Go 项目地址: https://gitcode.com/gh_mirrors/circ/circuitbreaker 作为一名Go开发者,你是否经常遇到远程服务调用失败…...

收藏|2026年大模型算法岗崛起!程序员小白入门高薪赛道全攻略

前些年,算法岗位一直稳居技术圈高薪行列,无数程序员争相入局,也成为计算机专业毕业生求职首选方向。 伴随大模型技术飞速迭代落地,行业就业格局迎来重大变革。如今含金量最高、人才缺口最大、长期发展潜力顶尖的岗位,已…...

数字合成器d-FORMANT:从模拟经典到数字复刻的工程实践

1. 项目概述:从模拟经典到数字复刻如果你对合成器稍有了解,或者对电子音乐制作背后的硬件感兴趣,那么“FORMANT”这个名字你一定不陌生。它最初是上世纪70年代由《Elektor》杂志发布的一款模拟单音合成器,以其清晰的模块化设计和出…...

星露谷物语SMAPI模组加载器:从新手到专家的完整使用指南

星露谷物语SMAPI模组加载器:从新手到专家的完整使用指南 【免费下载链接】SMAPI The modding API for Stardew Valley. 项目地址: https://gitcode.com/gh_mirrors/smap/SMAPI 星露谷物语SMAPI模组加载器是官方推荐的模组API,它为玩家和开发者提供…...

终极指南:5分钟搞定淘宝淘金币全任务自动化脚本

终极指南:5分钟搞定淘宝淘金币全任务自动化脚本 【免费下载链接】taojinbi 淘宝淘金币自动执行脚本,包含蚂蚁森林收取能量,芭芭农场全任务,解放你的双手 项目地址: https://gitcode.com/gh_mirrors/ta/taojinbi 你是否厌倦…...

告别手动映射!用AD域控组策略批量给员工电脑挂载共享盘(Windows Server 2016实战)

企业级共享存储自动化部署指南:基于AD域控的组策略实战每当新员工入职或部门调整时,IT管理员最头疼的莫过于重复配置几十台电脑的共享盘映射。财务部需要访问M盘的报表目录,市场部要连接N盘的设计素材,而手动设置不仅效率低下&…...