天天看點

SpringBoot——接口版本控制接口版本控制

接口版本控制

一、接口為什麼需要版本控制

一個系統上線後會不斷疊代更新,需求也會不斷變化,有可能接口的參數也會發生變化,如果在原有的參數上直接修改,可能會影響線上系統的正常運作,這時我們就需要設定不同的版本,這樣即使參數發生變化,由于老版本沒有變化,是以不會影響上線系統的運作。

一般我們可以在位址上帶上版本号,也可以在參數上帶上版本号,還可以再 header 裡帶上版本号,這裡我們在位址上帶上版本号,大緻的位址如:http://api.example.com/v1/test,其中,v1 即代表的是版本号。

二、實作示例

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {

    /**
     * 辨別版本号
     * @return
     */
    int value();
}
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {

    // 路徑中版本的字首, 這裡用 /v[1-9]/的形式
    private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");

    private int apiVersion;

    public ApiVersionCondition(int apiVersion){
        this.apiVersion = apiVersion;
    }

    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 采用最後定義優先原則,則方法上的定義覆寫類上面的定義
        return new ApiVersionCondition(other.getApiVersion());
    }

    @Override
    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)
            {
                return this;
            }
        }
        return null;
    }

    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        // 優先比對最新的版本号
        return other.getApiVersion() - this.apiVersion;
    }

    public int getApiVersion() {
        return apiVersion;
    }
}
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());
    }
}
@SpringBootConfiguration
public class WebConfig extends WebMvcConfigurationSupport {

    @Bean
    public AuthInterceptor interceptor(){
        return new AuthInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor());
    }

    @Override
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
        handlerMapping.setOrder(0);
        handlerMapping.setInterceptors(getInterceptors());
        return handlerMapping;
    }
}
           

Controller 類的接口定義如下:

@ApiVersion(1)
@RequestMapping("{version}/dd")
public class HelloController{}
           

這樣我們就實作了版本控制,如果增加了一個版本,則建立一個新的 Controller,方法名一緻,ApiVersion 設定為2,則位址中 v1 會找到 ApiVersion 為1的方法,v2 會找到 ApiVersion 為2的方法。

繼續閱讀