spring boot版本控制,代码如下:
/**
* 版本控制注解
* @author yuechao
* @deprecate 版本向上兼容,如存在1和3两个版本,若请求2,则默认请求版本1
*/
@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;
}
public ApiVersionCondition combine(ApiVersionCondition other) {
// 采用最后定义优先原则,则方法上的定义覆盖类上面的定义
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) // 如果请求的版本号大于配置版本号, 则满足
return this;
}else{
return this;
}
return null;
}
public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
// 优先匹配最新的版本号
return other.getApiVersion() - this.apiVersion;
}
public int getApiVersion() {
return apiVersion;
}
}
/**
* 版本号匹配拦截器
* @author yuechao
*
*/
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());
}
}
@Configuration
public class ApiConfig extends WebMvcConfigurationSupport {
/**
* 重新处理方法
*/
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors());
return handlerMapping;
}
}
测试类:
@RestController
@RequestMapping("/test/{version}/")
@Api(value="测试接口",tags= {"测试接口"})
public class TestController {
@ApiVersion(1)
@RequestMapping("user/{name}")
@ApiOperation("改变用户姓名")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "用户名", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "version", value = "版本", dataType = "int", paramType = "query")
})
public ApiResult getUser (@PathVariable("name") String name) {
User user = new User();
user.setUsername(name);
user.setUsername("哒哒哒哒哒哒多多");
ApiResult api = new ApiResult();
api.setCode(ApiResult.CODE_200);
api.setDatas(user);
return api;
}
@ApiVersion(3)
@GetMapping(value="user/{name}",produces = { "application/json;charset=UTF-8" })
@ApiOperation("改变用户姓名")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "用户名", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "version", value = "版本", dataType = "int", paramType = "query")
})
public ApiResult getUser1 (@PathVariable("name") String name) {
User user = new User();
user.setUsername("哒哒哒哒哒哒多多");
ApiResult api = new ApiResult();
api.setCode(ApiResult.CODE_200);
api.setDatas(user);
return api;
}
}
访问:http://localhost:8080/test/v2/user/aa则访问getUser方法,v3/user/aa访问getUser1方法。
但是后来发现swagger被拦截了。解决办法是重写WebMvcConfigurationSupport类中的addResourceHandlers方法,将swagger相关请求排除掉即可。如下:
/**
* swagger静态文件路径过滤,否则版本控制会拦截
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
super.addResourceHandlers(registry);
}