• spring boot: 设计接口站api的版本号,支持次版本号(spring boot 2.3.2)


    一,为什么接口站的api要使用版本号?

    1,当服务端接口的功能发生改进后,

        客户端如果不更新版本,

       则服务端返回的功能可能不能使用,
       所以在服务端功能升级后,
        客户端也要相应的使用新版的服务端接口
     
     
    2,注意点:不要频繁变更服务端接口站的版本
     
    不管是新增/修改服务端功能,只要app旧版本可以兼容,
    则服务端的版本号无需变动,因为这个版本和git的版本控制不一样,
    它起的作用是比较客户端的哪些版本和服务端的哪些版本能兼容
    只有客户端不能兼容时,才会新增版本号以便区分

    3,版本号需要能向下兼容,

       如果访问一个高的版本不存在时,应该能访问到比它小的离它最近的版本,

       因为如果每个入口或每个功能在有新版本时都要重新写一遍,

       则和把代码复制一份没有两样了,

       这样才可以方便的管理    

    4,版本号可以放到请求头和url中,

         我们采用比较直观的放到url中的形式演示,

         形如: /v1.2/home/page?

    5,说明:生产环境中没发现有必要在次版本号后面再加一级,

               所以有次版本号后已经够用了,

               大家如果认为有必要增加一级的话,可以修改代码中VERSION_PREFIX_PATTERN的正则:

    说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

             对应的源码可以访问这里获取: https://github.com/liuhongdi/

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,演示项目的相关信息

    1,项目地址:

    https://github.com/liuhongdi/apiversion

    2,项目说明:

            我们给接口站的接口增加api的版本号

            支持整数方式(例:v1)和次版本号形式(例:v1.3)

    3,项目结构:如图:

    三,java代码说明

    1,ApiVersion.java

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ApiVersion {
        //版本号的值,从1开始
        String value() default "1";
    }

    用来添加版本号的一个注解

    2,ApiVersionCondition.java

    //实现RequestCondition
    public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
        //api版本号
        private String apiVersion;
        //版本号的格式,如: /v[1-n]/api/test or /v1.5/home/api
        private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("/v((\d+\.\d+)|(\d+))/");
        public ApiVersionCondition(String apiVersion) {
            this.apiVersion = apiVersion;
        }
    
        //将不同的筛选条件进行合并
        @Override
        public ApiVersionCondition combine(ApiVersionCondition other) {
            // 采用最后定义优先原则,则方法上的定义覆盖类上面的定义
            return new ApiVersionCondition(other.getApiVersion());
        }
    
        //版本比对,用于排序
        @Override
        public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
            //优先匹配最新版本号
            return compareTo(other.getApiVersion(),this.apiVersion)?1:-1;
        }
    
        //获得符合匹配条件的ApiVersionCondition
        @Override
        public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
            Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
            if (m.find()) {
                String version = m.group(1);
                if (compareTo(version,this.apiVersion)){
                    return this;
                }
            }
            return null;
        }
        //compare version
        private boolean compareTo(String version1,String version2){
            if (!version1.contains(".")) {
                version1 += ".0";
            }
            if (!version2.contains(".")) {
                version2 += ".0";
            }
            String[] split1 = version1.split("\.");
            String[] split2 = version2.split("\.");
            for (int i = 0; i < split1.length; i++) {
                if (Integer.parseInt(split1[i])<Integer.parseInt(split2[i])){
                    return false;
                }
            }
            return true;
        }
    
        public String getApiVersion() {
            return apiVersion;
        }
    }

    实现查找和比较版本号的功能

    3,ApiVersionRequestMappingHandlerMapping.java

    //扩展RequestMappingHandlerMapping
    public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    
        //类上有 @ApiVersion注解时生效
        @Override
        protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
            ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
            return createRequestCondition(apiVersion);
        }
    
        //方法上有 @ApiVersion注解时生效
        @Override
        protected RequestCondition<?> getCustomMethodCondition(Method method) {
            ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
            return createRequestCondition(apiVersion);
        }
        
        //返回ApiVersionCondition
        private RequestCondition<ApiVersionCondition> createRequestCondition(ApiVersion apiVersion) {
            return apiVersion == null ? null : new ApiVersionCondition(apiVersion.value());
        }
    }

    继承RequestMappingHandlerMapping,在类上和方法上有注解时,

    使用ApiVersionCondition进行处理

    4,WebMvcConfig.java

    @Configuration
    public class WebMvcConfig extends WebMvcConfigurationSupport {
        //在获取RequestMappingHandlerMapping时
        //返回我们自定义的ApiVersionRequestMappingHandlerMapping
        @Override
        protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
            return new ApiVersionRequestMappingHandlerMapping();
        }
    }

    把createRequestMappingHandlerMapping方法返回时使用我们自定义的ApiVersionRequestMappingHandlerMapping

    5,HomeController.java

    @RestController
    @RequestMapping("/{version}/home")
    public class HomeController {
    
        //匹配版本v1的访问
        @ApiVersion("1")
        @GetMapping
        @RequestMapping("/home")
        public String home01(@PathVariable String version) {
            return "home v1 : version:" + version;
        }
    
        //匹配版本v2的访问
        @ApiVersion("2.0")
        @GetMapping
        @RequestMapping("/home")
        public String home02(@PathVariable String version) {
            return "home v2 version: " + version;
        }
    
        //匹配版本v1.5-2.0的访问
        @ApiVersion("1.5")
        @GetMapping
        @RequestMapping("/home")
        public String home15(@PathVariable String version) {
            return "home v1.5 version: " + version;
        }
    }

    6,GoodsV1Controller和GoodsV2Controller

      把版本号加到controller上,

      和加在方法上的使用一样,

      为节省篇幅,不再贴代码,大家可以自己去github上访问

    四,测试效果

    1,访问

    http://127.0.0.1:8080/v1.0/home/home

    返回:

    home v1 : version:v1.0

    访问

    http://127.0.0.1:8080/v2/home/home

    返回:

    home v2 version: v2

    可见版本号带不带点,不妨碍它访问到对应的版本

    2,访问:

    http://127.0.0.1:8080/v3.0/home/home

    返回:

    home v2 version: v3.0

    访问:

    http://127.0.0.1:8080/v1.14/home/home

    返回:

    home v1.5 version: v1.14

    可见版本号可以自动访问到距它最近的版本的功能

    五, 查看spring boot的版本

      .   ____          _            __ _ _
     /\ / ___'_ __ _ _(_)_ __  __ _    
    ( ( )\___ | '_ | '_| | '_ / _` |    
     \/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.3.2.RELEASE)
  • 相关阅读:
    CS 系统框架二[完善自动更新]
    CS 系统框架二
    CS 系统框架二[增加默认启动以及代码打开窗体]
    2022届宝鸡质检[1]文数参考答案
    2022届宝鸡质检[1]理数参考答案
    合并DataTable并排除重复数据的通用方法
    IE6鼠标闪烁之谜
    Windows下MemCache多端口安装配置
    XML解析文件出错解决方法
    巧用row_number和partition by分组取top数据
  • 原文地址:https://www.cnblogs.com/architectforest/p/13432869.html
Copyright © 2020-2023  润新知