SpingMVC框架实现restfull接口的版本控制



http://blog.csdn.net/lynnlovemin/article/details/52129916

互联网发展到今天,基于restfull开发的系统也越来越多,不再局限于jsp等脚本语言来实现动态数据的展示,而是通过后台提供的http接口给前端调用,但是当系统越做越大,同一个接口可能会不断的修改,一旦调用方式发生改变,后果是非常严重的,客户端将无法正常调用,除非强制客户端升级到最新版本,这个也是不太现实的,那怎么办呢?我们想到的就是通过版本来控制同一个接口,类似这样的一个地址:http://localhost:8080/api/v1,其中v1就是当前所用到的版本,那怎么来实现呢?直接上代码:

首先自定义一个注解:

  1. import java.lang.annotation.Documented;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.   
  7. import org.springframework.web.bind.annotation.Mapping;  
  8.   
  9. @Target({ElementType.METHOD,ElementType.TYPE})  
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Documented  
  12. @Mapping  
  13. public @interface ApiVersion {  
  14.   
  15.     /** 
  16.      * 标识版本号 
  17.      * @return 
  18.      */  
  19.     int value();  
  20. }  
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();
}


这个注解标识当前接口所对应的版本

  1. import org.springframework.web.bind.annotation.RequestMapping;  
  2. import org.springframework.web.bind.annotation.RestController;  
  3.   
  4. import cn.sunsharp.platform.annotation.ApiVersion;  
  5. import cn.sunsharp.platform.web.BaseController;  
  6.   
  7.   
  8. @RequestMapping("{version}")  
  9. @RestController  
  10. public class HelloController extends BaseController {  
  11.   
  12.     @ApiVersion(1)  
  13.     @RequestMapping("hello")  
  14.     public String hello1(){  
  15.         return "hello1";  
  16.     }  
  17.       
  18.     @ApiVersion(2)  
  19.     @RequestMapping("hello")  
  20.     public String hello2(){  
  21.         return "hello2";  
  22.     }  
  23. }  
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错误,也就是没有这个页面,怎么办呢,相当的就是拦截器,如果传入的版本没有,则默认访问最新的版本,请看代码:

  1. import java.util.regex.Matcher;  
  2. import java.util.regex.Pattern;  
  3.   
  4. import javax.servlet.http.HttpServletRequest;  
  5.   
  6. import org.springframework.web.servlet.mvc.condition.RequestCondition;  
  7.   
  8. public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {  
  9.   
  10.     // 路径中版本的前缀, 这里用 /v[1-9]/的形式  
  11.     private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");  
  12.        
  13.     private int apiVersion;  
  14.        
  15.     public ApiVersionCondition(int apiVersion){  
  16.         this.apiVersion = apiVersion;  
  17.     }  
  18.        
  19.     public ApiVersionCondition combine(ApiVersionCondition other) {  
  20.         // 采用最后定义优先原则,则方法上的定义覆盖类上面的定义  
  21.         return new ApiVersionCondition(other.getApiVersion());  
  22.     }  
  23.    
  24.     public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {  
  25.         Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());  
  26.         if(m.find()){  
  27.             Integer version = Integer.valueOf(m.group(1));  
  28.             if(version >= this.apiVersion) // 如果请求的版本号大于配置版本号, 则满足  
  29.                 return this;  
  30.         }  
  31.         return null;  
  32.     }  
  33.    
  34.     public int compareTo(ApiVersionCondition other, HttpServletRequest request) {  
  35.         // 优先匹配最新的版本号  
  36.         return other.getApiVersion() - this.apiVersion;  
  37.     }  
  38.    
  39.     public int getApiVersion() {  
  40.         return apiVersion;  
  41.     }  
  42. }  
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;
    }
}


  1. import java.lang.reflect.Method;  
  2.   
  3. import org.springframework.core.annotation.AnnotationUtils;  
  4. import org.springframework.web.servlet.mvc.condition.RequestCondition;  
  5. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;  
  6.   
  7. import cn.sunsharp.platform.annotation.ApiVersion;  
  8.   
  9. public class CustomRequestMappingHandlerMapping extends  
  10.         RequestMappingHandlerMapping {  
  11.   
  12.     @Override  
  13.     protected RequestCondition<ApiVersionCondition> getCustomTypeCondition(Class<?> handlerType) {  
  14.         ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);  
  15.         return createCondition(apiVersion);  
  16.     }  
  17.    
  18.     @Override  
  19.     protected RequestCondition<ApiVersionCondition> getCustomMethodCondition(Method method) {  
  20.         ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);  
  21.         return createCondition(apiVersion);  
  22.     }  
  23.        
  24.     private RequestCondition<ApiVersionCondition> createCondition(ApiVersion apiVersion) {  
  25.         return apiVersion == null ? null : new ApiVersionCondition(apiVersion.value());  
  26.     }  
  27. }  
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());
    }
}


这样,当传入的版本没有则默认会访问最新的版本,还没有完,还需要注册这个拦截器:

  1. import org.springframework.context.annotation.Bean;  
  2. import org.springframework.context.annotation.Configuration;  
  3. import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;  
  4. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;  
  5.   
  6. import cn.sunsharp.platform.version.CustomRequestMappingHandlerMapping;  
  7.   
  8. @Configuration  
  9. public class WebConfig extends WebMvcConfigurationSupport {  
  10.   
  11.     @Override  
  12.     @Bean  
  13.     public RequestMappingHandlerMapping requestMappingHandlerMapping() {  
  14.         RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();  
  15.         handlerMapping.setOrder(0);  
  16.         handlerMapping.setInterceptors(getInterceptors());  
  17.         return handlerMapping;  
  18.     }  
  19. }  
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的版本控制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值