扩展spring mvc的拦截器,实现AOP的环绕增加效果

原因:

1. spring mvc拦截器通过中postHander方法中只有ModelAndView类型的结果,如果@Controller返回的是@ResponseBody的字符串类型,ModelAndView的值就为null,就不能在postHandler中把结果写入日志或做其它对结果的处理。

 

public void postHandle(

			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

			throws Exception {

	}

2.AOP的环绕增强能够拿到@Controller的结果,但前置检查只能检查方法中定义的参数,没有固定HttpServletRequest参数,如之前我一篇文章中的例子http://blog.csdn.net/wuxinzaiyu/article/details/8608394,

request需要这样获取,并且具体执行方法的参数第一个必须是HttpServletRequest才行,即使获取的时候可以循环下判断类型得到,也不是很方便

获取参数方法:

 

HttpServletRequest request = (HttpServletRequest) pjp.getArgs()[0];  

 

执行方法代码:

 

  1. @ResponseBody  
  2.     @RequestMapping(value="/openapi/v1/account/kp")  
  3.     public String kp(HttpServletRequest request) {  
  4.         System.out.println("kp:123");  
  5.         return "kp:123";  
  6.     }  

 

 

目的:结合两种方法,即能实现环绕效果又不限制具体方法的写法。


用同事写好的代码为例,开工:

1.以spring mvc的AnnotationMethodHandlerAdapter为基础,在invokeHandlerProcess方法中增加前后执行内容,达到环绕增强

 

package com.test.interceptor;





import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.io.Reader;

import java.io.Writer;

import java.lang.reflect.Method;

import java.security.Principal;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Collections;

import java.util.Comparator;

import java.util.HashMap;

import java.util.Iterator;

import java.util.LinkedHashMap;

import java.util.LinkedHashSet;

import java.util.List;

import java.util.Locale;

import java.util.Map;

import java.util.Set;



import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;



import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.BeanUtils;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.BeanFactoryAware;

import org.springframework.beans.factory.config.BeanExpressionContext;

import org.springframework.beans.factory.config.BeanExpressionResolver;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;

import org.springframework.core.LocalVariableTableParameterNameDiscoverer;

import org.springframework.core.Ordered;

import org.springframework.core.ParameterNameDiscoverer;

import org.springframework.core.annotation.AnnotationUtils;

import org.springframework.http.HttpEntity;

import org.springframework.http.HttpHeaders;

import org.springframework.http.HttpInputMessage;

import org.springframework.http.HttpOutputMessage;

import org.springframework.http.HttpStatus;

import org.springframework.http.MediaType;

import org.springframework.http.ResponseEntity;

import org.springframework.http.converter.ByteArrayHttpMessageConverter;

import org.springframework.http.converter.HttpMessageConverter;

import org.springframework.http.converter.StringHttpMessageConverter;

import org.springframework.http.converter.xml.SourceHttpMessageConverter;

import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.http.server.ServletServerHttpRequest;

import org.springframework.http.server.ServletServerHttpResponse;

import org.springframework.ui.ExtendedModelMap;

import org.springframework.ui.Model;

import org.springframework.util.AntPathMatcher;

import org.springframework.util.Assert;

import org.springframework.util.ClassUtils;

import org.springframework.util.ObjectUtils;

import org.springframework.util.PathMatcher;

import org.springframework.util.StringUtils;

import org.springframework.validation.support.BindingAwareModelMap;

import org.springframework.web.HttpMediaTypeNotAcceptableException;

import org.springframework.web.HttpRequestMethodNotSupportedException;

import org.springframework.web.HttpSessionRequiredException;

import org.springframework.web.bind.MissingServletRequestParameterException;

import org.springframework.web.bind.ServletRequestDataBinder;

import org.springframework.web.bind.WebDataBinder;

import org.springframework.web.bind.annotation.ModelAttribute;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.ResponseStatus;

import org.springframework.web.bind.annotation.SessionAttributes;

import org.springframework.web.bind.annotation.support.HandlerMethodInvoker;

import org.springframework.web.bind.annotation.support.HandlerMethodResolver;

import org.springframework.web.bind.support.DefaultSessionAttributeStore;

import org.springframework.web.bind.support.SessionAttributeStore;

import org.springframework.web.bind.support.WebArgumentResolver;

import org.springframework.web.bind.support.WebBindingInitializer;

import org.springframework.web.context.request.NativeWebRequest;

import org.springframework.web.context.request.RequestScope;

import org.springframework.web.context.request.ServletWebRequest;

import org.springframework.web.multipart.MultipartRequest;

import org.springframework.web.servlet.HandlerAdapter;

import org.springframework.web.servlet.HandlerMapping;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.View;

import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;

import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;

import org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver;

import org.springframework.web.servlet.mvc.multiaction.MethodNameResolver;

import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;

import org.springframework.web.servlet.support.RequestContextUtils;

import org.springframework.web.servlet.support.WebContentGenerator;

import org.springframework.web.util.UrlPathHelper;

import org.springframework.web.util.WebUtils;



/**

 * 从spring的AnnotationMethodHandlerAdapter拷贝而来,增加了执行method前后的扩展点,顺便纪录下执行时间

 * @author zhipeng.qzp

 */

public class ExtendableHandlerAdapter extends WebContentGenerator implements HandlerAdapter, Ordered, BeanFactoryAware {



    /**

     * Log category to use when no mapped handler is found for a request.

     * @see #pageNotFoundLogger

     */

    public static final String                                PAGE_NOT_FOUND_LOG_CATEGORY             = "org.springframework.web.servlet.PageNotFound";



    /**

     * Additional logger to use when no mapped handler is found for a request.

     * @see #PAGE_NOT_FOUND_LOG_CATEGORY

     */

    protected static final Logger                             logger                                  = LoggerFactory.getLogger(PAGE_NOT_FOUND_LOG_CATEGORY);



    private UrlPathHelper                                     urlPathHelper                           = new UrlPathHelper();



    private PathMatcher                                       pathMatcher                             = new AntPathMatcher();



    private MethodNameResolver                                methodNameResolver                      = new InternalPathMethodNameResolver();



    private WebBindingInitializer                             webBindingInitializer;



    private SessionAttributeStore                             sessionAttributeStore                   = new DefaultSessionAttributeStore();



    private int                                               cacheSecondsForSessionAttributeHandlers = 0;



    private boolean                                           synchronizeOnSession                    = false;



    private ParameterNameDiscoverer                           parameterNameDiscoverer                 = new LocalVariableTableParameterNameDiscoverer();



    private WebArgumentResolver[]                             customArgumentResolvers;



    private ModelAndViewResolver[]                            customModelAndViewResolvers;



    private HttpMessageConverter<?>[]                         messageConverters;



    private int                                               order                                   = Ordered.HIGHEST_PRECEDENCE;



    private ConfigurableBeanFactory                           beanFactory;



    private BeanExpressionContext                             expressionContext;



    private final Map<Class<?>, ServletHandlerMethodResolver> methodResolverCache                     = new HashMap<Class<?>, ServletHandlerMethodResolver>();



    private List<IHandlerInterceptor>                         invokeInterceptors                      = new ArrayList<IHandlerInterceptor>();



    @SuppressWarnings("rawtypes")

    public ExtendableHandlerAdapter() {

        // no restriction of HTTP methods by default

        super(false);



        // See SPR-7316

        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();

        stringHttpMessageConverter.setWriteAcceptCharset(false);

        this.messageConverters = new HttpMessageConverter[] { new ByteArrayHttpMessageConverter(), stringHttpMessageConverter, new SourceHttpMessageConverter(), new XmlAwareFormHttpMessageConverter() };

    }



    /**

     * Set if URL lookup should always use the full path within the current

     * servlet context. Else, the path within the current servlet mapping is

     * used if applicable (that is, in the case of a ".../*" servlet mapping in

     * web.xml).

     * <p>

     * Default is "false".

     * @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath

     */

    public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {

        this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);

    }



    /**

     * Set if context path and request URI should be URL-decoded. Both are

     * returned <i>undecoded</i> by the Servlet API, in contrast to the servlet

     * path.

     * <p>

     * Uses either the request encoding or the default encoding according to the

     * Servlet spec (ISO-8859-1).

     * @see org.springframework.web.util.UrlPathHelper#setUrlDecode

     */

    public void setUrlDecode(boolean urlDecode) {

        this.urlPathHelper.setUrlDecode(urlDecode);

    }



    /**

     * Set the UrlPathHelper to use for resolution of lookup paths.

     * <p>

     * Use this to override the default UrlPathHelper with a custom subclass, or

     * to share common UrlPathHelper settings across multiple HandlerMappings

     * and HandlerAdapters.

     */

    public void setUrlPathHelper(UrlPathHelper urlPathHelper) {

        Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");

        this.urlPathHelper = urlPathHelper;

    }



    /**

     * Set the PathMatcher implementation to use for matching URL paths against

     * registered URL patterns.

     * <p>

     * Default is {@link org.springframework.util.AntPathMatcher}.

     */

    public void setPathMatcher(PathMatcher pathMatcher) {

        Assert.notNull(pathMatcher, "PathMatcher must not be null");

        this.pathMatcher = pathMatcher;

    }



    /**

     * Set the MethodNameResolver to use for resolving default handler methods

     * (carrying an empty <code>@RequestMapping</code> annotation).

     * <p>

     * Will only kick in when the handler method cannot be resolved uniquely

     * through the annotation metadata already.

     */

    public void setMethodNameResolver(MethodNameResolver methodNameResolver) {

        this.methodNameResolver = methodNameResolver;

    }



    /**

     * Specify a WebBindingInitializer which will apply pre-configured

     * configuration to every DataBinder that this controller uses.

     */

    public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {

        this.webBindingInitializer = webBindingInitializer;

    }



    /**

     * Specify the strategy to store session attributes with.

     * <p>

     * Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore} , storing session attributes in the HttpSession, using the same attribute

     * name as in the model.

     */

    public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {

        Assert.notNull(sessionAttributeStore, "SessionAttributeStore must not be null");

        this.sessionAttributeStore = sessionAttributeStore;

    }



    /**

     * Cache content produced by <code>@SessionAttributes</code> annotated

     * handlers for the given number of seconds. Default is 0, preventing

     * caching completely.

     * <p>

     * In contrast to the "cacheSeconds" property which will apply to all

     * general handlers (but not to <code>@SessionAttributes</code> annotated

     * handlers), this setting will apply to <code>@SessionAttributes</code>

     * annotated handlers only.

     * @see #setCacheSeconds

     * @see org.springframework.web.bind.annotation.SessionAttributes

     */

    public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) {

        this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers;

    }



    /**

     * Set if controller execution should be synchronized on the session, to

     * serialize parallel invocations from the same client.

     * <p>

     * More specifically, the execution of the

     * <code>handleRequestInternal</code> method will get synchronized if this

     * flag is "true". The best available session mutex will be used for the

     * synchronization; ideally, this will be a mutex exposed by

     * HttpSessionMutexListener.

     * <p>

     * The session mutex is guaranteed to be the same object during the entire

     * lifetime of the session, available under the key defined by the

     * <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a safe

     * reference to synchronize on for locking on the current session.

     * <p>

     * In many cases, the HttpSession reference itself is a safe mutex as well,

     * since it will always be the same object reference for the same active

     * logical session. However, this is not guaranteed across different servlet

     * containers; the only 100% safe way is a session mutex.

     * @see org.springframework.web.util.HttpSessionMutexListener

     * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)

     */

    public void setSynchronizeOnSession(boolean synchronizeOnSession) {

        this.synchronizeOnSession = synchronizeOnSession;

    }



    /**

     * Set the ParameterNameDiscoverer to use for resolving method parameter

     * names if needed (e.g. for default attribute names).

     * <p>

     * Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}.

     */

    public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {

        this.parameterNameDiscoverer = parameterNameDiscoverer;

    }



    /**

     * Set a custom WebArgumentResolvers to use for special method parameter

     * types.

     * <p>

     * Such a custom WebArgumentResolver will kick in first, having a chance to

     * resolve an argument value before the standard argument handling kicks in.

     */

    public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) {

        this.customArgumentResolvers = new WebArgumentResolver[] { argumentResolver };

    }



    /**

     * Set one or more custom WebArgumentResolvers to use for special method

     * parameter types.

     * <p>

     * Any such custom WebArgumentResolver will kick in first, having a chance

     * to resolve an argument value before the standard argument handling kicks

     * in.

     */

    public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) {

        this.customArgumentResolvers = argumentResolvers;

    }



    /**

     * Set a custom ModelAndViewResolvers to use for special method return

     * types.

     * <p>

     * Such a custom ModelAndViewResolver will kick in first, having a chance to

     * resolve a return value before the standard ModelAndView handling kicks

     * in.

     */

    public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) {

        this.customModelAndViewResolvers = new ModelAndViewResolver[] { customModelAndViewResolver };

    }



    /**

     * Set one or more custom ModelAndViewResolvers to use for special method

     * return types.

     * <p>

     * Any such custom ModelAndViewResolver will kick in first, having a chance

     * to resolve a return value before the standard ModelAndView handling kicks

     * in.

     */

    public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) {

        this.customModelAndViewResolvers = customModelAndViewResolvers;

    }



    /**

     * Set the message body converters to use.

     * <p>

     * These converters are used to convert from and to HTTP requests and

     * responses.

     */

    public void setMessageConverters(HttpMessageConverter<?>[] messageConverters) {

        this.messageConverters = messageConverters;

    }



    /**

     * Return the message body converters that this adapter has been configured

     * with.

     */

    public HttpMessageConverter<?>[] getMessageConverters() {

        return messageConverters;

    }



    /**

     * Specify the order value for this HandlerAdapter bean.

     * <p>

     * Default value is <code>Integer.MAX_VALUE</code>, meaning that it's

     * non-ordered.

     * @see org.springframework.core.Ordered#getOrder()

     */

    public void setOrder(int order) {

        this.order = order;

    }



    public int getOrder() {

        return this.order;

    }



    public void setBeanFactory(BeanFactory beanFactory) {

        if (beanFactory instanceof ConfigurableBeanFactory) {

            this.beanFactory = (ConfigurableBeanFactory) beanFactory;

            this.expressionContext = new BeanExpressionContext(this.beanFactory, new RequestScope());

        }

    }



    public void setInvokeInterceptors(List<?> invokeInterceptors) {

        for (Object obj : invokeInterceptors) {

            if (obj instanceof IHandlerInterceptor) {

                this.invokeInterceptors.add((IHandlerInterceptor) obj);

            }

        }

    }



    public boolean supports(Object handler) {

        return getMethodResolver(handler).hasHandlerMethods();

    }



    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (AnnotationUtils.findAnnotation(handler.getClass(), SessionAttributes.class) != null) {

            // Always prevent caching in case of session attribute management.

            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);

            // Prepare cached set of session attributes names.

        } else {

            // Uses configured default cacheSeconds setting.

            checkAndPrepare(request, response, true);

        }



        // Execute invokeHandlerMethod in synchronized block if required.

        if (this.synchronizeOnSession) {

            HttpSession session = request.getSession(false);

            if (session != null) {

                Object mutex = WebUtils.getSessionMutex(session);

                synchronized (mutex) {

                    return invokeHandlerProcess(request, response, handler);

                }

            }

        }



        return invokeHandlerProcess(request, response, handler);

    }



    protected ModelAndView invokeHandlerProcess(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);

        Method handlerMethod = methodResolver.resolveHandlerMethod(request);

        ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);

        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        ExtendedModelMap implicitModel = new BindingAwareModelMap();



        if (null != this.invokeInterceptors && !this.invokeInterceptors.isEmpty()) {

            for (IHandlerInterceptor interceptor : this.invokeInterceptors) {

                interceptor.preInvoke(handlerMethod, handler, webRequest);

            }

        }



        Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);



        ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);



        if (null != this.invokeInterceptors && !this.invokeInterceptors.isEmpty()) {

            for (int i = this.invokeInterceptors.size() - 1; i >= 0; i--) {

                this.invokeInterceptors.get(i).postInvoke(handlerMethod, handler, webRequest, ((null != result) ? result : mav));

            }

        }



        methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);



        return mav;

    }



    public long getLastModified(HttpServletRequest request, Object handler) {

        return -1;

    }



    /**

     * Build a HandlerMethodResolver for the given handler type.

     */

    private ServletHandlerMethodResolver getMethodResolver(Object handler) {

        // if(true) throw new RuntimeException();

        Class<?> handlerClass = ClassUtils.getUserClass(handler);

        synchronized (this.methodResolverCache) {

            ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass);

            if (resolver == null) {

                resolver = new ServletHandlerMethodResolver(handlerClass);

                this.methodResolverCache.put(handlerClass, resolver);

            }

            return resolver;

        }

    }



    /**

     * Template method for creating a new ServletRequestDataBinder instance.

     * <p>

     * The default implementation creates a standard ServletRequestDataBinder.

     * This can be overridden for custom ServletRequestDataBinder subclasses.

     * @param request

     *            current HTTP request

     * @param target

     *            the target object to bind onto (or <code>null</code> if the

     *            binder is just used to convert a plain parameter value)

     * @param objectName

     *            the objectName of the target object

     * @return the ServletRequestDataBinder instance to use

     * @throws Exception

     *             in case of invalid state or arguments

     * @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest)

     * @see ServletRequestDataBinder#convertIfNecessary(Object, Class<?>,

     *      org.springframework.core.MethodParameter)

     */

    protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) throws Exception {

        return new ServletRequestDataBinder(target, objectName);

    }



    /**

     * Template method for creating a new HttpInputMessage instance.

     * <p>

     * The default implementation creates a standard {@link ServletServerHttpRequest}. This can be overridden for custom {@code HttpInputMessage} implementations

     * @param servletRequest

     *            current HTTP request

     * @return the HttpInputMessage instance to use

     * @throws Exception

     *             in case of errors

     */

    protected HttpInputMessage createHttpInputMessage(HttpServletRequest servletRequest) throws Exception {

        return new ServletServerHttpRequest(servletRequest);

    }



    /**

     * Template method for creating a new HttpOuputMessage instance.

     * <p>

     * The default implementation creates a standard {@link ServletServerHttpResponse}. This can be overridden for custom {@code HttpOutputMessage} implementations

     * @param servletResponse

     *            current HTTP response

     * @return the HttpInputMessage instance to use

     * @throws Exception

     *             in case of errors

     */

    protected HttpOutputMessage createHttpOutputMessage(HttpServletResponse servletResponse) throws Exception {

        return new ServletServerHttpResponse(servletResponse);

    }



    /**

     * Servlet-specific subclass of {@link HandlerMethodResolver}.

     */

    private class ServletHandlerMethodResolver extends HandlerMethodResolver {



        private final Map<Method, RequestMappingInfo> mappings = new HashMap<Method, RequestMappingInfo>();



        private ServletHandlerMethodResolver(Class<?> handlerType) {

            init(handlerType);

        }



        @Override

        protected boolean isHandlerMethod(Method method) {

            if (this.mappings.containsKey(method)) {

                return true;

            }

            RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);

            if (mapping != null) {

                String[] patterns = mapping.value();

                RequestMethod[] methods = new RequestMethod[0];

                String[] params = new String[0];

                String[] headers = new String[0];

                if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) {

                    methods = mapping.method();

                }

                if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) {

                    params = mapping.params();

                }

                if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) {

                    headers = mapping.headers();

                }

                RequestMappingInfo mappingInfo = new RequestMappingInfo(patterns, methods, params, headers);

                this.mappings.put(method, mappingInfo);

                return true;

            }

            return false;

        }



        public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException {

            String lookupPath = urlPathHelper.getLookupPathForRequest(request);

            Comparator<String> pathComparator = pathMatcher.getPatternComparator(lookupPath);

            Map<RequestSpecificMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestSpecificMappingInfo, Method>();

            Set<String> allowedMethods = new LinkedHashSet<String>(7);

            String resolvedMethodName = null;

            for (Method handlerMethod : getHandlerMethods()) {

                RequestSpecificMappingInfo mappingInfo = new RequestSpecificMappingInfo(this.mappings.get(handlerMethod));

                boolean match = false;

                if (mappingInfo.hasPatterns()) {

                    for (String pattern : mappingInfo.getPatterns()) {

                        if (!hasTypeLevelMapping() && !pattern.startsWith("/")) {

                            pattern = "/" + pattern;

                        }

                        String combinedPattern = getCombinedPattern(pattern, lookupPath, request);

                        if (combinedPattern != null) {

                            if (mappingInfo.matches(request)) {

                                match = true;

                                mappingInfo.addMatchedPattern(combinedPattern);

                            } else {

                                if (!mappingInfo.matchesRequestMethod(request)) {

                                    allowedMethods.addAll(mappingInfo.methodNames());

                                }

                                break;

                            }

                        }

                    }

                    mappingInfo.sortMatchedPatterns(pathComparator);

                } else {

                    // No paths specified: parameter match sufficient.

                    match = mappingInfo.matches(request);

                    if (match && mappingInfo.getMethodCount() == 0 && mappingInfo.getParamCount() == 0 && resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) {

                        match = false;

                    } else {

                        if (!mappingInfo.matchesRequestMethod(request)) {

                            allowedMethods.addAll(mappingInfo.methodNames());

                        }

                    }

                }

                if (match) {

                    Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod);

                    if (oldMappedMethod != null && oldMappedMethod != handlerMethod) {

                        if (methodNameResolver != null && !mappingInfo.hasPatterns()) {

                            if (!oldMappedMethod.getName().equals(handlerMethod.getName())) {

                                if (resolvedMethodName == null) {

                                    resolvedMethodName = methodNameResolver.getHandlerMethodName(request);

                                }

                                if (!resolvedMethodName.equals(oldMappedMethod.getName())) {

                                    oldMappedMethod = null;

                                }

                                if (!resolvedMethodName.equals(handlerMethod.getName())) {

                                    if (oldMappedMethod != null) {

                                        targetHandlerMethods.put(mappingInfo, oldMappedMethod);

                                        oldMappedMethod = null;

                                    } else {

                                        targetHandlerMethods.remove(mappingInfo);

                                    }

                                }

                            }

                        }

                        if (oldMappedMethod != null) {

                            throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + lookupPath + "': {" + oldMappedMethod + ", " + handlerMethod + "}. If you intend to handle the same path in multiple methods, then factor "

                                    + "them out into a dedicated handler class with that path mapped at the type level!");

                        }

                    }

                }

            }

            if (!targetHandlerMethods.isEmpty()) {

                List<RequestSpecificMappingInfo> matches = new ArrayList<RequestSpecificMappingInfo>(targetHandlerMethods.keySet());

                RequestSpecificMappingInfoComparator requestMappingInfoComparator = new RequestSpecificMappingInfoComparator(pathComparator, request);

                Collections.sort(matches, requestMappingInfoComparator);

                RequestSpecificMappingInfo bestMappingMatch = matches.get(0);

                String bestMatchedPath = bestMappingMatch.bestMatchedPattern();

                if (bestMatchedPath != null) {

                    extractHandlerMethodUriTemplates(bestMatchedPath, lookupPath, request);

                }

                return targetHandlerMethods.get(bestMappingMatch);

            } else {

                if (!allowedMethods.isEmpty()) {

                    throw new HttpRequestMethodNotSupportedException(request.getMethod(), StringUtils.toStringArray(allowedMethods));

                }

                throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(), request.getParameterMap());

            }

        }



        /**

         * Determines the combined pattern for the given methodLevelPattern and

         * path.

         * <p>

         * Uses the following algorithm:

         * <ol>

         * <li>If there is a type-level mapping with path information, it is {@linkplain PathMatcher#combine(String, String) combined} with the

         * method-level pattern.</li>

         * <li>If there is a {@linkplain HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best

         * matching pattern} in the request, it is combined with the

         * method-level pattern.</li>

         * <li>Otherwise, the method-level pattern is returned.</li>

         * </ol>

         */

        private String getCombinedPattern(String methodLevelPattern, String lookupPath, HttpServletRequest request) {

            if (hasTypeLevelMapping() && (!ObjectUtils.isEmpty(getTypeLevelMapping().value()))) {

                String[] typeLevelPatterns = getTypeLevelMapping().value();

                for (String typeLevelPattern : typeLevelPatterns) {

                    if (!typeLevelPattern.startsWith("/")) {

                        typeLevelPattern = "/" + typeLevelPattern;

                    }

                    String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern);

                    if (isPathMatchInternal(combinedPattern, lookupPath)) {

                        return combinedPattern;

                    }

                }

                return null;

            }

            String bestMatchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);

            if (StringUtils.hasText(bestMatchingPattern) && bestMatchingPattern.endsWith("*")) {

                String combinedPattern = pathMatcher.combine(bestMatchingPattern, methodLevelPattern);

                if (!combinedPattern.equals(bestMatchingPattern) && (isPathMatchInternal(combinedPattern, lookupPath))) {

                    return combinedPattern;

                }

            }

            if (isPathMatchInternal(methodLevelPattern, lookupPath)) {

                return methodLevelPattern;

            }

            return null;

        }



        private boolean isPathMatchInternal(String pattern, String lookupPath) {

            if (pattern.equals(lookupPath) || pathMatcher.match(pattern, lookupPath)) {

                return true;

            }

            boolean hasSuffix = pattern.indexOf('.') != -1;

            if (!hasSuffix && pathMatcher.match(pattern + ".*", lookupPath)) {

                return true;

            }

            boolean endsWithSlash = pattern.endsWith("/");

            if (!endsWithSlash && pathMatcher.match(pattern + "/", lookupPath)) {

                return true;

            }

            return false;

        }



        @SuppressWarnings("unchecked")

        private void extractHandlerMethodUriTemplates(String mappedPattern, String lookupPath, HttpServletRequest request) {



            Map<String, String> variables = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);



            int patternVariableCount = StringUtils.countOccurrencesOf(mappedPattern, "{");



            if ((variables == null || patternVariableCount != variables.size()) && pathMatcher.match(mappedPattern, lookupPath)) {

                variables = pathMatcher.extractUriTemplateVariables(mappedPattern, lookupPath);

                request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, variables);

            }

        }

    }



    /**

     * Servlet-specific subclass of {@link HandlerMethodInvoker}.

     */

    private class ServletHandlerMethodInvoker extends HandlerMethodInvoker {



        private boolean responseArgumentUsed = false;



        private ServletHandlerMethodInvoker(HandlerMethodResolver resolver) {

            super(resolver, webBindingInitializer, sessionAttributeStore, parameterNameDiscoverer, customArgumentResolvers, messageConverters);

        }



        @SuppressWarnings("rawtypes")

        @Override

        protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception {

            throw new MissingServletRequestParameterException(paramName, paramType.getSimpleName());

        }



        @Override

        protected void raiseSessionRequiredException(String message) throws Exception {

            throw new HttpSessionRequiredException(message);

        }



        @Override

        protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) throws Exception {



            return ExtendableHandlerAdapter.this.createBinder(webRequest.getNativeRequest(HttpServletRequest.class), target, objectName);

        }



        @Override

        protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception {

            ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;

            servletBinder.bind(webRequest.getNativeRequest(ServletRequest.class));

        }



        @Override

        protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception {

            HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);

            return ExtendableHandlerAdapter.this.createHttpInputMessage(servletRequest);

        }



        @Override

        protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception {

            HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse();

            return ExtendableHandlerAdapter.this.createHttpOutputMessage(servletResponse);

        }



        @Override

        protected Object resolveDefaultValue(String value) {

            if (beanFactory == null) {

                return value;

            }

            String placeholdersResolved = beanFactory.resolveEmbeddedValue(value);

            BeanExpressionResolver exprResolver = beanFactory.getBeanExpressionResolver();

            if (exprResolver == null) {

                return value;

            }

            return exprResolver.evaluate(placeholdersResolved, expressionContext);

        }



        @SuppressWarnings("rawtypes")

        @Override

        protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) throws Exception {



            HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);

            Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName);

            if (Cookie.class.isAssignableFrom(paramType)) {

                return cookieValue;

            } else if (cookieValue != null) {

                return urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue());

            } else {

                return null;

            }

        }



        @Override

        @SuppressWarnings({ "unchecked" })

        protected String resolvePathVariable(String pathVarName, @SuppressWarnings("rawtypes") Class paramType, NativeWebRequest webRequest) throws Exception {



            HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);

            Map<String, String> uriTemplateVariables = (Map<String, String>) servletRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

            if (uriTemplateVariables == null || !uriTemplateVariables.containsKey(pathVarName)) {

                throw new IllegalStateException("Could not find @PathVariable [" + pathVarName + "] in @RequestMapping");

            }

            return uriTemplateVariables.get(pathVarName);

        }



        @Override

        protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {

            HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

            HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);



            if (ServletRequest.class.isAssignableFrom(parameterType) || MultipartRequest.class.isAssignableFrom(parameterType)) {

                Object nativeRequest = webRequest.getNativeRequest(parameterType);

                if (nativeRequest == null) {

                    throw new IllegalStateException("Current request is not of type [" + parameterType.getName() + "]: " + request);

                }

                return nativeRequest;

            } else if (ServletResponse.class.isAssignableFrom(parameterType)) {

                this.responseArgumentUsed = true;

                Object nativeResponse = webRequest.getNativeResponse(parameterType);

                if (nativeResponse == null) {

                    throw new IllegalStateException("Current response is not of type [" + parameterType.getName() + "]: " + response);

                }

                return nativeResponse;

            } else if (HttpSession.class.isAssignableFrom(parameterType)) {

                return request.getSession();

            } else if (Principal.class.isAssignableFrom(parameterType)) {

                return request.getUserPrincipal();

            } else if (Locale.class.equals(parameterType)) {

                return RequestContextUtils.getLocale(request);

            } else if (InputStream.class.isAssignableFrom(parameterType)) {

                return request.getInputStream();

            } else if (Reader.class.isAssignableFrom(parameterType)) {

                return request.getReader();

            } else if (OutputStream.class.isAssignableFrom(parameterType)) {

                this.responseArgumentUsed = true;

                return response.getOutputStream();

            } else if (Writer.class.isAssignableFrom(parameterType)) {

                this.responseArgumentUsed = true;

                return response.getWriter();

            }

            return super.resolveStandardArgument(parameterType, webRequest);

        }



        @SuppressWarnings({ "unchecked", "rawtypes" })

        public ModelAndView getModelAndView(Method handlerMethod, Class<?> handlerType, Object returnValue, ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception {



            ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class);

            if (responseStatusAnn != null) {

                HttpStatus responseStatus = responseStatusAnn.value();

                String reason = responseStatusAnn.reason();

                if (!StringUtils.hasText(reason)) {

                    webRequest.getResponse().setStatus(responseStatus.value());

                } else {

                    webRequest.getResponse().sendError(responseStatus.value(), reason);

                }



                // to be picked up by the RedirectView

                webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, responseStatus);



                responseArgumentUsed = true;

            }



            // Invoke custom resolvers if present...

            if (customModelAndViewResolvers != null) {

                for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) {

                    ModelAndView mav = mavResolver.resolveModelAndView(handlerMethod, handlerType, returnValue, implicitModel, webRequest);

                    if (mav != ModelAndViewResolver.UNRESOLVED) {

                        return mav;

                    }

                }

            }



            if (returnValue instanceof HttpEntity) {

                handleHttpEntityResponse((HttpEntity<?>) returnValue, webRequest);

                return null;

            } else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {

                handleResponseBody(returnValue, webRequest);

                return null;

            } else if (returnValue instanceof ModelAndView) {

                ModelAndView mav = (ModelAndView) returnValue;

                mav.getModelMap().mergeAttributes(implicitModel);

                return mav;

            } else if (returnValue instanceof Model) {

                return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap());

            } else if (returnValue instanceof View) {

                return new ModelAndView((View) returnValue).addAllObjects(implicitModel);

            } else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) {

                addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);

                return new ModelAndView().addAllObjects(implicitModel);

            } else if (returnValue instanceof Map) {

                return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue);

            } else if (returnValue instanceof String) {

                return new ModelAndView((String) returnValue).addAllObjects(implicitModel);

            } else if (returnValue == null) {

                // Either returned null or was 'void' return.

                if (this.responseArgumentUsed || webRequest.isNotModified()) {

                    return null;

                } else {

                    // Assuming view name translation...

                    return new ModelAndView().addAllObjects(implicitModel);

                }

            } else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) {

                // Assume a single model attribute...

                addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);

                return new ModelAndView().addAllObjects(implicitModel);

            } else {

                throw new IllegalArgumentException("Invalid handler method return value: " + returnValue);

            }

        }



        private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) throws Exception {

            if (returnValue == null) {

                return;

            }

            HttpInputMessage inputMessage = createHttpInputMessage(webRequest);

            HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest);

            writeWithMessageConverters(returnValue, inputMessage, outputMessage);

        }



        @SuppressWarnings("rawtypes")

        private void handleHttpEntityResponse(HttpEntity<?> responseEntity, ServletWebRequest webRequest) throws Exception {

            if (responseEntity == null) {

                return;

            }

            HttpInputMessage inputMessage = createHttpInputMessage(webRequest);

            HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest);

            if (responseEntity instanceof ResponseEntity && outputMessage instanceof ServerHttpResponse) {

                ((ServerHttpResponse) outputMessage).setStatusCode(((ResponseEntity) responseEntity).getStatusCode());

            }

            HttpHeaders entityHeaders = responseEntity.getHeaders();

            if (!entityHeaders.isEmpty()) {

                outputMessage.getHeaders().putAll(entityHeaders);

            }

            Object body = responseEntity.getBody();

            if (body != null) {

                writeWithMessageConverters(body, inputMessage, outputMessage);

            } else {

                // flush headers

                outputMessage.getBody();

            }

        }



        @SuppressWarnings({ "unchecked", "rawtypes" })

        private void writeWithMessageConverters(Object returnValue, HttpInputMessage inputMessage, HttpOutputMessage outputMessage) throws IOException, HttpMediaTypeNotAcceptableException {

            List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();

            if (acceptedMediaTypes.isEmpty()) {

                acceptedMediaTypes = Collections.singletonList(MediaType.ALL);

            }

            MediaType.sortByQualityValue(acceptedMediaTypes);

            Class<?> returnValueType = returnValue.getClass();

            List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();

            if (getMessageConverters() != null) {

                for (MediaType acceptedMediaType : acceptedMediaTypes) {

                    for (HttpMessageConverter messageConverter : getMessageConverters()) {

                        if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {

                            messageConverter.write(returnValue, acceptedMediaType, outputMessage);

                            if (logger.isDebugEnabled()) {

                                MediaType contentType = outputMessage.getHeaders().getContentType();

                                if (contentType == null) {

                                    contentType = acceptedMediaType;

                                }

                                logger.debug("Written [" + returnValue + "] as \"" + contentType + "\" using [" + messageConverter + "]");

                            }

                            this.responseArgumentUsed = true;

                            return;

                        }

                    }

                }

                for (HttpMessageConverter messageConverter : messageConverters) {

                    allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());

                }

            }

            throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);

        }



    }



    /**

     * Holder for request mapping metadata.

     */

    static class RequestMappingInfo {



        private final String[]        patterns;



        private final RequestMethod[] methods;



        private final String[]        params;



        private final String[]        headers;



        RequestMappingInfo(String[] patterns, RequestMethod[] methods, String[] params, String[] headers) {

            this.patterns = patterns != null ? patterns : new String[0];

            this.methods = methods != null ? methods : new RequestMethod[0];

            this.params = params != null ? params : new String[0];

            this.headers = headers != null ? headers : new String[0];

        }



        public boolean hasPatterns() {

            return patterns.length > 0;

        }



        public String[] getPatterns() {

            return patterns;

        }



        public int getMethodCount() {

            return methods.length;

        }



        public int getParamCount() {

            return params.length;

        }



        public int getHeaderCount() {

            return headers.length;

        }



        public boolean matches(HttpServletRequest request) {

            return matchesRequestMethod(request) && matchesParameters(request) && matchesHeaders(request);

        }



        public boolean matchesHeaders(HttpServletRequest request) {

            return ServletAnnotationMappingUtils.checkHeaders(this.headers, request);

        }



        public boolean matchesParameters(HttpServletRequest request) {

            return ServletAnnotationMappingUtils.checkParameters(this.params, request);

        }



        public boolean matchesRequestMethod(HttpServletRequest request) {

            return ServletAnnotationMappingUtils.checkRequestMethod(this.methods, request);

        }



        public Set<String> methodNames() {

            Set<String> methodNames = new LinkedHashSet<String>(methods.length);

            for (RequestMethod method : methods) {

                methodNames.add(method.name());

            }

            return methodNames;

        }



        @Override

        public boolean equals(Object obj) {

            RequestMappingInfo other = (RequestMappingInfo) obj;

            return (Arrays.equals(this.patterns, other.patterns) && Arrays.equals(this.methods, other.methods) && Arrays.equals(this.params, other.params) && Arrays.equals(this.headers, other.headers));

        }



        @Override

        public int hashCode() {

            return (Arrays.hashCode(this.patterns) * 23 + Arrays.hashCode(this.methods) * 29 + Arrays.hashCode(this.params) * 31 + Arrays.hashCode(this.headers));

        }



        @Override

        public String toString() {

            StringBuilder builder = new StringBuilder();

            builder.append(Arrays.asList(patterns));

            if (methods.length > 0) {

                builder.append(',');

                builder.append(Arrays.asList(methods));

            }

            if (headers.length > 0) {

                builder.append(',');

                builder.append(Arrays.asList(headers));

            }

            if (params.length > 0) {

                builder.append(',');

                builder.append(Arrays.asList(params));

            }

            return builder.toString();

        }

    }



    /**

     * Subclass of {@link RequestMappingInfo} that holds request-specific data.

     */

    static class RequestSpecificMappingInfo extends RequestMappingInfo {



        private final List<String> matchedPatterns = new ArrayList<String>();



        RequestSpecificMappingInfo(String[] patterns, RequestMethod[] methods, String[] params, String[] headers) {

            super(patterns, methods, params, headers);

        }



        RequestSpecificMappingInfo(RequestMappingInfo other) {

            super(other.patterns, other.methods, other.params, other.headers);

        }



        public void addMatchedPattern(String matchedPattern) {

            matchedPatterns.add(matchedPattern);

        }



        public void sortMatchedPatterns(Comparator<String> pathComparator) {

            Collections.sort(matchedPatterns, pathComparator);

        }



        public String bestMatchedPattern() {

            return (!this.matchedPatterns.isEmpty() ? this.matchedPatterns.get(0) : null);

        }

    }



    /**

     * Comparator capable of sorting {@link RequestSpecificMappingInfo}s (RHIs)

     * so that sorting a list with this comparator will result in:

     * <ul>

     * <li>RHIs with {@linkplain AnnotationMethodHandlerAdapter.RequestSpecificMappingInfo#matchedPatterns

     * better matched paths} take prescedence over those with a weaker match (as

     * expressed by the {@linkplain PathMatcher#getPatternComparator(String)

     * path pattern comparator}.) Typically, this means that patterns without

     * wild cards and uri templates will be ordered before those without.</li>

     * <li>RHIs with one single {@linkplain RequestMappingInfo#methods request

     * method} will be ordered before those without a method, or with more than

     * one method.</li>

     * <li>RHIs with more {@linkplain RequestMappingInfo#params request

     * parameters} will be ordered before those with less parameters</li> </ol>

     */

    static class RequestSpecificMappingInfoComparator implements Comparator<RequestSpecificMappingInfo> {



        private final Comparator<String> pathComparator;



        private final ServerHttpRequest  request;



        RequestSpecificMappingInfoComparator(Comparator<String> pathComparator, HttpServletRequest request) {

            this.pathComparator = pathComparator;

            this.request = new ServletServerHttpRequest(request);

        }



        public int compare(RequestSpecificMappingInfo info1, RequestSpecificMappingInfo info2) {

            int pathComparison = pathComparator.compare(info1.bestMatchedPattern(), info2.bestMatchedPattern());

            if (pathComparison != 0) {

                return pathComparison;

            }

            int info1ParamCount = info1.getParamCount();

            int info2ParamCount = info2.getParamCount();

            if (info1ParamCount != info2ParamCount) {

                return info2ParamCount - info1ParamCount;

            }

            int info1HeaderCount = info1.getHeaderCount();

            int info2HeaderCount = info2.getHeaderCount();

            if (info1HeaderCount != info2HeaderCount) {

                return info2HeaderCount - info1HeaderCount;

            }

            int acceptComparison = compareAcceptHeaders(info1, info2);

            if (acceptComparison != 0) {

                return acceptComparison;

            }

            int info1MethodCount = info1.getMethodCount();

            int info2MethodCount = info2.getMethodCount();

            if (info1MethodCount == 0 && info2MethodCount > 0) {

                return 1;

            } else if (info2MethodCount == 0 && info1MethodCount > 0) {

                return -1;

            } else if (info1MethodCount == 1 & info2MethodCount > 1) {

                return -1;

            } else if (info2MethodCount == 1 & info1MethodCount > 1) {

                return 1;

            }

            return 0;

        }



        private int compareAcceptHeaders(RequestMappingInfo info1, RequestMappingInfo info2) {

            List<MediaType> requestAccepts = request.getHeaders().getAccept();

            MediaType.sortByQualityValue(requestAccepts);



            List<MediaType> info1Accepts = getAcceptHeaderValue(info1);

            List<MediaType> info2Accepts = getAcceptHeaderValue(info2);



            for (MediaType requestAccept : requestAccepts) {

                int pos1 = indexOfIncluded(info1Accepts, requestAccept);

                int pos2 = indexOfIncluded(info2Accepts, requestAccept);

                if (pos1 != pos2) {

                    return pos2 - pos1;

                }

            }

            return 0;

        }



        private int indexOfIncluded(List<MediaType> infoAccepts, MediaType requestAccept) {

            for (int i = 0; i < infoAccepts.size(); i++) {

                MediaType info1Accept = infoAccepts.get(i);

                if (requestAccept.includes(info1Accept)) {

                    return i;

                }

            }

            return -1;

        }



        private List<MediaType> getAcceptHeaderValue(RequestMappingInfo info) {

            for (String header : info.headers) {

                int separator = header.indexOf('=');

                if (separator != -1) {

                    String key = header.substring(0, separator);

                    String value = header.substring(separator + 1);

                    if ("Accept".equalsIgnoreCase(key)) {

                        return MediaType.parseMediaTypes(value);

                    }

                }

            }

            return Collections.emptyList();

        }

    }



    static class ServletAnnotationMappingUtils {



        /**

         * Check whether the given request matches the specified request

         * methods.

         * @param methods

         *            the HTTP request methods to check against

         * @param request

         *            the current HTTP request to check

         */

        public static boolean checkRequestMethod(RequestMethod[] methods, HttpServletRequest request) {

            if (ObjectUtils.isEmpty(methods)) {

                return true;

            }

            for (RequestMethod method : methods) {

                if (method.name().equals(request.getMethod())) {

                    return true;

                }

            }

            return false;

        }



        /**

         * Check whether the given request matches the specified parameter

         * conditions.

         * @param params

         *            the parameter conditions, following {@link RequestMapping#params()}

         * @param request

         *            the current HTTP request to check

         */

        public static boolean checkParameters(String[] params, HttpServletRequest request) {

            if (!ObjectUtils.isEmpty(params)) {

                for (String param : params) {

                    int separator = param.indexOf('=');

                    if (separator == -1) {

                        if (param.startsWith("!")) {

                            if (WebUtils.hasSubmitParameter(request, param.substring(1))) {

                                return false;

                            }

                        } else if (!WebUtils.hasSubmitParameter(request, param)) {

                            return false;

                        }

                    } else {

                        String key = param.substring(0, separator);

                        String value = param.substring(separator + 1);

                        if (!value.equals(request.getParameter(key))) {

                            return false;

                        }

                    }

                }

            }

            return true;

        }



        /**

         * Check whether the given request matches the specified header

         * conditions.

         * @param headers

         *            the header conditions, following {@link RequestMapping#headers()}

         * @param request

         *            the current HTTP request to check

         */

        public static boolean checkHeaders(String[] headers, HttpServletRequest request) {

            if (!ObjectUtils.isEmpty(headers)) {

                for (String header : headers) {

                    int separator = header.indexOf('=');

                    if (separator == -1) {

                        if (header.startsWith("!")) {

                            if (request.getHeader(header.substring(1)) != null) {

                                return false;

                            }

                        } else if (request.getHeader(header) == null) {

                            return false;

                        }

                    } else {

                        String key = header.substring(0, separator);

                        String value = header.substring(separator + 1);

                        if (isMediaTypeHeader(key)) {

                            List<MediaType> requestMediaTypes = MediaType.parseMediaTypes(request.getHeader(key));

                            List<MediaType> valueMediaTypes = MediaType.parseMediaTypes(value);

                            boolean found = false;

                            for (Iterator<MediaType> valIter = valueMediaTypes.iterator(); valIter.hasNext() && !found;) {

                                MediaType valueMediaType = valIter.next();

                                for (Iterator<MediaType> reqIter = requestMediaTypes.iterator(); reqIter.hasNext() && !found;) {

                                    MediaType requestMediaType = reqIter.next();

                                    if (valueMediaType.includes(requestMediaType)) {

                                        found = true;

                                    }

                                }



                            }

                            if (!found) {

                                return false;

                            }

                        } else if (!value.equals(request.getHeader(key))) {

                            return false;

                        }

                    }

                }

            }

            return true;

        }



        private static boolean isMediaTypeHeader(String headerName) {

            return "Accept".equalsIgnoreCase(headerName) || "Content-Type".equalsIgnoreCase(headerName);

        }



    }



}


