java写api接⼝源码_SpringBoot实现API接⼝的完整代码
⼀、简介
产品迭代过程中,同⼀个接⼝可能同时存在多个版本,不同版本的接⼝URL、参数相同,可能就是内部逻辑不同。尤其是在同⼀接⼝需要同时⽀持旧版本和新版本的情况下,⽐如APP发布新版本了,有的⽤户可能不选择升级,这是后接⼝的版本管理就⼗分必要了,根据APP的版本就可以提供不同版本的接⼝。
⼆、代码实现
本⽂的代码实现基于SpringBoot 2.3.4-release
1.定义注解
ApiVersion
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiVersion {
/**
* 版本。x.y.z格式
*
* @return
*/
String value() default "1.0.0";
}
value值默认为1.0.0
EnableApiVersion
/
**
* 是否开启API版本控制
*/
@Target(ElementType.TYPE)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Import(ApiAutoConfiguration.class)
public @interface EnableApiVersion {
}
在启动类上添加这个注解后就可以开启接⼝的多版本⽀持。使⽤Import引⼊配置ApiAutoConfiguration。
2.将版本号抽象为ApiItem类
ApiItem
@Data
public class ApiItem implements Comparable {
private int high = 1;
private int mid = 0;
private int low = 0;
public static final ApiItem API_ITEM_DEFAULT = vert(ApiVersionConstant.DEFAULT_VERSION); public ApiItem() {
}
@Override
public int compareTo(ApiItem right) {
if (High() > High()) {
return 1;
} else if (High() < High()) {
return -1;
}
if (Mid() > Mid()) {
return 1;
} else if (Mid() < Mid()) {
return -1;
}
if (Low() > Low()) {
return 1;
} else if (Low() < Low()) {
return -1;
}
return 0;
}
}
为了⽐较版本号的⼤⼩,实现Comparable接⼝并重写compareTo(),从⾼位到低位依次⽐较。
ApiConverter
public class ApiConverter {
public static ApiItem convert(String api) {
ApiItem apiItem = new ApiItem();
if (StringUtils.isBlank(api)) {
return apiItem;
}
String[] cells = StringUtils.split(api, ".");
apiItem.setHigh(Integer.parseInt(cells[0]));
if (cells.length > 1) {
apiItem.setMid(Integer.parseInt(cells[1]));
}
if (cells.length > 2) {
apiItem.setLow(Integer.parseInt(cells[2]));
}
return apiItem;
}
}
ApiConverter提供静态⽅法将字符创转为ApiItem。
常量类,定义请求头及默认版本号
public class ApiVersionConstant {
/**
* header 指定版本号请求头
*/
public static final String API_VERSION = "x-api-version";
/**
* 默认版本号
*/
public static final String DEFAULT_VERSION = "1.0.0";
}
3.核⼼ApiCondition
新建ApiCondition类,实现RequestCondition,重写combine、getMatchingCondition、compareTo⽅法。RequestCondition
public interface RequestCondition {
/**
* ⽅法和类上都存在相同的条件时的处理⽅法
*/
T combine(T other);
/**
* 判断是否符合当前请求,返回null表⽰不符合
*/
@Nullable
T getMatchingCondition(HttpServletRequest request);
/**
*如果存在多个符合条件的接⼝,则会根据这个来排序,然后⽤集合的第⼀个元素来处理
*/
int compareTo(T other, HttpServletRequest request);
以上对RequestCondition简要说明,后续详细源码分析各个⽅法的作⽤。
ApiCondition
@Slf4j
public class ApiCondition implements RequestCondition {
public static ApiCondition empty = new vert(ApiVersionConstant.DEFAULT_VERSION)); private ApiItem version;
private boolean NULL;
public ApiCondition(ApiItem item) {
this.version = item;
}
public ApiCondition(ApiItem item, boolean NULL) {
this.version = item;
this.NULL = NULL;
}
/**
*
* Spring先扫描⽅法再扫描类,然后调⽤{@link #combine}
* 按照⽅法上的注解优先级⼤于类上注解的原则处理,但是要注意如果⽅法上不定义注解的情况。
* 如果⽅法或者类上不定义注解,我们会给⼀个默认的值{@code empty},{@link ApiHandlerMapping}
*
* @param other ⽅法扫描封装结果
* @return
*/
@Override
public ApiCondition combine(ApiCondition other) {
// 选择版本最⼤的接⼝
if (other.NULL) {
return this;
}
return other;
java影视app源码}
@Override
public ApiCondition getMatchingCondition(HttpServletRequest request) {
if (CorsUtils.isPreFlightRequest(request)) {
return empty;
}
String version = Header(ApiVersionConstant.API_VERSION);
// 获取所有⼩于等于版本的接⼝;如果前端不指定版本号,则默认请求1.0.0版本的接⼝
if (StringUtils.isBlank(version)) {
log.warn("未指定版本,使⽤默认1.0.0版本。");
version = ApiVersionConstant.DEFAULT_VERSION;
}
ApiItem item = vert(version);
if (itempareTo(ApiItem.API_ITEM_DEFAULT) < 0) {
throw new IllegalArgumentException(String.format("API版本[%s]错误,最低版本[%s]", version, ApiVersionConstant.DEFAULT_VERSION));
}
if (itempareTo(this.version) >= 0) {
return this;
}
return null;
}
@Override
public int compareTo(ApiCondition other, HttpServletRequest request) {
// 获取到多个符合条件的接⼝后,会按照这个排序,然后get(0)获取最⼤版本对应的接⼝.⾃定义条件会最后⽐较
int compare = other.versionpareTo(this.version);
if (compare == 0) {
log.warn("RequestMappingInfo相同,请检查!version:{}", other.version);
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论