今天呢,闲来无事,想到了接口设计的版本号的一些知识,特此来简单的说下API接口设计中的Version版本号。
我们在接口的日常开发中,肯定都避免不了接口永成不变,那么就会出现接口变更,那么接口变更又是怎么区分的呢?接口变更又会不会对老接口有什么影响或者其他的呢,说了这么多,这就引出了一个版本号的概念,通过给API接口设置不同的版本号就可以达到区分接口的目的,版本号的定义在接口开发中又是百花齐放,我就一个小小的案例来尝试一下简单的用注解的方式定义版本的吧。
市面上目前主要定义版本号的实现主要有三种,第一种是通过接口路径定义的时候直接把Version
版本号定义进去,第二种就是通过入参
传递版本号以达到访问不同版本的接口,第三种就是设置请求头X-API-VERSION
参数实现版本控制。这三种方式中我个人还是倾向于第一种接口路径版本号的方式,主要是这种方式简单直观清晰,并且实现起来也是非常简单的,下面我就第一种接口路径实现版本号的方式简单的用注解实现一下,当然直接写在路径中也可以,但是注解的方式更加显得正规一点。
1.定义版本号注解@ApiVersion
新建一个版本号注解@ApiVersion,用在类上或者方法上都可以,看自己需要。
package cn.youhaveme.version;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiVersion {
String[] value();
}
2.创建一个ApiVersionMapping继承
RequestMappingHandlerMapping
是根据类或方法上的@RequestMapping来生成 RequestMappingInfo的实例。那么我们通过实现registerHandlerMethod方法就可以自定义版本号的实现。通过读取@ApiVersion的版本号拼接上原有路径组成一个新的鞋带版本号的路径就可以实现这种注解式版本。
package cn.youhaveme.version;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
public class ApiVersionMapping extends RequestMappingHandlerMapping {
@Override
protected boolean isHandler(Class<?> beanType) {
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
}
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
Class<?> controllerClass = method.getDeclaringClass();
// Controller的@ApIVersion注解
ApiVersion apiVersion = AnnotationUtils.findAnnotation(controllerClass, ApiVersion.class);
// 方法的@ApIVersion注解
ApiVersion methodAnnotation = AnnotationUtils.findAnnotation(method, ApiVersion.class);
// 方法上的注解优先级高于类上的注解
if (methodAnnotation != null) {
apiVersion = methodAnnotation;
}
String[] urlPatterns = apiVersion == null ? new String[0] : apiVersion.value();
PatternsRequestCondition apiPattern = new PatternsRequestCondition(urlPatterns);
PatternsRequestCondition oldPattern = mapping.getPatternsCondition();
PatternsRequestCondition updatedFinalPattern = apiPattern.combine(oldPattern);
mapping = new RequestMappingInfo(mapping.getName(), updatedFinalPattern, mapping.getMethodsCondition(),
mapping.getParamsCondition(), mapping.getHeadersCondition(), mapping.getConsumesCondition(),
mapping.getProducesCondition(), mapping.getCustomCondition());
super.registerHandlerMethod(handler, method, mapping);
}
}
3.全局配置
全局配置是让自定义的Mapping生效,正常的如果不配置这个的话自己的Mapping是无法生效的。
package cn.youhaveme.version;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
public class ApiVersionConfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new ApiVersionMapping();
}
}
这样的话就已经实现了版本号的注解开发,如有需要,直接在Controller类上或者方法上使用@ApiVersion("v1")标记版本号即可,怎吗样,还是挺简单的吧。