最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot實現(xiàn)API接口的完整代碼

 更新時間:2020年10月25日 14:54:40   作者:Atomic  
這篇文章主要給大家介紹了關于SpringBoot實現(xiàn)API接口的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、簡介

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

二、代碼實現(xiàn)

本文的代碼實現(xiàn)基于SpringBoot 2.3.4-release

1.定義注解

ApiVersion

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @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

@Data
public 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;
  }

}

為了比較版本號的大小,實現(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)轉為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類,實現(xiàn)RequestCondition,重寫combine、getMatchingCondition、compareTo方法。

RequestCondition

public interface RequestCondition<T> {

 /**
 * 方法和類上都存在相同的條件時的處理方法
 */
 T combine(T other);

 /**
 * 判斷是否符合當前請求,返回null表示不符合
 */
 @Nullable
 T getMatchingCondition(HttpServletRequest request);

 /**
 *如果存在多個符合條件的接口,則會根據(jù)這個來排序,然后用集合的第一個元素來處理
 */
 int compareTo(T other, HttpServletRequest request);

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

ApiCondition

@Slf4j
public 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)先級大于類上注解的原則處理,但是要注意如果方法上不定義注解的情況。
   *   如果方法或者類上不定義注解,我們會給一個默認的值{@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);
  }
}

ApiAutoConfiguration

public class ApiAutoConfiguration implements WebMvcRegistrations {

  @Override
  public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
    return new ApiHandlerMapping();
  }

}

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

三、原理解析

四、總結

到此這篇關于SpringBoot實現(xiàn)API接口的文章就介紹到這了,更多相關SpringBoot實現(xiàn)API接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java JVM調(diào)優(yōu)五大技能詳解

    Java JVM調(diào)優(yōu)五大技能詳解

    這篇文章主要為大家介紹了JVM調(diào)優(yōu)的五大技能,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • Java Swagger技術使用指南

    Java Swagger技術使用指南

    Swagger 是一個規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化 RESTful 風格的 Web 服務??傮w目標是使客戶端和文件系統(tǒng)作為服務器以同樣的速度來更新。文件的方法,參數(shù)和模型緊密集成到服務器端的代碼,允許API來始終保持同步
    2021-09-09
  • Java 創(chuàng)建URL的常見問題及解決方案

    Java 創(chuàng)建URL的常見問題及解決方案

    這篇文章主要介紹了Java 創(chuàng)建URL的常見問題及解決方案的相關資料,需要的朋友可以參考下
    2016-10-10
  • 多線程下嵌套異步任務導致程序假死問題

    多線程下嵌套異步任務導致程序假死問題

    這篇文章主要介紹了多線程下嵌套異步任務導致程序假死問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • SpringBoot應用啟動慢的原因分析及優(yōu)化方法

    SpringBoot應用啟動慢的原因分析及優(yōu)化方法

    在使用Spring Boot進行開發(fā)時,快速啟動應用程序是一個非常重要的需求,然而,在某些情況下,我們會遇到Spring Boot應用啟動緩慢的問題,本文將分析Spring Boot應用啟動慢的常見原因,并提供一些優(yōu)化方法,需要的朋友可以參考下
    2024-08-08
  • Win10系統(tǒng)下配置java環(huán)境變量的全過程

    Win10系統(tǒng)下配置java環(huán)境變量的全過程

    這篇文章主要給大家介紹了關于Win10系統(tǒng)下配置java環(huán)境變量的相關資料,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • RestTemplate發(fā)送form-data請求上傳rul資源文件及對象參數(shù)方式

    RestTemplate發(fā)送form-data請求上傳rul資源文件及對象參數(shù)方式

    這篇文章主要介紹了RestTemplate發(fā)送form-data請求上傳rul資源文件及對象參數(shù)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java中字符串截取方法詳解及實際應用小結

    Java中字符串截取方法詳解及實際應用小結

    java中截取字符串的常用方法是使用String類的substring方法,本文通過實例代碼給大家介紹Java中字符串截取方法詳解及實際應用小結,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • SpringBoot啟用GZIP壓縮的代碼工程

    SpringBoot啟用GZIP壓縮的代碼工程

    經(jīng)常我們都會與服務端進行大數(shù)據(jù)量的文本傳輸,例如?JSON?就是常見的一種格式,通過?REST?API?接口進行?GET?和?POST?請求,可能會有大量的文本格式數(shù)據(jù)提交、返回,壓縮和解壓在提升網(wǎng)絡帶寬的同時,會帶來?CPU?資源的損耗,本文介紹了SpringBoot啟用GZIP壓縮的代碼工程
    2024-08-08
  • Java如何將處理完異常之后的程序能夠從拋出異常的地點向下執(zhí)行?

    Java如何將處理完異常之后的程序能夠從拋出異常的地點向下執(zhí)行?

    今天小編就為大家分享一篇關于Java如何將處理完異常之后的程序能夠從拋出異常的地點向下執(zhí)行?,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04

最新評論

新竹县| 桐柏县| 遂宁市| 乐业县| 平和县| 宜春市| 兴隆县| 确山县| 石河子市| 吉首市| 新密市| 华阴市| 镇康县| 读书| 新巴尔虎左旗| 手机| 延庆县| 美姑县| 滦南县| 五家渠市| 和平区| 晋城| 泸西县| 蒲江县| 淮阳县| 井冈山市| 如东县| 霍城县| 荆门市| 南城县| 海伦市| 万山特区| 内江市| 左权县| 新丰县| 宁安市| 桃园市| 涡阳县| 泸水县| 桐城市| 彭州市|