您的位置:首页 > 编程语言 > Java开发

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

2016-08-05 16:02 357 查看
互联网发展到今天,基于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 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.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;
}
}


如此就实现了最基本的对api的版本控制。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JAVA SpringMV restful