一、接口版本控制目的:
1.1 保證減少停服務升級(減少升級影響用戶的使用,這里只涉及到接口層,其實還要考慮數據層的版本控制,比如:版本間要雙寫、字段不能刪除等)
1.2 版本向后兼容
二、接口版本控制的同種做法:
2.1 在URI中標記版本 https://xxx.com/api/v3/list 【我們今天講的是這種】
2.2 用參數的形式傳遞版本號:https://xxx.com/api/list?version=3.0
2.3 將版本號放到request header里:api-version:v1
2.4 通過token來判斷版本號: https://xxx.com/api/list?token=5782b5e0512c7d47345d10af413b3d28 // 服務端token處理器處理 ------> 確定請求API的內部版本 -----> 執行具體API ------>返回結果
三、實現:【sprinbboot+annotation+spring configuration+mvc】
3.1 自定義注解 ApiVersion.java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {
double value() default 1.0;
}
3.2 版本匹配
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
private static final Pattern VERSION_PREFIX_PATTERN = Pattern.compile("^\\S+/([1-9][.][0-9])$");
private double apiVersion;
public ApiVersionCondition(double apiVersion) {
this.apiVersion = apiVersion;
}
public double getApiVersion() {
return apiVersion;
}
public void setApiVersion(double apiVersion) {
this.apiVersion = apiVersion;
}
@Override
public ApiVersionCondition combine(ApiVersionCondition other) {
return new ApiVersionCondition(other.getApiVersion());
}
@Override
public ApiVersionCondition getMatchingCondition(HttpServletRequest httpServletRequest) {
Matcher matcher = VERSION_PREFIX_PATTERN.matcher(httpServletRequest.getRequestURI());
if (matcher.find()) {
Double version = Double.valueOf(matcher.group(1));
System.out.println("version:" + version + ",this.apiVersion:" + this.apiVersion);
if (version >= this.apiVersion) {
return this;
}
}
return null;
}
@Override
public int compareTo(ApiVersionCondition apiVersionCondition, HttpServletRequest httpServletRequest) {
return Double.compare(apiVersionCondition.getApiVersion(), this.apiVersion);
}
}
3.3 URL請求映射(帶@ApiVersion注解的走匹配規則)
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType,ApiVersion.class);
return createCondition(apiVersion);
}
@Override
protected RequestCondition<?> 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());
}
}
3.4控制器映射請求定義(URL映射)
@SpringBootConfiguration
public class WebMvcRegistrationsConfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new CustomRequestMappingHandlerMapping();
}
}
3.5創建控制器
@RestController
public class ImageController {
@GetMapping("/api/test/{version}")
@ApiVersion(2.0)
public String searchTargetImage() {
return "Hello,Welcome to version 2.0";
}
@GetMapping("/api/test/{version}")
@ApiVersion(1.0)
public String searchTargetImage2() {
return "Hello,Welcome to version 1.0";
}
@GetMapping("/api/test/{version}")
@ApiVersion(3.0)
public String searchTargetImage3() {
return "Hello,Welcome to version 3.0";
}
}
3.6執行
localhost:8383/api/test/2.0 => 結果:Hello,Welcome to version 2.0
localhost:8383/api/test/1.0 => 結果:Hello,Welcome to version 1.0