文章出处:http://www.cnblogs.com/jcli/p/springmvc_restful_version.html
主要实现webapi版本兼容和降级,比如访问api/v3/hello但是服务端没有这个版本只有api/v2/hello可以默认降级到该版本
下面贴部分代码:
1.ApiVersion.java 定义版本注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.web.bind.annotation.Mapping;
/**
*
* @author wszhang
*
* @create 2017年4月9日 上午12:57:04
* @version 1.0
* @description 接口版本标识注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {
int value();
}
2.ApiVesrsionCondition 版本筛选,注意request.getPathInfo()和request.getPathInfo()区别否则会有空指针,在原作者基础上加了一个case使错误版本号默认返回最新版本
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
/**
*
* @author wszhang
*
* @create 2017年4月9日 上午12:57:39
* @version 1.0
* @description 版本号匹配筛选器
*/
public class ApiVesrsionCondition implements RequestCondition<ApiVesrsionCondition> {
// 路径中版本的前缀, 这里用 /v[1-9]/的形式
private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");
private int apiVersion;
public ApiVesrsionCondition(int apiVersion) {
this.apiVersion = apiVersion;
}
@Override
public ApiVesrsionCondition combine(ApiVesrsionCondition other) {
// 采用最后定义优先原则,则方法上的定义覆盖类上面的定义
return new ApiVesrsionCondition(other.getApiVersion());
}
@Override
public int compareTo(ApiVesrsionCondition other, HttpServletRequest request) {
// 优先匹配最新的版本号
return other.getApiVersion() - this.apiVersion;
}
public int getApiVersion() {
return apiVersion;
}
@Override
public ApiVesrsionCondition getMatchingCondition(HttpServletRequest request) {
//request.getPathInfo()
Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getServletPath());
if (m.find()) {
Integer version = Integer.valueOf(m.group(1));
if (version >= this.apiVersion)
// 如果请求的版本号大于等于配置版本号, 则满足
return this;
} else {
// 如果版本号错误返回最新版本号
return this;
}
return null;
}
}
2.CustomRequestMappingHandlerMapping自定义RequestMappingHandlerMapping
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
/**
*
* @author wszhang
*
* @create 2017年4月9日 上午12:57:39
* @version 1.0
* @description 版本号匹配筛选器
*/
public class ApiVesrsionCondition implements RequestCondition<ApiVesrsionCondition> {
// 路径中版本的前缀, 这里用 /v[1-9]/的形式
private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");
private int apiVersion;
public ApiVesrsionCondition(int apiVersion) {
this.apiVersion = apiVersion;
}
@Override
public ApiVesrsionCondition combine(ApiVesrsionCondition other) {
// 采用最后定义优先原则,则方法上的定义覆盖类上面的定义
return new ApiVesrsionCondition(other.getApiVersion());
}
@Override
public int compareTo(ApiVesrsionCondition other, HttpServletRequest request) {
// 优先匹配最新的版本号
return other.getApiVersion() - this.apiVersion;
}
public int getApiVersion() {
return apiVersion;
}
@Override
public ApiVesrsionCondition getMatchingCondition(HttpServletRequest request) {
//request.getPathInfo()
Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getServletPath());
if (m.find()) {
Integer version = Integer.valueOf(m.group(1));
if (version >= this.apiVersion)
// 如果请求的版本号大于等于配置版本号, 则满足
return this;
} else {
// 如果版本号错误返回最新版本号
return this;
}
return null;
}
}
4.配置文件及小结,原作者已经说明采用这种方式会导致mvc:annotation-driven不能使用,做过不少尝试避免此问题,但是均没有好的解决方案,主要是不设置ByteArrayHttpMessageConverter会导致接口返回数据乱码,遂重新注入了RequestMappingHandlerAdapter
<!--自定义requestMapping解析器 -->
<bean class="com.demo.util.version.CustomRequestMappingHandlerMapping">
<property name="order" value="0" />
</bean>
<!-- 解决乱码问题 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
原作者采用JavaConfig的方式注入CustomRequestMappingHandlerMapping,代码如下:
@Configuration
public class WebConfig extends WebMvcConfigurationSupport{
@Override
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors());
return handlerMapping;
}
}