自定義注解實(shí)現(xiàn)Restful接口版本管理

??在我們的日常開(kāi)發(fā)中肋联,需求總是變化的锈麸。對(duì)于某個(gè)接口,隨著需求的升級(jí)牺蹄,也面臨里面邏輯的變化忘伞。例如,對(duì)于/v1/hello,/v2/hello 兩個(gè)請(qǐng)求沙兰,若存在相應(yīng)的映射氓奈,則對(duì)應(yīng)入座。否則都映射到最新的接口上鼎天。則映射到最新的接口上舀奶。此時(shí),我們又想保持以前的接口還保留斋射,那么我們此時(shí)需要做的事育勺,把對(duì)接口的請(qǐng)求都映射到最新的接口上,而原來(lái)的接口請(qǐng)求還是映射原來(lái)的接口上罗岖。我在這里介紹用自定義注解的形式涧至,在@RequestMapping()的映射原理上做文章。
  1. 自定義注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {
    int value();
}

??就是定義一個(gè)簡(jiǎn)單的注解@ApiVersion桑包,這個(gè)注解可以在類上和方法上都可以應(yīng)用南蓬。

  1. 注解的識(shí)別
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

    @Override   // ①
    protected RequestCondition<ApiVesrsionCondition> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
        return createCondition(apiVersion);
    }

    @Override  //②
    protected RequestCondition<ApiVesrsionCondition> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
        return createCondition(apiVersion);
    }
    //③  實(shí)例化RequestCondition
    private RequestCondition<ApiVesrsionCondition> createCondition(ApiVersion apiVersion) {
        return apiVersion == null ? null : new ApiVesrsionCondition(apiVersion.value());
    }

}

??我們知道,光定義注解是沒(méi)什么用的哑了,重要的是我們識(shí)別到注解赘方,做相應(yīng)的事。RequestMappingHandlerMapping類是與 @RequestMapping相關(guān)的弱左,它定義映射的規(guī)則窄陡。即滿足怎樣的條件則映射到那個(gè)接口上。

??①處構(gòu)建類級(jí)的映射要求拆火,AnnotationUtils.findAnnotation根據(jù)在類上面的注解實(shí)例化一個(gè)注解類跳夭。然后構(gòu)造RequestCondition鳖悠。

??②處構(gòu)建類級(jí)的映射要求,AnnotationUtils.findAnnotation根據(jù)在方法上面的注解實(shí)例化一個(gè)注解類优妙。然后構(gòu)造RequestCondition乘综。
AnnotationUtils.findAnnotation是用到Spring的工具類,根據(jù)標(biāo)注的注解識(shí)別注解套硼。很方便卡辰,比通過(guò)反射的方式來(lái)找到注解要方便。

  1. 自定義條件類
public class ApiVesrsionCondition implements RequestCondition<ApiVesrsionCondition> {
    // 路徑中版本的前綴邪意, 這里用 /v[1-9]/的形式
    private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");

    private int apiVersion;

    public ApiVesrsionCondition(int apiVersion){
        this.apiVersion = apiVersion;
    }
    //將不同的篩選條件合并,這里采用的覆蓋九妈,即后來(lái)的規(guī)則生效
    public ApiVesrsionCondition combine(ApiVesrsionCondition other) {
        return new ApiVesrsionCondition(other.getApiVersion());
    }
    //根據(jù)request查找匹配到的篩選條件
    public ApiVesrsionCondition getMatchingCondition(HttpServletRequest request) {
        System.out.println(request.getRequestURI());
        Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
        if(m.find()){
            Integer version = Integer.valueOf(m.group(1));
            if(version >= this.apiVersion) // 如果請(qǐng)求的版本號(hào)大于配置版本號(hào), 則滿足雾鬼,即與請(qǐng)求的
                return this;
        }
        return null;
    }
    //實(shí)現(xiàn)不同條件類的比較萌朱,從而實(shí)現(xiàn)優(yōu)先級(jí)排序
    public int compareTo(ApiVesrsionCondition other, HttpServletRequest request) {

        return other.getApiVersion() - this.apiVersion;
    }

