一个注解实现版本控制

**

一个系统上线后会不断迭代更新,需求也会不断变化,有可能接口的参数也会发生变化,如果在原有的参数上直接修改,可能会影响线上系统的正常运行,这时我们就需要设置不同的版本,这样即使参数发生变化,由于老版本没有变化,因此不会影响上线系统的运行。

**一般我们可以在地址上带上版本号,例如:http://api.example.com/v1/test

其中v1代表的是版本号,所以我们只需要动态的设置v1,v2,v3……

现在我们利用spring的RequestMappingHandlerMapping自己定制一个request匹配,
首先,大概介绍下这个RequestMappingHandlerMapping ,该类的作用有两个:

  • 通过request查找对应的HandlerMethod,即当前request具体是由Controller中的哪个方法进行处理;
  • 查找当前系统中的Interceptor,将其与HandlerMethod封装为一个HandlerExecutionChain。

废话不多说了,直接上代码:

import org.springframework.web.bind.annotation.Mapping;

import java.lang.annotation.*;


@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {
    /**
     * 标识版本号
     * @return
     */
    int value();

}
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.mvc.condition.RequestCondition;

import javax.servlet.http.HttpServletRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


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;
    }

    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 采用最后定义优先原则,则方法上的定义覆盖类上面的定义
        return new ApiVersionCondition(other.getApiVersion());
    }

    @Override
    @Nullable
    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;
    }

    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        // 优先匹配最新的版本号
        return other.getApiVersion() - this.apiVersion;
    }

    public int getApiVersion() {
        return apiVersion;
    }
}
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;


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());
    }

}

最后一步很关键,要在WebMvcConfig进行配置(基于springboot2.0以上):


      @Configuration
        public class WebMvcConfig extends WebMvcConfigurationSupport {
    
    		    @Override
    		    @Bean
    		    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
    		        RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
    		        handlerMapping.setOrder(0);
    		        handlerMapping.setInterceptors(getInterceptors());
    		        return handlerMapping;
    		    }
        }

现在我们用postman来测试下:

@Slf4j
@RestController
@RequestMapping("/dd")
public class Test {

	@ApiVersion(1)
	@GetMapping("{version}/test")
	public Result test(){
		log.info("版本控制测试!");
		return Result.success("V1测试成功");
	}
	@ApiVersion(2)
	@GetMapping("{version}/test")
	public Result test1(){
		log.info("版本控制测试!");
		return Result.success("V2测试成功");
	}
}

先是V1 :
在这里插入图片描述
现在看V2:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT界的奇葩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值