获取指定类上的@RequestMapping注解的请求信息

从来好事天生俭,自古瓜儿苦后甜。这篇文章主要讲述获取指定类上的@RequestMapping注解的请求信息相关的知识,希望能为你提供帮助。
通过上一篇博客,我们能够轻松的得到制定类上的制定注解。现在,我们尝试获取指定类上的@RequestMapping注解,并获取该控制层的全部请求信息。在这里,提供一个实体类,用于存放请求的部分信息。

public class RequestUrlInfo implements Comparable< RequestUrlInfo> {private String name; //mapping的名称 private String value; //mapping的请求路径 private RequestMethod requestMethod; //响应请求的方法public RequestUrlInfo() {}public RequestUrlInfo(String name) { super(); this.name = name; }public String getName() { return name; }public void setName(String name) { this.name = name; }public String getValue() { return value; }public void setValue(String value) { this.value = https://www.songbingjia.com/android/value; }public RequestMethod getRequestMethod() { return requestMethod; }public void setRequestMethod(RequestMethod requestMethod) { this.requestMethod = requestMethod; }@Override public String toString() { return"RequestUrlInfo [name=" + name + ", value="https://www.songbingjia.com/android/+ value +", requestMethod=" + requestMethod + "]" + "\n"; }/** * 根据请求路径对请求信息进行区分。 */ @Override public int compareTo(RequestUrlInfo o) { return this.value.compareTo(o.getValue()); }}

在这里,为了后续的排序操作,实现Comparable接口,并根据请求路径进行排序依据。
接下来,就是获取指定类的RequestMapping注解信息。通过以下代码,能够轻松的获取类级别以及方法级别的注解。
Annotation classAnnotation = AnnotationHelper.getInstance().getClassAnnotation(scannerClass, RequestMapping.class); List< Annotation> methodAnnotations = AnnotationHelper.getInstance().getMethodAnnotation(scannerClass, RequestMapping.class);

现在,注解已经得到,需要通过得到的注解,获取该注解相关的信息。要获取RequestMapping注解的信息,就需要了解该注解的相关信息。
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping {/** * Assign a name to this mapping. * < p> < b> Supported at the type level as well as at the method level!< /b> * When used on both levels, a combined name is derived by concatenation * with "#" as separator. * @see org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder * @see org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy */ String name() default ""; /** * The primary mapping expressed by this annotation. * < p> In a Servlet environment this is an alias for {@link #path}. * For example {@code @RequestMapping("/foo")} is equivalent to * {@code @RequestMapping(path="/foo")}. * < p> In a Portlet environment this is the mapped portlet modes * (i.e. "EDIT", "VIEW", "HELP" or any custom modes). * < p> < b> Supported at the type level as well as at the method level!< /b> * When used at the type level, all method-level mappings inherit * this primary mapping, narrowing it for a specific handler method. */ @AliasFor("path") String[] value() default {}; /** * In a Servlet environment only: the path mapping URIs (e.g. "/myPath.do"). * Ant-style path patterns are also supported (e.g. "/myPath/*.do"). * At the method level, relative paths (e.g. "edit.do") are supported within * the primary mapping expressed at the type level. Path mapping URIs may * contain placeholders (e.g. "/${connect}") * < p> < b> Supported at the type level as well as at the method level!< /b> * When used at the type level, all method-level mappings inherit * this primary mapping, narrowing it for a specific handler method. * @see org.springframework.web.bind.annotation.ValueConstants#DEFAULT_NONE * @since 4.2 */ @AliasFor("value") String[] path() default {}; /** * The HTTP request methods to map to, narrowing the primary mapping: * GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. * < p> < b> Supported at the type level as well as at the method level!< /b> * When used at the type level, all method-level mappings inherit * this HTTP method restriction (i.e. the type-level restriction * gets checked before the handler method is even resolved). * < p> Supported for Servlet environments as well as Portlet 2.0 environments. */ RequestMethod[] method() default {}; /** * The parameters of the mapped request, narrowing the primary mapping. * < p> Same format for any environment: a sequence of "myParam=myValue" style * expressions, with a request only mapped if each such parameter is found * to have the given value. Expressions can be negated by using the "!=" operator, * as in "myParam!=myValue". "myParam" style expressions are also supported, * with such parameters having to be present in the request (allowed to have * any value). Finally, "!myParam" style expressions indicate that the * specified parameter is < i> not< /i> supposed to be present in the request. * < p> < b> Supported at the type level as well as at the method level!< /b> * When used at the type level, all method-level mappings inherit * this parameter restriction (i.e. the type-level restriction * gets checked before the handler method is even resolved). * < p> In a Servlet environment, parameter mappings are considered as restrictions * that are enforced at the type level. The primary path mapping (i.e. the * specified URI value) still has to uniquely identify the target handler, with * parameter mappings simply expressing preconditions for invoking the handler. * < p> In a Portlet environment, parameters are taken into account as mapping * differentiators, i.e. the primary portlet mode mapping plus the parameter * conditions uniquely identify the target handler. Different handlers may be * mapped onto the same portlet mode, as long as their parameter mappings differ. */ String[] params() default {}; /** * The headers of the mapped request, narrowing the primary mapping. * < p> Same format for any environment: a sequence of "My-Header=myValue" style * expressions, with a request only mapped if each such header is found * to have the given value. Expressions can be negated by using the "!=" operator, * as in "My-Header!=myValue". "My-Header" style expressions are also supported, * with such headers having to be present in the request (allowed to have * any value). Finally, "!My-Header" style expressions indicate that the * specified header is < i> not< /i> supposed to be present in the request. * < p> Also supports media type wildcards (*), for headers such as Accept * and Content-Type. For instance, * < pre class="code"> * & #064; RequestMapping(value = "https://www.songbingjia.com/something", headers = "content-type=text/*") * < /pre> * will match requests with a Content-Type of "text/html", "text/plain", etc. * < p> < b> Supported at the type level as well as at the method level!< /b> * When used at the type level, all method-level mappings inherit * this header restriction (i.e. the type-level restriction * gets checked before the handler method is even resolved). * < p> Maps against HttpServletRequest headers in a Servlet environment, * and against PortletRequest properties in a Portlet 2.0 environment. * @see org.springframework.http.MediaType */ String[] headers() default {}; /** * The consumable media types of the mapped request, narrowing the primary mapping. * < p> The format is a single media type or a sequence of media types, * with a request only mapped if the {@code Content-Type} matches one of these media types. * Examples: * < pre class="code"> * consumes = "text/plain" * consumes = {"text/plain", "application/*"} * < /pre> * Expressions can be negated by using the "!" operator, as in "!text/plain", which matches * all requests with a {@code Content-Type} other than "text/plain". * < p> < b> Supported at the type level as well as at the method level!< /b> * When used at the type level, all method-level mappings override * this consumes restriction. * @see org.springframework.http.MediaType * @see javax.servlet.http.HttpServletRequest#getContentType() */ String[] consumes() default {}; /** * The producible media types of the mapped request, narrowing the primary mapping. * < p> The format is a single media type or a sequence of media types, * with a request only mapped if the {@code Accept} matches one of these media types. * Examples: * < pre class="code"> * produces = "text/plain" * produces = {"text/plain", "application/*"} * produces = "application/json; charset=UTF-8" * < /pre> * < p> It affects the actual content type written, for example to produce a JSON response * with UTF-8 encoding, {@code "application/json; charset=UTF-8"} should be used. * < p> Expressions can be negated by using the "!" operator, as in "!text/plain", which matches * all requests with a {@code Accept} other than "text/plain". * < p> < b> Supported at the type level as well as at the method level!< /b> * When used at the type level, all method-level mappings override * this produces restriction. * @see org.springframework.http.MediaType */ String[] produces() default {}; }

现在,我们知道RequestMapping注解的name、value以及method的返回值,分别是String、String[]、RequestMethod[]。接下来,就是获取将注解的内容填充进实体类中。
private List< RequestUrlInfo> getRequestUrlInfos(Annotation annotation) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { List< RequestUrlInfo> infos = new ArrayList< RequestUrlInfo> (); if(annotation == null) { return infos; }String name = (String) AnnotationHelper.getInstance().getAnnotationInfo(annotation, "name"); List< String> requestUrls = Arrays.asList((String[]) AnnotationHelper.getInstance().getAnnotationInfo(annotation, "value")); List< RequestMethod> requestMethods = Arrays.asList((RequestMethod[]) AnnotationHelper.getInstance().getAnnotationInfo(annotation, "method")); if(requestMethods.isEmpty()) { for(String url : requestUrls) { RequestUrlInfo info = new RequestUrlInfo(name); info.setValue(url); info.setRequestMethod(null); infos.add(info); } } else { for(String url : requestUrls) { for(RequestMethod method : requestMethods) { RequestUrlInfo info = new RequestUrlInfo(name); info.setValue(url); info.setRequestMethod(method); infos.add(info); } } }

剩下的就是,将类级别的注解与方法级别的注解,组装成一个整体的实体类。
private List< RequestUrlInfo> getRequestUrlInfos(Annotation classAnnotation , Annotation methodAnnotation) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {List< RequestUrlInfo> infos = new ArrayList< RequestUrlInfo> (); if(classAnnotation != null) { String[] paths = (String[]) AnnotationHelper.getInstance().getAnnotationInfo(classAnnotation, "value"); for(String path : paths) { infos.addAll(getRequestUrlInfos(path, methodAnnotation)); } } else { infos.addAll(getRequestUrlInfos(methodAnnotation)); }return infos; }

下面,就是这个类的完整代码:
public class RequestUrlHelper {private static final RequestUrlHelper helper = new RequestUrlHelper(); protected RequestUrlHelper() {}public static RequestUrlHelper getInstance() { return helper; }/** * 将RequestMapping注解信息,组装成RequestUrlInfo类中。此类方法共有三种重载方式,分别为Annotation、提供basePath、提供classAnnotation注解三种方式。 * @param annotation * @return * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */ private List< RequestUrlInfo> getRequestUrlInfos(Annotation annotation) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { List< RequestUrlInfo> infos = new ArrayList< RequestUrlInfo> (); if(annotation == null) { return infos; }String name = (String) AnnotationHelper.getInstance().getAnnotationInfo(annotation, "name"); List< String> requestUrls = Arrays.asList((String[]) AnnotationHelper.getInstance().getAnnotationInfo(annotation, "value")); List< RequestMethod> requestMethods = Arrays.asList((RequestMethod[]) AnnotationHelper.getInstance().getAnnotationInfo(annotation, "method")); if(requestMethods.isEmpty()) { for(String url : requestUrls) { RequestUrlInfo info = new RequestUrlInfo(name); info.setValue(url); info.setRequestMethod(null); infos.add(info); } } else { for(String url : requestUrls) { for(RequestMethod method : requestMethods) { RequestUrlInfo info = new RequestUrlInfo(name); info.setValue(url); info.setRequestMethod(method); infos.add(info); } } }return infos; }/** * 上一个方法的重载方法,主要是将类上面的注解中的路径添加到全部的请求信息中。 * @param basePath * @param annotation * @return * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */ private List< RequestUrlInfo> getRequestUrlInfos(String basePath , Annotation annotation) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { List< RequestUrlInfo> infos = getRequestUrlInfos(annotation); if(!StringUtils.hasText(basePath)) { return infos; }for(RequestUrlInfo info : infos) { info.setValue(basePath.concat("/" + info.getValue())); }return infos; }/** * 上一个方法的重载方法,这次,没有提供basePath,而是提供一个Annotation,并从这个注解上面获取得到类上面注解的请求路径。 * @param classAnnotation * @param methodAnnotation * @return * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */ private List< RequestUrlInfo> getRequestUrlInfos(Annotation classAnnotation , Annotation methodAnnotation) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {List< RequestUrlInfo> infos = new ArrayList< RequestUrlInfo> (); if(classAnnotation != null) { String[] paths = (String[]) AnnotationHelper.getInstance().getAnnotationInfo(classAnnotation, "value"); for(String path : paths) { infos.addAll(getRequestUrlInfos(path, methodAnnotation)); } } else { infos.addAll(getRequestUrlInfos(methodAnnotation)); }return infos; }/** * 获取全部的请求,将其包装成RequestUrlInfo实体类,并将其通过请求路径排序后,进行返回。 * @param scannerClass * @return * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */ public List< RequestUrlInfo> getAllRequestUrlInfos(Class< ?> scannerClass) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Annotation classAnnotation = AnnotationHelper.getInstance().getClassAnnotation(scannerClass, RequestMapping.class); List< Annotation> methodAnnotations = AnnotationHelper.getInstance().getMethodAnnotation(scannerClass, RequestMapping.class); List< RequestUrlInfo> infos = new ArrayList< RequestUrlInfo> (); for(Annotation methodAnnotation : methodAnnotations) { infos.addAll(getRequestUrlInfos(classAnnotation, methodAnnotation)); }Collections.reverse(infos); return infos; } }

【获取指定类上的@RequestMapping注解的请求信息】 

    推荐阅读