    public int getApiVersion() {
        return apiVersion;
    }
}

??getMatchingCondition()利用正則表達(dá)式把請(qǐng)求路徑中的/v1/hello中的1(版本號(hào))找出來(lái),然后返回與大于等于1的條件類策菜。那么@RequestMapping則路由到產(chǎn)生該條件類的方法下晶疼。

  1. 測(cè)試
@RequestMapping("/{version}/")
@Controller
public class VersionController {
    @RequestMapping("hello")
    @ApiVersion(1)
    @ResponseBody
    public String hello(){
        System.out.println("haha1..........");

        return "hello version1";
    }

    @RequestMapping("hello")
    @ApiVersion(2)
    @ResponseBody
    public String hello2(){
        System.out.println("haha2.........");

        return "hello version2";
    }

    @RequestMapping("hello")
    @ResponseBody
    @ApiVersion(5)
    public String hello5(){
        System.out.println("haha5.........");
        return "hello version5";
    }

    @RequestMapping("test")
    @ResponseBody
    public String test(){
        return "test";
    }

}

??每個(gè)方法上都用 @ApiVersion()注解啦。當(dāng)在瀏覽器輸入http://localhost:8761/v2/hello 則跳到hello2()方法中執(zhí)行又憨。當(dāng)在瀏覽器輸入http://localhost:8761/v5/hello 則跳到hello5()中執(zhí)行翠霍,因?yàn)楸?大的都調(diào)到最新hello5()執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蠢莺,一起剝皮案震驚了整個(gè)濱河市寒匙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌躏将,老刑警劉巖锄弱,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異祸憋,居然都是意外死亡会宪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門夺衍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)狈谊,“玉大人,你說(shuō)我怎么就攤上這事沟沙。” “怎么了壁榕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵矛紫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我牌里,道長(zhǎng)颊咬,這世上最難降的妖魔是什么务甥? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮喳篇,結(jié)果婚禮上敞临,老公的妹妹穿的比我還像新娘。我一直安慰自己麸澜,他們只是感情好挺尿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著炊邦,像睡著了一般编矾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馁害,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天窄俏,我揣著相機(jī)與錄音,去河邊找鬼碘菜。 笑死凹蜈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的忍啸。 我是一名探鬼主播踪区,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吊骤!你這毒婦竟也來(lái)了缎岗?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤白粉,失蹤者是張志新(化名)和其女友劉穎传泊,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鸭巴,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡眷细,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鹃祖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溪椎。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恬口,靈堂內(nèi)的尸體忽然破棺而出校读,到底是詐尸還是另有隱情,我是刑警寧澤祖能,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布歉秫,位于F島的核電站,受9級(jí)特大地震影響养铸,放射性物質(zhì)發(fā)生泄漏雁芙。R本人自食惡果不足惜轧膘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兔甘。 院中可真熱鬧谎碍,春花似錦、人聲如沸洞焙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)闽晦。三九已至扳碍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仙蛉,已是汗流浹背笋敞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荠瘪,地道東北人夯巷。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像哀墓,于是被迫代替她去往敵國(guó)和親趁餐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理篮绰,服務(wù)發(fā)現(xiàn)后雷,斷路器,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,823評(píng)論 6 342
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評(píng)論 25 707
  • Spring的模型-視圖-控制器(MVC)框架是圍繞一個(gè)DispatcherServlet來(lái)設(shè)計(jì)的吠各,這個(gè)Servl...
    alexpdh閱讀 2,647評(píng)論 0 3
  • 湖光山色瑞士游(伯爾尼臀突、洛桑、蒙特勒) 酒店的早餐依然很簡(jiǎn)單贾漏,雖然沒(méi)有國(guó)內(nèi)酒店的早餐豐富候学,但是老公兒子早已很習(xí)慣...
    含月6666閱讀 416評(píng)論 0 0