在后端开发的时候,我们经常会涉及到这样的一些业务场景:
1、开发一个接口给第三方进行调用,此时接口需要升级,但是第三方还未来得及开发,需要涉及到兼容 2、开发后端项目提供给安卓,ios,鸿蒙等客户端使用,接口需要升级,但是客户端还没有升级,需要涉及到兼容
此时的话我们就要求必须要使用接口版本管理,也就是相同的接口有不同的版本同时对外进行服务,保证第三方系统与我们服务进行交互的兼容性。
这项内容在我们的开发规范里面也是强制性要求的。所以这里的话我们来统一演示下做接口版本管理的模板。
1)声明接口版本注解
这里我们创建一个接口版本的注解,方便后续在实际的接口调用中直接使用注解声明,示例代码如下:
package com.mybatis.demo.version; 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; /** * 自定义一个版本注解,后续在对应的接口上编写添加版本注解,代表注解名称 */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ApiVersion { //默认版本是1.0.0 String value() default "1.0.0"; }
2)创建版本转化
这里的话我们需要把版本进行解析出来,后续使用 int 的方式进行比对,所以这里我们创建一个版本转化的实体类。示例代码如下:
package com.mybatis.demo.version; import lombok.Data; /** * 转换版本,之前的版本是v1.0.0,3个部分,我们把他拆开成一个moddel,使用int在后面比对 */ @Data public class ApiVersionItem implements Comparable<ApiVersionItem> { private int high = 1; private int mid = 0; private int low = 0; public ApiVersionItem() { } @Override public int compareTo(ApiVersionItem right) { if (this.getHigh() > right.getHigh()) { return 1; } else if (this.getHigh() < right.getHigh()) { return -1; } if (this.getMid() > right.getMid()) { return 1; } else if (this.getMid() < right.getMid()) { return -1; } if (this.getLow() > right.getLow()) { return 1; } else if (this.getLow() < right.getLow()) { return -1; } return 0; } }
3)创建版本转化方法
在实际声明注解的时候,我们的版本号一般是 V1.0.0这种模式,这种字符串的话我们需要转化成上面的 apiversionitem 类,所以这里编写一个转化的方法,示例代码如下:
package com.mybatis.demo.version; import lombok.Data; /** * 转换版本,之前的版本是v1.0.0,3个部分,我们把他拆开成一个moddel,使用int在后面比对 */ @Data public class ApiVersionItem implements Comparable<ApiVersionItem> { private int high = 1; private int mid = 0; private int low = 0; public ApiVersionItem() { } @Override public int compareTo(ApiVersionItem right) { if (this.getHigh() > right.getHigh()) { return 1; } else if (this.getHigh() < right.getHigh()) { return -1; } if (this.getMid() > right.getMid()) { return 1; } else if (this.getMid() < right.getMid()) { return -1; } if (this.getLow() > right.getLow()) { return 1; } else if (this.getLow() < right.getLow()) { return -1; } return 0; } }
4)编写解析request版本类
这里我们在 request 的时候,想着让他在 header 头里面传递一个api-version:1.0.0这样的参数用来匹配后端的版本,所以这里需要编写一个解析处理类,示例代码如下:
package com.mybatis.demo.version; import javax.servlet.http.HttpServletRequest; import org.springframework.web.servlet.mvc.condition.RequestCondition; /** * 版本适配器 */ public class ApiCondition implements RequestCondition<ApiCondition> { private ApiVersionItem version; public ApiCondition(ApiVersionItem version) { this.version = version; } @Override public ApiCondition combine(ApiCondition other) { // 选择版本最大的接口 return version.compareTo(other.version) >= 0 ? new ApiCondition(version) : new ApiCondition(other.version); } @Override public ApiCondition getMatchingCondition(HttpServletRequest request) { String version = request.getHeader("api-version"); ApiVersionItem item = ApiVersionConverter.convert(version); // 获取所有小于等于版本的接口 if (item.compareTo(this.version) >= 0) { return this; } return null; } @Override public int compareTo(ApiCondition other, HttpServletRequest request) { // 获取最大版本对应的接口 return other.version.compareTo(this.version); } }
5)注册解析 request 类
接下来我们把解析类注册到 request 处理的 handler 里面去,示例代码如下:
package com.mybatis.demo.version; 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; public class ApiHandlerMapping extends RequestMappingHandlerMapping { @Override protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) { return buildFrom(AnnotationUtils.findAnnotation(handlerType, ApiVersion.class)); } @Override protected RequestCondition<?> getCustomMethodCondition(Method method) { return buildFrom(AnnotationUtils.findAnnotation(method, ApiVersion.class)); } private ApiCondition buildFrom(ApiVersion platform) { return platform == null ? new ApiCondition(new ApiVersionItem()) : new ApiCondition(ApiVersionConverter.convert(platform.value())); } }
6)配置 webconf
我们把对应的 requestmappinghandler 注册到 web conf里面去,示例代码如下:
package com.mybatis.demo.config; import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import com.mybatis.demo.version.ApiHandlerMapping; @Configuration public class ApiAutoConfiguration implements WebMvcRegistrations { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return new ApiHandlerMapping(); } }
到这里我们的接口版本相关的代码就完成了,接下来我们使用某个接口来演示一下,例如我们创建3个 test 的接口,只是对应不同的版本:
然后我们把项目运行起来看看,然后在 request 的 header 头里面传递版本信息:
可以看到我们传递不同的版本号,就返回了不同的结果。以上就是关于接口版本管理的案例模板。
备注:
1、这里我们在实际的开发过程中一定要注意接口版本的兼容问题。 2、使用接口版本管理,可以为实际的项目线上避免很少的风险。
最后按照惯例,附上本案例的源码,登录后即可下载:
还没有评论,来说两句吧...