日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

SpringBoot實(shí)現(xiàn)API接口多版本支持的示例代碼

瀏覽:146日期:2023-04-14 10:10:42

一、簡(jiǎn)介

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

二、代碼實(shí)現(xiàn)

本文的代碼實(shí)現(xiàn)基于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值默認(rèn)為1.0.0

EnableApiVersion

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

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

2.將版本號(hào)抽象為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; }}

為了比較版本號(hào)的大小,實(shí)現(xiàn)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提供靜態(tài)方法將字符創(chuàng)轉(zhuǎn)為ApiItem。

常量類,定義請(qǐng)求頭及默認(rèn)版本號(hào)

public class ApiVersionConstant { /** * header 指定版本號(hào)請(qǐng)求頭 */ public static final String API_VERSION = 'x-api-version'; /** * 默認(rèn)版本號(hào) */ public static final String DEFAULT_VERSION = '1.0.0';}

3.核心ApiCondition 新建ApiCondition類,實(shí)現(xiàn)RequestCondition,重寫combine、getMatchingCondition、compareTo方法。

RequestCondition

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

以上對(duì)RequestCondition簡(jiǎn)要說(shuō)明,后續(xù)詳細(xì)源碼分析各個(gè)方法的作用。

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先掃描方法再掃描類,然后調(diào)用{@link #combine} * 按照方法上的注解優(yōu)先級(jí)大于類上注解的原則處理,但是要注意如果方法上不定義注解的情況。 * 如果方法或者類上不定義注解,我們會(huì)給一個(gè)默認(rèn)的值{@code empty},{@link ApiHandlerMapping} * </pre> * @param other 方法掃描封裝結(jié)果 * @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); // 獲取所有小于等于版本的接口;如果前端不指定版本號(hào),則默認(rèn)請(qǐng)求1.0.0版本的接口 if (StringUtils.isBlank(version)) { log.warn('未指定版本,使用默認(rèn)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]錯(cuò)誤,最低版本[%s]', version, ApiVersionConstant.DEFAULT_VERSION)); } if (item.compareTo(this.version) >= 0) { return this; } return null; } @Override public int compareTo(ApiCondition other, HttpServletRequest request) { // 獲取到多個(gè)符合條件的接口后,會(huì)按照這個(gè)排序,然后get(0)獲取最大版本對(duì)應(yīng)的接口.自定義條件會(huì)最后比較 int compare = other.version.compareTo(this.version); if (compare == 0) { log.warn('RequestMappingInfo相同,請(qǐng)檢查!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自動(dòng)注入,而是使用Import帶入,目的是可以在程序中選擇性啟用或者不啟用版本控制。

總結(jié)

到此這篇關(guān)于SpringBoot實(shí)現(xiàn)API接口多版本支持的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot API多版本支持內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Spring
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲精品一区二区在线看| 狠狠爱www人成狠狠爱综合网| 中国女人久久久| 亚洲在线一区| 日韩高清在线不卡| 国产精品久久久久久久久久齐齐 | 亚洲伦乱视频| 国产91精品对白在线播放| 99热精品在线观看| 亚洲资源网站| 欧美黄色一区| 欧美成人国产| 日韩av成人高清| 精品午夜视频| 欧美精品一二| 日本免费在线视频不卡一不卡二| 麻豆一区二区三| 欧美不卡高清| 日韩av在线播放中文字幕| 免费亚洲婷婷| 日韩国产网站| 亚洲一区二区小说| 精品国产一区二区三区av片| 欧美91福利在线观看| 青青草91视频| 日韩精品一区二区三区免费观影 | 婷婷亚洲成人| 黄色在线网站噜噜噜| 在线视频亚洲| 久久亚洲人体| 美女网站久久| 青青青国产精品| 99久久精品费精品国产| 91嫩草精品| 欧美日中文字幕| 国产精品igao视频网网址不卡日韩| 国产一区欧美| 久久精品伊人| 视频一区在线播放| 精品成人18| 日韩综合一区二区三区| 丝袜美腿诱惑一区二区三区| 日本h片久久| 天堂网在线观看国产精品| 国产精品美女午夜爽爽| 91久久中文| 里番精品3d一二三区| 亚洲精品观看| 91精品成人| 日韩电影免费网站| 国产精品网址| 亚洲天堂日韩在线| 五月综合激情| 欧洲一区二区三区精品| 国产美女精品视频免费播放软件| 亚洲激情二区| 欧美精品日日操| 久久精品国产成人一区二区三区| 日韩一区二区三区在线看| 99久久亚洲精品蜜臀| 久久精品国产亚洲一区二区三区| 精品中文字幕一区二区三区av| 麻豆国产精品| 欧美精品中文| 日本一区中文字幕| 亚洲一区二区三区四区电影| 尤物精品在线| 久久国产毛片| 韩国久久久久久| 麻豆一区二区99久久久久| 日韩精品第一| 日韩中文av| 日本一区福利在线| 免费在线看一区| 欧美特黄一级| 国产高清久久| 国产精品久久久久蜜臀| 麻豆成人综合网| 欧美黄色一区| 精品一级视频| 国产一区丝袜| 麻豆精品视频在线| 国产精品白丝av嫩草影院| 视频一区日韩精品| 视频一区二区三区在线| 欧美一级专区| 久久精品不卡| 亚洲精品99| 在线亚洲欧美| 免费成人av在线播放| av成人国产| 五月婷婷亚洲| 麻豆久久精品| 日本亚洲欧美天堂免费| 蜜桃视频免费观看一区| 在线视频免费在线观看一区二区| 黄色免费成人| 一级成人国产| 青青草视频一区| 欧美极品中文字幕| 亚洲精品**中文毛片| 午夜久久中文| 免费久久久久久久久| 性色一区二区| 日本午夜精品视频在线观看| 欧美日韩调教| 久久精品凹凸全集| 国产人成精品一区二区三| 国产精品videossex久久发布 | 日韩va亚洲va欧美va久久| 久久精品99国产精品日本| 国产日产精品_国产精品毛片| 国产精品久久亚洲不卡| 国产一区二区三区网| 免费观看亚洲| 91久久中文| 日韩成人一级| 国产一区二区三区亚洲| 亚洲无线一线二线三线区别av| 国产亚洲福利| 国产麻豆一区二区三区精品视频| 久久精品亚洲| 91精品一区二区三区综合| 中文一区在线| 国产精品亚洲片在线播放| 在线手机中文字幕| 一区久久精品| 国产剧情一区二区在线观看| 国产乱码午夜在线视频| 久久网站免费观看| 日韩毛片一区| 韩国三级一区| 日韩va欧美va亚洲va久久| 国产第一亚洲| 国产亚洲精品v| 国产精品久久久网站| 另类中文字幕国产精品| 一区二区三区四区在线观看国产日韩| 国产精品久久久久久久久久齐齐 | 91精品麻豆| 色一区二区三区| 亚洲精品女人| 人人草在线视频| 日韩欧乱色一区二区三区在线| 国产一区二区亚洲| 日韩中文字幕麻豆| 国产精品99一区二区三区| 亚洲综合日本| 精品美女久久| 亚洲精品人人| 欧美福利在线| 不卡专区在线| 欧美日韩91| 久久九九电影| 久久伊人国产| 91在线成人| 午夜精品婷婷| 精品一区91| 亚洲三级av| 午夜久久99| 日本免费久久| 欧美精品成人| 亚洲欧洲日韩精品在线| 神马日本精品| 麻豆久久久久久久| 午夜性色一区二区三区免费视频| 99精品一区| 国产精品99视频| 视频精品一区| 亚洲欧美网站| 欧美一区二区三区高清视频| 欧美经典一区| 日韩和欧美的一区| 亚洲一区二区三区四区五区午夜| zzzwww在线看片免费| 国产欧美精品久久| 麻豆成人在线| 91国语精品自产拍| 色吊丝一区二区| 国内精品麻豆美女在线播放视频| 日韩欧美三区| 亚洲精品美女91| 免费在线观看视频一区| 久久影视一区| 91看片一区| 国产a久久精品一区二区三区| 欧美日韩午夜电影网| 亚洲精品第一| 亚洲精品在线国产| 婷婷精品在线| 四虎在线精品| 亚洲精品动态| 亚洲毛片网站| 亚洲+小说+欧美+激情+另类| 日韩一区欧美二区| 免费一区二区视频| 亚洲精品护士| 日韩欧美精品一区二区综合视频| 国产精品日本欧美一区二区三区| 国内精品99|