接口版本控制
一、接口為什麼需要版本控制
一個系統上線後會不斷疊代更新,需求也會不斷變化,有可能接口的參數也會發生變化,如果在原有的參數上直接修改,可能會影響線上系統的正常運作,這時我們就需要設定不同的版本,這樣即使參數發生變化,由于老版本沒有變化,是以不會影響上線系統的運作。
一般我們可以在位址上帶上版本号,也可以在參數上帶上版本号,還可以再 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的方法。