獲取指定類上的@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 = value;
    }

    public RequestMethod getRequestMethod() {
        return requestMethod;
    }

    public void setRequestMethod(RequestMethod requestMethod) {
        this.requestMethod = requestMethod;
    }

    @Override
    public String toString() {
        return "RequestUrlInfo [name=" + name + ", value=" + 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 = "/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;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM