欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot如何實(shí)現(xiàn)接口版本控制

 更新時(shí)間:2021年10月13日 09:25:58   作者:Zacxxx  
這篇文章主要介紹了SpringBoot如何實(shí)現(xiàn)接口版本控制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

SpringBoot 接口版本控制

一個(gè)系統(tǒng)在上線后會(huì)不斷迭代更新,需求也會(huì)不斷變化,有可能接口的參數(shù)也會(huì)發(fā)生變化,如果在原有的參數(shù)上直接修改,可能會(huì)影響到現(xiàn)有項(xiàng)目的正常運(yùn)行,這時(shí)我們就需要設(shè)置不同的版本,這樣即使參數(shù)發(fā)生變化,由于老版本沒(méi)有變化,因此不會(huì)影響上線系統(tǒng)的運(yùn)行。

這里我們選擇使用帶有一位小數(shù)的浮點(diǎn)數(shù)作為版本號(hào),在請(qǐng)求地址末尾中帶上版本號(hào),大致的地址如:http://api/test/1.0,其中,1.0即代表的是版本號(hào)。具體做法請(qǐng)看代碼

自定義一個(gè)版本號(hào)的注解接口ApiVersion.java

import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
/**
 * 版本控制
 * @author Zac
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {
    /**
     * 標(biāo)識(shí)版本號(hào)
     * @return
     */
    double value();
}

版本號(hào)篩選器ApiVersionCondition

import org.springframework.web.servlet.mvc.condition.RequestCondition;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern; 
/**
 * 版本號(hào)匹配篩選器
 * @author Zac
 */
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
 
    /**
     * 路徑中版本的正則表達(dá)式匹配, 這里用 /1.0的形式
     */
    private static final Pattern VERSION_PREFIX_PATTERN = Pattern.compile("^\\S+/([1-9][.][0-9])$");
    private double apiVersion;
     public ApiVersionCondition(double apiVersion) {
        this.apiVersion = apiVersion;
    }
 
    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 采用最后定義優(yōu)先原則,則方法上的定義覆蓋類上面的定義
        return new ApiVersionCondition(other.getApiVersion());
    }
 
    @Override public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
         Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
        if (m.find()) {
            Double version = Double.valueOf(m.group(1));
            // 如果請(qǐng)求的版本號(hào)大于配置版本號(hào), 則滿足
            if (version >= this.apiVersion) {
                return this;
            }
        }
        return null;
    }
 
    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        // 優(yōu)先匹配最新的版本號(hào)
        return Double.compare(other.getApiVersion(), this.apiVersion);
    } 
    public double getApiVersion() {
        return apiVersion; 
    }
}

版本號(hào)匹配攔截器

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
 
/**
 * 版本號(hào)匹配攔截器
 * @author Zac
 */
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
     @Override protected RequestCondition<ApiVersionCondition> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
        return createCondition(apiVersion);
    }
 
    @Override protected RequestCondition<ApiVersionCondition> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
        return createCondition(apiVersion);
    } 
    private RequestCondition<ApiVersionCondition> createCondition(ApiVersion apiVersion) {
        return apiVersion == null ? null : new ApiVersionCondition(apiVersion.value());
    }  
}

配置WebMvcRegistrationsConfig

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcRegistrationsAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 
@SpringBootConfiguration
public class WebMvcRegistrationsConfig extends WebMvcRegistrationsAdapter {
 
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new CustomRequestMappingHandlerMapping();
    }  
}
controller層實(shí)現(xiàn)
/**
     * version
     * @return
     */
    @GetMapping("/api/test/{version}")
    @ApiVersion(2.0)
    public String searchTargetImage() {
        return "Hello! Welcome to Version2";
    }  
/**
     * 多目標(biāo)類型搜索,關(guān)聯(lián)圖片查詢接口
     *
     * @param attribute
     * @return
     */
    @GetMapping("/api/test/{version}")
    @ApiVersion(1.0)
    public AppResult searchTargetImage() {
        return "Hello! Welcome to Version1";
    }

SpringBoot 2.x 接口多版本

準(zhǔn)備將現(xiàn)有的接口加上版本管理,兼容以前的版本。網(wǎng)上一調(diào)研,發(fā)現(xiàn)有很多示例,但是還是存在以下兩個(gè)問(wèn)題。

1.大部分使用Integer作為版本號(hào),但是通常的版本號(hào)形式為v1.0.0,

2.版本號(hào)攜帶在header中,對(duì)接調(diào)用不清晰。

