[英]Adding validation in RequestMapping annotation
I am using spring boot and I want to add API versioning support for some of the RequestMapping (url path should start with /v[1-9]+/). 我正在使用Spring Boot,我想为某些RequestMapping添加API版本支持(URL路径应以/ v [1-9] + /开头)。
I am thinking of creating an annotation: MyRequestMapping that additionally supports the api versioning path. 我正在考虑创建一个注释:MyRequestMapping,它另外支持api版本控制路径。 This way, anyone using MyRequestMapping will automatically have api version assigned to it.
这样,任何使用MyRequestMapping的人都会自动为其分配api版本。
As I can not extend RequestMapping annotation (annotation extension is not allowed in Java), I am not sure how to go forward with this approach.. Any hint/idea will be great! 由于我无法扩展RequestMapping注释(Java中不允许扩展注释),因此我不确定如何继续使用此方法。任何提示/想法都将非常有用!
In short: How do I support api versioning for "path" in RequestMapping? 简而言之:我如何在RequestMapping中为“路径”支持api版本控制? Thanks..
谢谢..
I would create class-only MyRequestMapping that matches URLs starting with /v[1-9]+/ 我将创建与/ v [1-9] + /开头的URL匹配的纯类MyRequestMapping
See https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestmapping-uri-templates for official documentation about using regex in request mapping 有关在请求映射中使用正则表达式的官方文档,请参阅https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestmapping-uri-templates
Then user could further narrow down the path with method-level RequestMapping annotations. 然后,用户可以使用方法级的RequestMapping注释进一步缩小路径。
You can use a filter
, and do the required check inside filter
. 您可以使用
filter
,并在filter
内部进行所需的检查。 If the check didnt return true just modify the httpresponse
from the filter itself and return, Thats it. 如果检查未返回true,则只需修改过滤器本身的
httpresponse
并返回,就可以了。 I added a sample filter
below, you need to do required changes in web.xml
or @configuration
class accordingly, for the filter to work. 我在下面添加了一个示例
filter
,您需要在web.xml
或@configuration
类中进行必要的更改,才能使过滤器正常工作。
public class MyFilter implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
if("")//Do the required check here
{
//Modifiy httpservlet response .
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
I found better way to support api versioning. 我找到了更好的方法来支持api版本控制。 Below is the explanation:
以下是说明:
1) Create an annotation: ApiVersion: 1) 创建一个注释:ApiVersion:
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping("/{apiVersion}")
public @interface ApiVersion {
/**
* version
*
* @return
*/
int value() default 1;
boolean latest() default false;
}
2) Create custom RequestCondition to put the matching logic:** 2) 创建自定义RequestCondition以放置匹配逻辑:**
public class ApiVersionCondition implements RequestCondition { 公共类ApiVersionCondition实现RequestCondition {
private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("/v(\\d+)/");
private final static Pattern LATEST_PREFIX_PATTERN = Pattern.compile("/latest/");
private int apiVersion;
private boolean latest;
public ApiVersionCondition(int apiVersion, boolean latest) {
this.apiVersion = apiVersion;
this.latest = latest;
}
/**
* Latest definition will take effect, that means method definition will override the classes definition
*
* @param otherApiVersionCondition other condition that is matching.
* @return latest definition of matching condition.
*/
public ApiVersionCondition combine(ApiVersionCondition otherApiVersionCondition) {
return new ApiVersionCondition(otherApiVersionCondition.getApiVersion(), otherApiVersionCondition.isLatest());
}
/**
* Define matcher to match the pattern for api versioning.
* When version number requested is equal to or greater than configured, condition will be returned.
*
* @param request Request instance
* @return ApiVersionCondition based on match
*/
public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
Matcher m = LATEST_PREFIX_PATTERN.matcher(request.getRequestURI());
if (m.find() && isLatest()) {
return this;
}
m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
if (m.find()) {
Integer version = Integer.valueOf(m.group(1));
if (version >= this.apiVersion)
return this;
}
return null;
}
/**
* When more than one configured version number passes the match rule, the bigest one will take effect.
*
* @param otherApiVersionCondition other api version condition that was satisfied.
* @param request Request instance
* @return 1 if other version condition has greater api version, -1 if this condition has greater api version, 0 if they are same.
*/
public int compareTo(ApiVersionCondition otherApiVersionCondition, HttpServletRequest request) {
return otherApiVersionCondition.getApiVersion() - this.apiVersion;
}
/**
* Getter for api version.
*
* @return api version for the condition.
*/
private int getApiVersion() {
return apiVersion;
}
/**
* Getter for whether latest is configured in annotation.
*
* @return true if latest is configured in annotation, else false.
*/
private boolean isLatest() {
return latest;
}
} }
3) Create custom RequestMappingHandlerMapping: 3) 创建自定义RequestMappingHandlerMapping:
public class ApiVersioningRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestCondition<ApiVersionCondition> getCustomTypeCondition(Class<?> handlerType) {
return createCondition(AnnotationUtils.findAnnotation(handlerType, ApiVersion.class));
}
@Override
protected RequestCondition<ApiVersionCondition> getCustomMethodCondition(Method method) {
return createCondition(AnnotationUtils.findAnnotation(method, ApiVersion.class));
}
private RequestCondition<ApiVersionCondition> createCondition(ApiVersion apiVersion) {
return apiVersion == null ? null : new ApiVersionCondition(apiVersion.value(), apiVersion.latest());
}
}
4) Ask Spring to use the custom RequestMappingHandlerMapping: 4) 让Spring使用自定义的RequestMappingHandlerMapping:
@Configuration
public class WebMvcRegistrationsConfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
ApiVersioningRequestMappingHandlerMapping apiVersioningRequestMappingHandlerMapping = new ApiVersioningRequestMappingHandlerMapping();
apiVersioningRequestMappingHandlerMapping.setOrder(0);
apiVersioningRequestMappingHandlerMapping.setRemoveSemicolonContent(false);
return apiVersioningRequestMappingHandlerMapping;
}
}
5) Use it in controller: 5) 在控制器中使用:
@ApiVersion //default is version 1
//@RequestMapping("{apiVersion}/test") //add this if want to specify a common root e.g. v<x>/test for all below request mapping
@RestController
public class GreetingController {
private static final String template = "Hello , %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting") // URI: /v1/greeting will be mapped to this method
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
@ApiVersion(2)
@RequestMapping("/greeting") // URI: /v2/greeting will be mapped to this method
public Greeting greetingV2(@RequestParam(value = "name", defaultValue = "World version 2") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
@ApiVersion(value = 3, latest = true)
@RequestMapping("/greeting") // URI: /v3/greeting OR /latest/greeting will be mapped to this method
public Greeting greetingV3(@RequestParam(value = "name", defaultValue = "World version 3") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
There are still some fine tuning to do but this is a good start for what I wanted to achieve. 仍然需要进行一些微调,但这是我想要实现的目标的良好开端。 Will update if find better idea or some improvements.
如果发现更好的主意或某些改进,将进行更新。 Please let us know if someone finds improvements.
如果有人发现改进之处,请告诉我们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.