背景介绍
在做后端API接口的时候,被前端同事吐槽以前的接口URL没有遵循Restful API 规范,所以开会讨论,最终拍板确定,新做的接口定义要照着标准规范来。
找了找关于Restful API的文章,还是这位大佬说的容易理解: www.ruanyifeng.com/blog/2014/0…
里面讲到了API的版本号。
这里跟组员协商确定后,URL要也同样要突出版本号。所以在某个版本阶段开发的API接口,要指明URL的版本号。
在实际代码中,发现如下问题:
如果把”v1″这类词直接写到controller的映射中,那就变成类似如下:
@GetMapping("/v1/user/info")
复制代码
这样每个实际url都要写一遍重复的”v1″,不够灵活。
有没有方法,可以直接在指定的url上,前面全部拼接上v1呢?
因此这里就抛出一个问题:Spring Boot 如何修改请求url?
问题描述
Spring Boot 如何修改请求url?
关键词: Spring Boot add url prefix
解决方案
自定义注解 @ApiVersion , 设置注解修饰的方法,在请求映射 request mapping 上添加前缀值。
具体值直接传入注解,即可。
实现代码
自定义注解 @ApiVersion
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiVersion {
int[] value();
}
复制代码
配置注解 @ApiVersion 生效
自定义beanApiVersionRequestMappingHandlerMapping, 重写RequestMappingHandlerMapping
public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
private final String prefix;
public ApiVersionRequestMappingHandlerMapping(String prefix) {
this.prefix = prefix;
}
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = super.getMappingForMethod(method, handlerType);
if(info == null) return null;
ApiVersion methodAnnotation = AnnotationUtils.findAnnotation(method, ApiVersion.class);
if(methodAnnotation != null) {
RequestCondition<?> methodCondition = getCustomMethodCondition(method);
// Concatenate our ApiVersion with the usual request mapping
info = createApiVersionInfo(methodAnnotation, methodCondition).combine(info);
} else {
ApiVersion typeAnnotation = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
if(typeAnnotation != null) {
RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
// Concatenate our ApiVersion with the usual request mapping
info = createApiVersionInfo(typeAnnotation, typeCondition).combine(info);
}
}
return info;
}
private RequestMappingInfo createApiVersionInfo(ApiVersion annotation, RequestCondition<?> customCondition) {
int[] values = annotation.value();
String[] patterns = new String[values.length];
for(int i=0; i<values.length; i++) {
// Build the URL prefix
patterns[i] = prefix+values[i];
}
return new RequestMappingInfo(
new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(), useSuffixPatternMatch(), useTrailingSlashMatch(), getFileExtensions()),
new RequestMethodsRequestCondition(),
new ParamsRequestCondition(),
new HeadersRequestCondition(),
new ConsumesRequestCondition(),
new ProducesRequestCondition(),
customCondition);
}
}
复制代码
添加配置WebMvcConfig,启动时注入beanApiVersionRequestMappingHandlerMapping
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
return new ApiVersionRequestMappingHandlerMapping("v");
}
@Bean
protected RequestMappingHandlerMapping customRequestMappingHandlerMapping() {
return new ApiVersionRequestMappingHandlerMapping("v");
}
}
复制代码
Controller 方法使用注解
如下所示:
原来的请求url是 : /user/info
加上注解 @ApiVersion(1) 后,请求url就变成 /v1/user/info ;
同理,改成 @ApiVersion(2) 后,请求url就变成 /v2/user/info .
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/info")
@ApiVersion(1)
public R getUserInfo(UserQueryDTO userQueryDTO){
try {
return userService.getUserInfo(userQueryDTO)
.msg("success");
} catch (Exception e) {
log.error("get user info fail:{}", e);
return R.fail().msg("get user info fail");
}
}
}