Python 官方文档:入门教程 => 点击学习
目录SpringBoot 增加 api Version一、增加ApiVersion自定义注解二、新增RequestCondition自定义匹配条件三、重写RequestMapping
基于restful风格上,增加version版本号
例如: get /api/v1/users/
作用于Controller上,指定API版本号
这里版本号使用了double ,考虑到小版本的情况,例如1.1
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiVersion {
double version() default 1;
}
Spring提供RequestCondition接口,用于定义API匹配条件
这里通过自定义匹配条件,识别ApiVersion,进行版本匹配
getMatchinGCondition 用于检查URL中,是否符合/v{版本号},用于过滤无版本号接口;
compareTo 用于决定多个相同API时,使用哪个接口进行处理;
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> {
private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("/v([0-9]+\\.{0,1}[0-9]{0,2})/");
private ApiVersion apiVersion;
ApiVersionCondition(ApiVersion apiVersion){
this.apiVersion = apiVersion;
}
@Override
public ApiVersionCondition combine(ApiVersionCondition other) {
// 此处按优先级,method大于class
return new ApiVersionCondition(other.getApiVersion());
}
@Override
public ApiVersionCondition getMatchingCondition(HttpServletRequest httpServletRequest) {
// 通过uri匹配版本号
System.out.println(httpServletRequest.getRequestURI());
Matcher m = VERSION_PREFIX_PATTERN.matcher(httpServletRequest.getRequestURI());
if (m.find()) {
// 获得符合匹配条件的ApiVersionCondition
System.out.println("groupCount:"+m.groupCount());
double version = Double.valueOf(m.group(1));
if (version >= getApiVersion().version()) {
return this;
}
}
return null;
}
@Override
public int compareTo(ApiVersionCondition other, HttpServletRequest httpServletRequest) {
// 当出现多个符合匹配条件的ApiVersionCondition,优先匹配版本号较大的
return other.getApiVersion().version() >= getApiVersion().version() ? 1 : -1;
}
public ApiVersion getApiVersion() {
return apiVersion;
}
}
通过重写 RequestMappingHandlerMapping 类,对RequestMappering进行识别@ApiVersion注解,针对性处理;
这里考虑到有些接口不存在版本号,则使用Spring原来的ApiVersionRequestMappingHandlerMapping继续处理;
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 ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType,ApiVersion.class);
return null == apiVersion ? super.getCustomTypeCondition(handlerType) : new ApiVersionCondition(apiVersion);
}
@Override
protected RequestCondition<?> getCustomMethodCondition(Method method) {
ApiVersion apiVersion = AnnotationUtils.findAnnotation(method,ApiVersion.class);
return null == apiVersion ? super.getCustomMethodCondition(method) : new ApiVersionCondition(apiVersion);
}
}
通过@ApiVersion注解指定该接口版本号
import com.panda.common.web.controller.BasicController;
import com.panda.common.web.version.ApiVersion;
import com.panda.core.umc.service.UserInfoService;
import com.panda.core.umc.vo.QueryUsersConditionVo;
import com.panda.face.umc.dto.user.QueryUsersReq;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RequestMapping("/api")
@RestController
public class UserInfoController extends BasicController{
@Autowired
private UserInfoService userInfoService;
@ApiVersion
@RequestMapping(value = "{version}/users", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity getUsers(@PathVariable("version") String version, QueryUsersReq req){
QueryUsersConditionVo condition = new QueryUsersConditionVo();
BeanUtils.copyProperties(req,condition);
condition.setOrderBy("CREATE_TIME");
condition.setSort("DESC");
return assemble("1111");
}
@ApiVersion(version = 1.1)
@RequestMapping(value = "{version}/users", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity getUsersV2(@PathVariable("version") String version, QueryUsersReq req){
QueryUsersConditionVo condition = new QueryUsersConditionVo();
BeanUtils.copyProperties(req,condition);
condition.setOrderBy("CREATE_TIME");
condition.setSort("DESC");
return assemble("222");
}
@RequestMapping(value = "/users/uid/{userId}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity getUserInfo(@PathVariable("userId") String userId){
return assemble(userInfoService.selectByUserId(userId));
}
}
通过访问以下URL,测试返回结果
GET http://127.0.0.1/api/v1/users
GET http://127.0.0.1/api/v1.1/users
GET http://127.0.0.1/api/v1.2/users
GET http://127.0.0.1/api/users/uid/U0001
1.通过@ApiVersion注解方式,可以灵活指定接口版本;
2.缺点很明显,需要在URL上加入{version},才能进行匹配成功,这种PathVariable识别过于模糊,后期排查问题增加困难;
3.建议通过包名增加v1/v2明显区分版本,且在controller的URL上直接写死v1版本号,这种更直观;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiVersion {
int value() default 1;
}
@Data
@Slf4j
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
private final static Pattern VERSION_PREFIX = Pattern.compile("/v(\\d+)/");
private int apiVersion;
ApiVersionCondition(int apiVersion) {
this.apiVersion = apiVersion;
}
@Override
public ApiVersionCondition combine(ApiVersionCondition other) {
return new ApiVersionCondition(other.getApiVersion());
}
@Override
public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
Matcher m = VERSION_PREFIX.matcher(request.getRequestURI());
if (m.find()) {
int version = Integer.valueOf(m.group(1));
if (version >= getApiVersion()) {
return this;
}
}
return null;
}
@Override
public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
return other.getApiVersion() - getApiVersion();
}
}
说明:
getMatchingCondition方法中,控制了只有版本小于等于请求参数中的版本的 ApiCondition 才满足规则
compareTo 指定了当有多个ApiCoondition满足这个请求时,选择最大的版本
public class ApiRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
// 扫描类上的 @ApiVersion
ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
return createRequestCondition(apiVersion);
}
@Override
protected RequestCondition<?> getCustomMethodCondition(Method method) {
// 扫描方法上的 @ApiVersion
ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
return createRequestCondition(apiVersion);
}
private RequestCondition<ApiVersionCondition> createRequestCondition(ApiVersion apiVersion) {
if (Objects.isNull(apiVersion)) {
return null;
}
int value = apiVersion.value();
Assert.isTrue(value >= 1, "Api Version Must be greater than or equal to 1");
return new ApiVersionCondition(value);
}
}
@Configuration
public class WebMvcRegistrationsConfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new ApiRequestMappingHandlerMapping();
}
}
@RestController
@RequestMapping("/api/{version}")
public class ApiControler {
@GetMapping("/fun")
public String fun1() {
return "fun 1";
}
@ApiVersion(5)
@GetMapping("/fun")
public String fun2() {
return "fun 2";
}
@ApiVersion(9)
@GetMapping("/fun")
public String fun3() {
return "fun 5";
}
}
页面测试效果:
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
--结束END--
本文标题: SpringBoot API增加version版本号方式
本文链接: https://www.lsjlt.com/news/154362.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0