http://blog.csdn.net/lynnlovemin/article/details/52129916
互联网发展到今天,基于restfull开发的系统也越来越多,不再局限于jsp等脚本语言来实现动态数据的展示,而是通过后台提供的http接口给前端调用,但是当系统越做越大,同一个接口可能会不断的修改,一旦调用方式发生改变,后果是非常严重的,客户端将无法正常调用,除非强制客户端升级到最新版本,这个也是不太现实的,那怎么办呢?我们想到的就是通过版本来控制同一个接口,类似这样的一个地址:http://localhost:8080/api/v1,其中v1就是当前所用到的版本,那怎么来实现呢?直接上代码:
首先自定义一个注解:
- 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;
- @Target({ElementType.METHOD,ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Mapping
- public @interface ApiVersion {
- /**
- * 标识版本号
- * @return
- */
- int value();
- }
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;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {
/**
* 标识版本号
* @return
*/
int value();
}
这个注解标识当前接口所对应的版本
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import cn.sunsharp.platform.annotation.ApiVersion;
- import cn.sunsharp.platform.web.BaseController;
- @RequestMapping("{version}")
- @RestController
- public class HelloController extends BaseController {
- @ApiVersion(1)
- @RequestMapping("hello")
- public String hello1(){
- return "hello1";
- }
- @ApiVersion(2)
- @RequestMapping("hello")
- public String hello2(){
- return "hello2";
- }
- }
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.sunsharp.platform.annotation.ApiVersion;
import cn.sunsharp.platform.web.BaseController;
@RequestMapping("{version}")
@RestController
public class HelloController extends BaseController {
@ApiVersion(1)
@RequestMapping("hello")
public String hello1(){
return "hello1";
}
@ApiVersion(2)
@RequestMapping("hello")
public String hello2(){
return "hello2";
}
}
这样我们通过v1,v2这样的地址就能访问到对应的版本,但是这样会有一个问题,如果客户端传入v3,但是所定义的版本并没有定义v3,此时客户端肯定会报404错误,也就是没有这个页面,怎么办呢,相当的就是拦截器,如果传入的版本没有,则默认访问最新的版本,请看代码:
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import javax.servlet.http.HttpServletRequest;
- import org.springframework.web.servlet.mvc.condition.RequestCondition;
- 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;
- }
- return null;
- }
- public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
- // 优先匹配最新的版本号
- return other.getApiVersion() - this.apiVersion;
- }
- public int getApiVersion() {
- return apiVersion;
- }
- }
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
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;
}
return null;
}
public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
// 优先匹配最新的版本号
return other.getApiVersion() - this.apiVersion;
}
public int getApiVersion() {
return apiVersion;
}
}
- import java.lang.reflect.Method;
- import org.springframework.core.annotation.AnnotationUtils;
- import org.springframework.web.servlet.mvc.condition.RequestCondition;
- import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
- import cn.sunsharp.platform.annotation.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());
- }
- }
import java.lang.reflect.Method;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import cn.sunsharp.platform.annotation.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());
}
}
这样,当传入的版本没有则默认会访问最新的版本,还没有完,还需要注册这个拦截器:
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
- import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
- import cn.sunsharp.platform.version.CustomRequestMappingHandlerMapping;
- @Configuration
- public class WebConfig extends WebMvcConfigurationSupport {
- @Override
- @Bean
- public RequestMappingHandlerMapping requestMappingHandlerMapping() {
- RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
- handlerMapping.setOrder(0);
- handlerMapping.setInterceptors(getInterceptors());
- return handlerMapping;
- }
- }
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import cn.sunsharp.platform.version.CustomRequestMappingHandlerMapping;
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors());
return handlerMapping;
}
}
如此就实现了最基本的对api的版本控制。