針對(duì)以上兩個(gè)問(wèn)題,做如下改造。

1.自定義接口版本注解ApiVersion

后面條件映射使用equals匹配,此處是否將String變?yōu)镾tring[]應(yīng)對(duì)多個(gè)版本使用同一代碼的問(wèn)題。

package com.yugioh.api.common.core.version;
import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
/**
 * 接口版本
 *
 * @author lieber
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {  
    String value() default "1.0.0";
}

2.請(qǐng)求映射條件ApiVersionCondition

package com.yugioh.api.common.core.version;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 版本控制
 *
 * @author lieber
 */
@AllArgsConstructor
@Getter
@Slf4j
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
    private String version;
    private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile(".*v(\\d+(.\\d+){0,2}).*");
    public final static String API_VERSION_CONDITION_NULL_KEY = "API_VERSION_CONDITION_NULL_KEY";
    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 方法上的注解優(yōu)于類上的注解
        return new ApiVersionCondition(other.getVersion());
    }
    @Override
    public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
        Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
        if (m.find()) {
            String version = m.group(1);
            if (this.compareTo(version)) {
                return this;
            }
        }
        // 將錯(cuò)誤放在request中,可以在錯(cuò)誤頁(yè)面明確提示,此處可重構(gòu)為拋出運(yùn)行時(shí)異常
        request.setAttribute(API_VERSION_CONDITION_NULL_KEY, true);
        return null;
    }
    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        return this.compareTo(other.getVersion()) ? 1 : -1;
    }
    private boolean compareTo(String version) {
        return Objects.equals(version, this.version);
    }
}

3.創(chuàng)建自定義匹配處理器ApiVersionRequestMappingHandlerMapping

網(wǎng)上大部分只重寫了getCustomTypeCondition和getCustomMethodCondition方法。這里為了解決路由映射問(wèn)題,重寫getMappingForMethod方法,在路由中加入前綴{version},加入后路由變?yōu)?api/{version}/xxx

package com.yugioh.api.common.core.version;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
/**
 * 自定義匹配處理器
 *
 * @author lieber
 */
public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    private final static String VERSION_PREFIX = "{version}";
    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
        return createCondition(apiVersion);
    }
    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
        return createCondition(apiVersion);
    }
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo requestMappingInfo = super.getMappingForMethod(method, handlerType);
        if (requestMappingInfo == null) {
            return null;
        }
        return createCustomRequestMappingInfo(method, handlerType, requestMappingInfo);
    }
    private RequestMappingInfo createCustomRequestMappingInfo(Method method, Class<?> handlerType, RequestMappingInfo requestMappingInfo) {
        ApiVersion methodApi = AnnotatedElementUtils.findMergedAnnotation(method, ApiVersion.class);
        ApiVersion handlerApi = AnnotatedElementUtils.findMergedAnnotation(handlerType, ApiVersion.class);
        if (methodApi != null || handlerApi != null) {
            return RequestMappingInfo.paths(VERSION_PREFIX).options(this.config).build().combine(requestMappingInfo);
        }
        return requestMappingInfo;
    }
    private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();
    private RequestCondition<ApiVersionCondition> createCondition(ApiVersion apiVersion) {
        return apiVersion == null ? null : new ApiVersionCondition(apiVersion.value());
    }
}

4.使用ApiVersionConfig配置來(lái)決定是否開(kāi)啟多版本

package com.yugioh.api.common.core.version;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
 * 版本管理器配置
 *
 * @author lieber
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "api.config.version", ignoreInvalidFields = true)
public class ApiVersionConfig {
    /**
     * 是否開(kāi)啟
     */
    private boolean enable;
}

5.配置WebMvcRegistrations,啟用自定義路由Mapping

package com.yugioh.api.common.core.version;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
 * @author lieber
 */
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ApiWebMvcRegistrations implements WebMvcRegistrations {
    private final ApiVersionConfig apiVersionConfig;
    @Autowired
    public ApiWebMvcRegistrations(ApiVersionConfig apiVersionConfig) {
        this.apiVersionConfig = apiVersionConfig;
    }
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        if (apiVersionConfig.isEnable()) {
            return new ApiVersionRequestMappingHandlerMapping();
        }
        return null;
    }
}