2.定义拦截器接口,上面的代码428行已写了类型名称IHandlerInterceptor

 

 

package com.test.interceptor;





import java.lang.reflect.Method;



import org.springframework.web.context.request.ServletWebRequest;



/**

 * @author zhipeng.qzp

 */

public interface IHandlerInterceptor {



    public void preInvoke(Method handlerMethod, Object handler, ServletWebRequest webRequest) throws Exception;



    public void postInvoke(Method handlerMethod, Object handler, ServletWebRequest webRequest, Object handlerReturn) throws Exception;



}


3.写一个具体的拦截器,实现接口的方法

 

 

/**

 * API访问权限验证拦截器

 * @author zhipeng.qzp

 */

public class ApiAuthInterceptor implements IHandlerInterceptor {



    @Override

    public void preInvoke(Method handlerMethod, Object handler, ServletWebRequest webRequest) throws ReturnBoException {

        /* 接口request参数检查 */

        HttpServletRequest request = (HttpServletRequest) webRequest.getRequest();

        try {

            //TODO 权限检查

        }

        finally {

            //TODO log

        }

        system.out.println("preInvoke");

    }



    @Override

    public void postInvoke(Method handlerMethod, Object handler, ServletWebRequest webRequest, Object handlerReturn) {

        //TODO log

        system.out.println("postInvoke");

    }



}

 

4.Spring xml配置

 

<bean class="com.test.interceptor.ExtendableHandlerAdapter">

		<property name="invokeInterceptors">

			<list>

				<bean class="com.test.interceptor.ApiAuthInterceptor" />

			</list>

		</property>

	</bean>


5.完工了,运行下就可以看到打出了两个print字符串,在postInvoke中可以通过handlerReturn拿到方法的结果。

 

 

 

 

 

你可能感兴趣的:(spring mvc)