亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

更多QQ空间微信QQ好友腾讯朋友复制链接
您的位置:首頁/技術文章
文章詳情頁

SpringBoot實現API接口多版本支持的示例代碼

【字号: 作者:豬豬瀏覽:66日期:2023-04-14 10:10:42

一、簡介

產品迭代過程中,同一個接口可能同時存在多個版本,不同版本的接口URL、參數相同,可能就是內部邏輯不同。尤其是在同一接口需要同時支持舊版本和新版本的情況下,比如APP發布新版本了,有的用戶可能不選擇升級,這是后接口的版本管理就十分必要了,根據APP的版本就可以提供不同版本的接口。

二、代碼實現

本文的代碼實現基于SpringBoot 2.3.4-release

1.定義注解

ApiVersion

@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ApiVersion { /** * 版本。x.y.z格式 * * @return */ String value() default '1.0.0';}

value值默認為1.0.0

EnableApiVersion

/** * 是否開啟API版本控制 */@Target(ElementType.TYPE)@Documented@Retention(RetentionPolicy.RUNTIME)@Import(ApiAutoConfiguration.class)public @interface EnableApiVersion {}

在啟動類上添加這個注解后就可以開啟接口的多版本支持。使用Import引入配置ApiAutoConfiguration。

2.將版本號抽象為ApiItem類

ApiItem

@Datapublic class ApiItem implements Comparable<ApiItem> { private int high = 1; private int mid = 0; private int low = 0; public static final ApiItem API_ITEM_DEFAULT = ApiConverter.convert(ApiVersionConstant.DEFAULT_VERSION); public ApiItem() { } @Override public int compareTo(ApiItem right) { if (this.getHigh() > right.getHigh()) { return 1; } else if (this.getHigh() < right.getHigh()) { return -1; } if (this.getMid() > right.getMid()) { return 1; } else if (this.getMid() < right.getMid()) { return -1; } if (this.getLow() > right.getLow()) { return 1; } else if (this.getLow() < right.getLow()) { return -1; }return 0; }}

為了比較版本號的大小,實現Comparable接口并重寫compareTo(),從高位到低位依次比較。

ApiConverter

public class ApiConverter { public static ApiItem convert(String api) { ApiItem apiItem = new ApiItem(); if (StringUtils.isBlank(api)) { return apiItem; } String[] cells = StringUtils.split(api, '.'); apiItem.setHigh(Integer.parseInt(cells[0])); if (cells.length > 1) { apiItem.setMid(Integer.parseInt(cells[1])); } if (cells.length > 2) { apiItem.setLow(Integer.parseInt(cells[2])); }return apiItem; }}

ApiConverter提供靜態方法將字符創轉為ApiItem。

常量類,定義請求頭及默認版本號

public class ApiVersionConstant { /** * header 指定版本號請求頭 */ public static final String API_VERSION = 'x-api-version'; /** * 默認版本號 */ public static final String DEFAULT_VERSION = '1.0.0';}

3.核心ApiCondition 新建ApiCondition類,實現RequestCondition,重寫combine、getMatchingCondition、compareTo方法。

RequestCondition

