轻松一下
重庆交警把一个骑摩托车拦下,并让司机出示证件。
司机说: 都是重庆人,哥子给个面子撒,本本儿忘带了,我家斗在勒点的。
交警说: 莫豁我,你不是重庆嘞。
司机反问: 你郎个晓得我不是重庆嘞? ?
交警说: 你莫不承认,等我拦个重庆的给你看哈。
这时候一小伙子骑摩托过来了,交警摆手拦车!结果摩托车飞奔而过,风中远远传来一句: 你个哈批! 过来抓老子撒!
交警转身对刚才的司机说: 看到没得! 勒个才是重庆的! 你娃儿一看就是成都的。
需求来源
公司使用敏捷开发,app要兼容不同的版本,最开始最方便的方法是在类或者方法上直接加上V1,V2等版本的标识,可是在迭代或者不同开发者(新同事)之间标准不统一,比如:v1/user/add和user/v1/add到底是同一个接口还是不同的接口,为了更好的处理问题,使用注解和反射解决。
1、创建注解@ApiVersion
/**
* 版本注解
*
* @author Zhang Jie
* @version 1.0.0
* @since 2021/4/22 11:49
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiVersion {
String[] value();
}
2、继承RequestMappingHandlerMapping
RequestMappingHandlerMapping从类或方法上的注解@RequestMapping 来生成RequestMappingInfo 的实例。
/**
* 实现RequestMappingHandlerMapping
* @author Zhang Jie
* @version 1.0.0
* @since 2021/4/22 13:46
*/
public class ApiVersionHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected boolean isHandler(Class<?> beanType) {
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
}
/**
* 从@ApiVersion自定义注解中读取版本信息,拼接上原有的、不带版本号的 URL Pattern
*/
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
Class<?> controllerClass = method.getDeclaringClass();
// 类上的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);
// 重新构建RequestMappingInfo
mapping = new RequestMappingInfo(mapping.getName(), updatedFinalPattern, mapping.getMethodsCondition(),
mapping.getParamsCondition(), mapping.getHeadersCondition(), mapping.getConsumesCondition(),
mapping.getProducesCondition(), mapping.getCustomCondition());
super.registerHandlerMethod(handler, method, mapping);
}
}
3、在spring boot的启动类上实现接口WebMvcRegistrations
@EnableScheduling
@EnableEurekaClient
@SpringBootApplication
public class CouponTemplateApplication implements WebMvcRegistrations {
public static void main(String[] args) {
SpringApplication.run(CouponTemplateApplication.class, args);
}
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new ApiVersionHandlerMapping();
}
}
4、测试
/**
* 测试版本注解
* 方法上的注解优先
*
* @author Zhang Jie
* @version 1.0.0
* @since 2021/4/22 14:09
*/
@RestController
@ApiVersion("v1")
@RequestMapping("/test")
public class TestController {
@GetMapping("t1")
@ApiVersion("v2")
public String t1(){
// 布隆过滤器
return "test";
}
}

1186

被折叠的 条评论
为什么被折叠?



