API Restful接口开发 版本控制

API版本控制常用实践

  • URL:http://example.com/v1/helloworld

  • HEADER:这里写图片描述

  • 各大公司做法:
    http://www.lexicalscope.com/blog/2012/03/12/how-are-rest-apis-versioned/

Spring Boot实践API版本管理

原理

在SpringMVC中RequestMappingHandlerMapping是比较重要的一个角色,它决定了每个URL分发至哪个Controller。

Spring Boot加载过程如下,所以我们可以通过自定义WebMvcRegistrationsAdapter来改写RequestMappingHandlerMapping。
这里写图片描述

ApiVersion.java

package com.freud.apiversioning.configuration;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
import org.springframework.web.bind.annotation.Mapping;
 
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {
 
    /**
     * version
     * 
     * @return
     */
    int value();
}

ApiVersionCondition.java

package com.freud.apiversioning.configuration;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import javax.servlet.http.HttpServletRequest;
 
import org.springframework.web.servlet.mvc.condition.RequestCondition;
 
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
 
    // extract the version part from url. example [v0-9]
    private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("/v(\\d+)/.*");
 
    private int apiVersion;
 
    public ApiVersionCondition(int apiVersion) {
        this.apiVersion = apiVersion;
    }
 
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // latest defined would be take effect, that means, methods definition with
        // override the classes definition
        return new ApiVersionCondition(other.getApiVersion());
    }
 
    public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
        Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
        if (m.find()) {
            Integer version = Integer.valueOf(m.group(1));
            if (version >= this.apiVersion) // when applying version number bigger than configuration, then it will take
                                            // effect
                return this;
        }
        return null;
    }
 
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        // when more than one configured version number passed the match rule, then only
        // the biggest one will take effect.
        return other.getApiVersion() - this.apiVersion;
    }
 
    public int getApiVersion() {
        return apiVersion;
    }
 
}

ApiVersioningRequestMappingHandlerMapping.java

package com.freud.apiversioning.configuration;
 
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;
 
public class ApiVersioningRequestMappingHandlerMapping 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.java

package com.freud.apiversioning.configuration;
 
import org.springframework.boot.autoconfigure.web.WebMvcRegistrationsAdapter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 
@Configuration
public class WebMvcRegistrationsConfig extends WebMvcRegistrationsAdapter {
 
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new ApiVersioningRequestMappingHandlerMapping();
    }
 
}

测试

TestVersioningController.java

package com.freud.apiversioning.v1.controller;
 
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import com.freud.apiversioning.configuration.ApiVersion;
 
@ApiVersion(1)
@RequestMapping("/{api_version}")
@RestController("TestVersioningController-v1")
public class TestVersioningController {
 
    @RequestMapping("/hello")
    public String hello() {
        return "hello v1";
    }
}

TestVersioningController.java

package com.freud.apiversioning.v2.controller;
 
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import com.freud.apiversioning.configuration.ApiVersion;
 
@ApiVersion(2)
@RequestMapping("/{api_version}")
@RestController("TestVersioningController-v2")
public class TestVersioningController {
 
    @RequestMapping("/hello")
    public String hello() {
        return "hello v2";
    }
}

ApiVersioningApplication.java

package com.freud.apiversioning;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class ApiVersioningApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ApiVersioningApplication.class, args);
    }
}

application.yml

server:
  port: 7905

项目结构

这里写图片描述

演示

v1

访问http://localhost:7905/v1/hello
这里写图片描述

v2

访问http://localhost:7905/v2/hello
这里写图片描述

。。。

v100

访问http://localhost:7905/v100/hello

这里写图片描述

參考資料

Spring Boot API 版本权限控制: http://blog.csdn.net/u010782227/article/details/74905404

让SpringMVC支持可版本管理的Restful接口:http://www.cnblogs.com/jcli/p/springmvc_restful_version.html

如何做到API兼容: https://kb.cnblogs.com/page/108253/

解析@EnableWebMvc 、WebMvcConfigurationSupport和WebMvcConfigurationAdapter: http://blog.csdn.net/pinebud55/article/details/53420481

How are REST APIs versioned?: http://blog.csdn.net/pinebud55/article/details/53420481

让SpringMVC支持可版本管理的Restful接口:https://www.cnblogs.com/jcli/p/springmvc_restful_version.html

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值