一、接口版本控制目的:
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