public interface RequestCondition<T> { /** * 方法和類上都存在相同的條件時的處理方法 */ T combine(T other); /** * 判斷是否符合當前請求,返回null表示不符合 */ @Nullable T getMatchingCondition(HttpServletRequest request); /** *如果存在多個符合條件的接口,則會根據這個來排序,然后用集合的第一個元素來處理 */ int compareTo(T other, HttpServletRequest request);

以上對RequestCondition簡要說明,后續詳細源碼分析各個方法的作用。

ApiCondition

@Slf4jpublic class ApiCondition implements RequestCondition<ApiCondition> { public static ApiCondition empty = new ApiCondition(ApiConverter.convert(ApiVersionConstant.DEFAULT_VERSION)); private ApiItem version; private boolean NULL; public ApiCondition(ApiItem item) { this.version = item; } public ApiCondition(ApiItem item, boolean NULL) { this.version = item; this.NULL = NULL; } /** * <pre> * Spring先掃描方法再掃描類,然后調用{@link #combine} * 按照方法上的注解優先級大于類上注解的原則處理,但是要注意如果方法上不定義注解的情況。 * 如果方法或者類上不定義注解,我們會給一個默認的值{@code empty},{@link ApiHandlerMapping} * </pre> * @param other 方法掃描封裝結果 * @return */ @Override public ApiCondition combine(ApiCondition other) { // 選擇版本最大的接口 if (other.NULL) { return this; } return other; } @Override public ApiCondition getMatchingCondition(HttpServletRequest request) { if (CorsUtils.isPreFlightRequest(request)) { return empty; } String version = request.getHeader(ApiVersionConstant.API_VERSION); // 獲取所有小于等于版本的接口;如果前端不指定版本號,則默認請求1.0.0版本的接口 if (StringUtils.isBlank(version)) { log.warn('未指定版本,使用默認1.0.0版本。'); version = ApiVersionConstant.DEFAULT_VERSION; } ApiItem item = ApiConverter.convert(version); if (item.compareTo(ApiItem.API_ITEM_DEFAULT) < 0) { throw new IllegalArgumentException(String.format('API版本[%s]錯誤,最低版本[%s]', version, ApiVersionConstant.DEFAULT_VERSION)); } if (item.compareTo(this.version) >= 0) { return this; } return null; } @Override public int compareTo(ApiCondition other, HttpServletRequest request) { // 獲取到多個符合條件的接口后,會按照這個排序,然后get(0)獲取最大版本對應的接口.自定義條件會最后比較 int compare = other.version.compareTo(this.version); if (compare == 0) { log.warn('RequestMappingInfo相同,請檢查!version:{}', other.version); } return compare; }}

3.配置類注入容器

ApiHandlerMapping

public class ApiHandlerMapping extends RequestMappingHandlerMapping { @Override protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) { return buildFrom(AnnotationUtils.findAnnotation(handlerType, ApiVersion.class)); } @Override protected RequestCondition<?> getCustomMethodCondition(Method method) { return buildFrom(AnnotationUtils.findAnnotation(method, ApiVersion.class)); } private ApiCondition buildFrom(ApiVersion platform) { return platform == null ? getDefaultCondition() :new ApiCondition(ApiConverter.convert(platform.value())); } private ApiCondition getDefaultCondition(){ return new ApiCondition(ApiConverter.convert(ApiVersionConstant.DEFAULT_VERSION),true); }}ApiAutoConfigurationpublic class ApiAutoConfiguration implements WebMvcRegistrations { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return new ApiHandlerMapping(); }}

ApiAutoConfiguration沒有使用Configuration自動注入,而是使用Import帶入,目的是可以在程序中選擇性啟用或者不啟用版本控制。

總結

到此這篇關于SpringBoot實現API接口多版本支持的示例代碼的文章就介紹到這了,更多相關SpringBoot API多版本支持內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
主站蜘蛛池模板: 一级一级特黄女人精品毛片视频 | 黄色片网站日本 | 欧美高清免费精品国产自 | 国产亚洲美女精品久久久久 | 国产视频成人 | 香港黄页亚洲一级 | 中国一级特黄 | 老汉tv永久视频福利在线观看 | 亚洲精品色一区二区三区 | 国产成人综合网亚洲欧美在线 | 69欧美xxxxx色护士视频 | 亚洲欧美另类精品久久久 | 欧美日韩视频一区二区三区 | 香港三级做爰大爽视频 | 亚洲午夜视频在线观看 | 大学生一级特黄的免费大片视频 | 亚洲欧美日韩另类在线 | 激情亚洲综合网 | 亚洲黄色片免费看 | 香蕉乱码成人久久天堂爱免费 | 一级片特黄| 国内精品91 | 日本制服丝袜在线 | 女人一级片 | 免费高清观看青青草原 | 在线看片免费 | 薰衣草视频高清在线观看免费 | 成人啪啪| 精品国产一区二区三区在线 | 性色网址| 日韩欧美中字 | 亚洲婷婷综合中文字幕第一页 | 国产精品视频在线播放 | 国产福利91精品一区二区三区 | 午夜在线视频国产 | 黄色国产视频 | 大学生高清一级毛片免费 | 国产日韩视频在线 | 亚洲精品国产福利片 | 国产成人91青青草原精品 | 国产亚洲精品久久久久久牛牛 |