至此我們就能在項(xiàng)目中愉快的使用@APIVersion來(lái)指定版本了,但是現(xiàn)在這個(gè)和swagger整合還會(huì)有問(wèn)題,繼續(xù)研究中…

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java Hutool工具實(shí)現(xiàn)驗(yàn)證碼生成及Excel文件的導(dǎo)入和導(dǎo)出

    Java Hutool工具實(shí)現(xiàn)驗(yàn)證碼生成及Excel文件的導(dǎo)入和導(dǎo)出

    Hutool是一個(gè)小而全的Java工具類庫(kù),通過(guò)靜態(tài)方法封裝,降低相關(guān)API的學(xué)習(xí)成本,提高工作效率,本文主要介紹了使用Hutool工具實(shí)現(xiàn)驗(yàn)證碼生成和excel文件的導(dǎo)入、導(dǎo)出,需要的朋友可參考一下
    2021-11-11
  • Java泛型機(jī)制與反射原理相關(guān)知識(shí)總結(jié)

    Java泛型機(jī)制與反射原理相關(guān)知識(shí)總結(jié)

    今天帶大家學(xué)習(xí)的是關(guān)于Java進(jìn)階的相關(guān)知識(shí),文章圍繞著Java泛型機(jī)制與反射原理展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java面試題沖刺第二十一天--JVM

    Java面試題沖刺第二十一天--JVM

    這篇文章主要為大家分享了最有價(jià)值的三道關(guān)于JVM的面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java字符串拼接的五種方法及性能比較分析(從執(zhí)行100次到90萬(wàn)次)

    Java字符串拼接的五種方法及性能比較分析(從執(zhí)行100次到90萬(wàn)次)

    字符串拼接一般使用“+”,但是“+”不能滿足大批量數(shù)據(jù)的處理,Java中有以下五種方法處理字符串拼接及性能比較分析,感興趣的可以了解一下
    2021-12-12
  • java實(shí)現(xiàn)打印日歷

    java實(shí)現(xiàn)打印日歷

    這篇文章主要為大家詳細(xì)介紹了java打印日歷的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(45)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(45)

    下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你
    2021-07-07
  • Java實(shí)戰(zhàn)之小蜜蜂擴(kuò)音器網(wǎng)上商城系統(tǒng)的實(shí)現(xiàn)

    Java實(shí)戰(zhàn)之小蜜蜂擴(kuò)音器網(wǎng)上商城系統(tǒng)的實(shí)現(xiàn)

    這篇文章主要介紹了如何利用Java實(shí)現(xiàn)簡(jiǎn)單的小蜜蜂擴(kuò)音器網(wǎng)上商城系統(tǒng),文中采用到的技術(shù)有JSP、Servlet?、JDBC、Ajax等,感興趣的可以動(dòng)手試一試
    2022-03-03
  • 一文詳解Java抽象類到底有多抽象

    一文詳解Java抽象類到底有多抽象

    這篇文章主要介紹了一文詳解Java抽象類到底有多抽象,抽象方法所在的類必須是抽象類,子類若繼承了一個(gè)抽象類,就必須覆寫父類的所有抽象方法,這里的子類是普通類,是強(qiáng)制要求覆寫所有抽象方法,但是如果子類也是一個(gè)抽象類,那么就可以不覆寫
    2022-06-06
  • SpringBoot整合Ip2region獲取IP地址和定位的詳細(xì)過(guò)程

    SpringBoot整合Ip2region獲取IP地址和定位的詳細(xì)過(guò)程

    ip2region v2.0 - 是一個(gè)離線IP地址定位庫(kù)和IP定位數(shù)據(jù)管理框架,10微秒級(jí)別的查詢效率,提供了眾多主流編程語(yǔ)言的 xdb 數(shù)據(jù)生成和查詢客戶端實(shí)現(xiàn) ,這篇文章主要介紹了SpringBoot整合Ip2region獲取IP地址和定位,需要的朋友可以參考下
    2023-06-06
  • java?stream實(shí)現(xiàn)分組BigDecimal求和以及自定義分組求和

    java?stream實(shí)現(xiàn)分組BigDecimal求和以及自定義分組求和

    這篇文章主要給大家介紹了關(guān)于java?stream實(shí)現(xiàn)分組BigDecimal求和以及自定義分組求和的相關(guān)資料,Stream是Java8的一大亮點(diǎn),是對(duì)容器對(duì)象功能的增強(qiáng),它專注于對(duì)容器對(duì)象進(jìn)行各種非常便利、高效的聚合操作或者大批量數(shù)據(jù)操作,需要的朋友可以參考下
    2023-12-12

最新評(píng)論