`
jiangshaolin
  • 浏览: 57246 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

spring mvc3.0权限控制

阅读更多
新项目中用到了Spring mvc3.0,之后又升级到3.0.4,因为对静态资源处理有更好支持

<mvc:resources location="/css/" mapping="/css/**" />


spring mvc 3.0最大的特别即是对restful url很友好的支持。但也带来很多不便的地方,比如权限控制。
部分人提出思路例如:
https://jira.springframework.org/browse/SPR-5763
https://jira.springframework.org/browse/SPR-7451

花不少时间阅读源码,发现根本无法扩展对方法级别的控制,也就是使Controller层失去了面向对象的特征,惨!不知道作者是怎么想的,Juergen Hoeller!恨死你了,居然不留一点扩展的余地,要自己写过滤和匹配映射规则虽然能行,但没必要去repeat ,最后无耐Copy源码,修改一翻,想怎么控制就怎么控制了。

总结:
     在一个项目组中,如果要使用新技术,必须要有一个人精通,碰到任何问题都能解决,否则,千万不能用新技术。

spring 配置文件如下:
<bean class="com.jquickwork.extend.AnnotationMethodHandlerAdapter">
		<property name="permissionService">
			<bean class="com.******.manage.web.common.service.PermissionServiceImpl">
				<property name="rightService" ref="RightService"></property>
				<property name="test" value="false" />
			</bean>
		</property>
	</bean>



修改源码后的 AnnotationMethodHandlerAdapter类如下:

/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jquickwork.extend;

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 java.util.concurrent.ConcurrentHashMap;
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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.InitBinder;
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.RequestParam;
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.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;

import com.tuankela.manage.web.common.service.PermissionException;
import com.tuankela.manage.web.common.service.PermissionService;

/**
 * Implementation of the {@link org.springframework.web.servlet.HandlerAdapter} interface
 * that maps handler methods based on HTTP paths, HTTP methods and request parameters
 * expressed through the {@link RequestMapping} annotation.
 *
 * <p>Supports request parameter binding through the {@link RequestParam} annotation.
 * Also supports the {@link ModelAttribute} annotation for exposing model attribute
 * values to the view, as well as {@link InitBinder} for binder initialization methods
 * and {@link SessionAttributes} for automatic session management of specific attributes.
 *
 * <p>This adapter can be customized through various bean properties.
 * A common use case is to apply shared binder initialization logic through
 * a custom {@link #setWebBindingInitializer WebBindingInitializer}.
 *
 * @author Juergen Hoeller
 * @author Arjen Poutsma
 * @since 2.5
 * @see #setPathMatcher
 * @see #setMethodNameResolver
 * @see #setWebBindingInitializer
 * @see #setSessionAttributeStore
 */
public class AnnotationMethodHandlerAdapter extends WebContentGenerator
		implements HandlerAdapter, Ordered, BeanFactoryAware {

	private PermissionService permissionService;
	/**
	 * 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 Log pageNotFoundLogger = LogFactory.getLog(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.LOWEST_PRECEDENCE;

	private ConfigurableBeanFactory beanFactory;

	private BeanExpressionContext expressionContext;

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


	public AnnotationMethodHandlerAdapter() {
		// no restriction of HTTP methods by default
		super(false);

		// See SPR-7316
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setWriteAcceptCharset(false);
		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 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 invokeHandlerMethod(request, response, handler);
				}
			}
		}

		return invokeHandlerMethod(request, response, handler);
	}

	protected ModelAndView invokeHandlerMethod(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();

		Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
		ModelAndView mav =
				methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
		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) {
		Class handlerClass = ClassUtils.getUserClass(handler);
		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) {
				RequestMappingInfo mappingInfo = new RequestMappingInfo();
				mappingInfo.patterns = mapping.value();
				if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) {
					mappingInfo.methods = mapping.method();
				}
				if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) {
					mappingInfo.params = mapping.params();
				}
				if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) {
					mappingInfo.headers = mapping.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<RequestMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestMappingInfo, Method>();
			Set<String> allowedMethods = new LinkedHashSet<String>(7);
			String resolvedMethodName = null;
			for (Method handlerMethod : getHandlerMethods()) {
				RequestMappingInfo mappingInfo = this.mappings.get(handlerMethod);
				boolean match = false;
				if (mappingInfo.hasPatterns()) {
					List<String> matchingPatterns = new ArrayList<String>(mappingInfo.patterns.length);
					for (String pattern : mappingInfo.patterns) {
						if (!hasTypeLevelMapping() && !pattern.startsWith("/")) {
							pattern = "/" + pattern;
						}
						String combinedPattern = getCombinedPattern(pattern, lookupPath, request);
						if (combinedPattern != null) {
							if (mappingInfo.matches(request)) {
								match = true;
								matchingPatterns.add(combinedPattern);
							}
							else {
								if (!mappingInfo.matchesRequestMethod(request)) {
									allowedMethods.addAll(mappingInfo.methodNames());
								}
								break;
							}
						}
					}
					Collections.sort(matchingPatterns, pathComparator);
					mappingInfo.matchedPatterns = matchingPatterns;
				}
				else {
					// No paths specified: parameter match sufficient.
					match = mappingInfo.matches(request);
					if (match && mappingInfo.methods.length == 0 && mappingInfo.params.length == 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.patterns.length == 0) {
							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<RequestMappingInfo> matches = new ArrayList<RequestMappingInfo>(targetHandlerMethods.keySet());
				RequestMappingInfoComparator requestMappingInfoComparator =
						new RequestMappingInfoComparator(pathComparator, request);
				Collections.sort(matches, requestMappingInfoComparator);
				RequestMappingInfo bestMappingMatch = matches.get(0);
				String bestMatchedPath = bestMappingMatch.bestMatchedPattern();
				if (bestMatchedPath != null) {
					//validate permission
					permissionService.isPermit(request, bestMatchedPath ,bestMappingMatch.patterns[0]);
					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);
		}

		@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 AnnotationMethodHandlerAdapter.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 AnnotationMethodHandlerAdapter.this.createHttpInputMessage(servletRequest);
		}

        @Override
		protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception {
			HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse();
			return AnnotationMethodHandlerAdapter.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);
		}

		@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, 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")
		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);
		}

		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")
		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. Allows for finding a best matching candidate.
	 */
	static class RequestMappingInfo {

		String[] patterns = new String[0];

		List<String> matchedPatterns = Collections.emptyList();

		RequestMethod[] methods = new RequestMethod[0];

		String[] params = new String[0];

		String[] headers = new String[0];

		public boolean hasPatterns() {
			return patterns.length > 0;
		}

		public String bestMatchedPattern() {
			return (!this.matchedPatterns.isEmpty() ? this.matchedPatterns.get(0) : null);
		}

		public boolean matches(HttpServletRequest request) {
			return matchesRequestMethod(request) && matchesParameters(request) && matchesHeaders(request);
		}

		public boolean matchesHeaders(HttpServletRequest request) {
			return checkHeaders(this.headers, request);
		}

		public boolean matchesParameters(HttpServletRequest request) {
			return checkParameters(this.params, request);
		}

		public boolean matchesRequestMethod(HttpServletRequest request) {
			return 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();
		}
	}


	/**
	 * Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will
	 * result in:
	 * <ul>
	 * <li>RHIs with {@linkplain RequestMappingInfo#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 RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {

		private final Comparator<String> pathComparator;

		private final ServerHttpRequest request;

		RequestMappingInfoComparator(Comparator<String> pathComparator, HttpServletRequest request) {
			this.pathComparator = pathComparator;
			this.request = new ServletServerHttpRequest(request);
		}

		public int compare(RequestMappingInfo info1, RequestMappingInfo info2) {
			int pathComparison = pathComparator.compare(info1.bestMatchedPattern(), info2.bestMatchedPattern());
			if (pathComparison != 0) {
				return pathComparison;
			}
			int info1ParamCount = info1.params.length;
			int info2ParamCount = info2.params.length;
			if (info1ParamCount != info2ParamCount) {
				return info2ParamCount - info1ParamCount;
			}
			int info1HeaderCount = info1.headers.length;
			int info2HeaderCount = info2.headers.length;
			if (info1HeaderCount != info2HeaderCount) {
				return info2HeaderCount - info1HeaderCount;
			}
			int acceptComparison = compareAcceptHeaders(info1, info2);
			if (acceptComparison != 0) {
				return acceptComparison;
			}
			int info1MethodCount = info1.methods.length;
			int info2MethodCount = info2.methods.length;
			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();
		}
	}

	
	
	
	
	///----------------------org.springframework.web.servlet.mvc.annotation.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);
	}


	public void setPermissionService(PermissionService permissionService) {
		this.permissionService = permissionService;
	}
}



分享到:
评论
23 楼 wwjjkk 2011-12-28  
wwjjkk 写道
AnnotationMethodHandlerAdapter里面有个customArgumentResolvers..

呃,看错了,当我什么也没错
22 楼 wwjjkk 2011-12-28  
AnnotationMethodHandlerAdapter里面有个customArgumentResolvers..
21 楼 tq02ksu 2010-12-23  
anyin89 写道


这句话非常好,本来准备学习spring应用在新项目上,看来还是不要搞为好


spring 还是用的很普遍的. 不用就OUT了.
20 楼 jelver 2010-12-07  
,支持,不过不能动不动就搞几百行代码上来,选关键的就行了
19 楼 jiangshaolin 2010-12-07  
leiyuch 写道
在需要权限控制的方法上加上自定义注解
Override preHandle方法 加入自己的判断
大概应该是下面这样的代码
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
for (Annotation annotation : handlerMethod.getAnnotations())
  {
    if (annotation instanceof NeedSession)
                {


原本:A直接关联B
你的做法是:A关联C再用C关联B,何必呢?
18 楼 jiangshaolin 2010-12-07  
freesea 写道
the type SimpleFormController is deprecated
借问一下,为什么不推荐使用SimpleFormController呢



这个用不到spring mvc3.0的注解新特性。
17 楼 freesea 2010-12-07  
the type SimpleFormController is deprecated
借问一下,为什么不推荐使用SimpleFormController呢
16 楼 leiyuch 2010-12-07  
在需要权限控制的方法上加上自定义注解
Override preHandle方法 加入自己的判断
大概应该是下面这样的代码
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
for (Annotation annotation : handlerMethod.getAnnotations())
  {
    if (annotation instanceof NeedSession)
                {
15 楼 leiyuch 2010-12-07  
如果不想使用spring security,写一个类继承HandlerInterceptorAdapter
同时配置
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
14 楼 caoyangx 2010-12-06  
spring security不能满足你?
下一次可能会有用struts做持久化的文章出现。
13 楼 jiangshaolin 2010-11-30  
grandboy 写道
没有看出来比自己写一个filter或者其他方式好在哪里, 有什么特别考虑请具体指出.修改了源码,对升级不是什么好主意.个人还是觉得写一个filter比较简单.



如果你用了springmvc3.0里面的路径变量特性,你一定要写正则表达式,而我在文章中已经提到,
引用
要自己写过滤和匹配映射规则虽然能行,但没必要去repeat


所以你没必要去写正则了,因为他那里面已经写了跟你类似的工作,源码改动不大。万一要用更高级springmvc的版本特性,你只需花几分钟,大可再改一次,但这种需求,估计一年以内是碰不到的。

开源的东西最大的好处即为,在需要的时候能查看和修改源码。

p.s.  此Class应该为springmvc3.0新特性的核心部分,所以略显复杂。
12 楼 grandboy 2010-11-29  
没有看出来比自己写一个filter或者其他方式好在哪里, 有什么特别考虑请具体指出.修改了源码,对升级不是什么好主意.个人还是觉得写一个filter比较简单.
11 楼 bossdai 2010-11-29  
咱们用的浅 只会了点依赖注入 aop用到项目中就够了 权限还是用的自己写代码去控制的
10 楼 beihan007 2010-11-27  
这一大篇代码看到我两眼发直。。。。
9 楼 grave 2010-11-25  
用Spring Security吧..
8 楼 jiangshaolin 2010-11-25  
redwave 写道
楼主,恨死你了!帖了一堆源码

方法级的权限控制我是用AOP实现的,方法之前加个自定义的注释


兄弟,请看代码的621行,这个地方就是关键点。不理解请站内信。
7 楼 redwave 2010-11-25  
楼主,恨死你了!帖了一堆源码

方法级的权限控制我是用AOP实现的,方法之前加个自定义的注释
6 楼 jiangshaolin 2010-10-12  
<div class="quote_title">dominic6988 写道</div>
<div class="quote_div">
<p>这么长的代码有几个人有耐心看完啊</p>
</div>
<p>不要把所有代码都仔细看完,看几个关键点,等会我用红色把它标出来。</p>
5 楼 dominic6988 2010-10-12  
<p>这么长的代码有几个人有耐心看完啊</p>

相关推荐

    springmvc3.0

    Spring MVC 3.0是Spring框架的一个重要组成部分,专门用于构建Web应用程序的模型-视图-控制器(MVC)架构。这个版本引入了许多增强功能,提高了开发效率和灵活性。结合Hibernate,一个流行的Java持久化框架,可以...

    Spring-MVC-3.0.rar_Java spring mvc_spring mvc_spring ppt

    4. **MVC interceptors**:拦截器允许在请求处理前后执行自定义逻辑,用于权限控制、日志记录等场景。 5. **HandlerExceptionResolvers**:异常处理器,用于统一处理Controller抛出的异常。 6. **Tiles view ...

    spring3.0Mvc简单示例

    Spring 3.0 MVC 是一个基于Java的企业级框架,用于构建Web应用程序,特别是控制器、视图和模型组件的分离。这个“spring3.0Mvc简单示例”旨在帮助开发者快速理解并入门Spring MVC的基本概念和操作流程。让我们深入...

    spring3.0MVC中文教程

    通过这个Spring 3.0 MVC中文教程,你将学习到如何配置Spring MVC环境,创建控制器,处理请求,进行数据绑定和验证,以及如何利用拦截器和视图解析器优化你的Web应用。实践案例会帮助你更好地理解和应用这些概念,...

    Spring3.0MVC注解(附实例)

    在Spring 3.0中,Spring MVC引入了强大的注解支持,使得开发Web应用程序变得更加简洁高效。本节将深入探讨Spring MVC注解及其在实际应用中的实现方式。 首先,Spring MVC注解允许开发者以声明式的方式配置控制器,...

    Spring_MVC_3.0实战指南

    此外,书中还会讲解如何集成其他Spring模块,如Spring Security进行权限控制,以及与MyBatis或Hibernate等持久层框架的整合。 总之,《Spring_MVC_3.0实战指南》是学习和掌握Spring MVC 3.0不可或缺的资源,无论你...

    springMVC+springSecurity3.0+maven

    这个版本提供了认证和授权功能,可以实现用户的登录、权限控制、会话管理等。Spring Security可以轻松集成到Spring MVC中,通过配置安全拦截器,对特定的URL进行访问控制,确保只有经过身份验证和授权的用户才能访问...

    使用spring mvc portlet 3.0开发IBM WebSphere Portlet应用

    你可能会用到Spring的AOP(面向切面编程)来实现事务管理,以及Spring Security来控制portlet的访问权限。 总结一下,使用Spring MVC Portlet 3.0开发IBM WebSphere Portlet应用涉及的主要知识点有: - Portlet 3.0...

    Mastering Spring MVC 4(2015.09)源码

    首先,Spring MVC 4基于Servlet 3.0规范,这意味着它可以利用异步处理能力,提高了Web应用的性能。通过AsyncSupport和AsyncConfigurer接口,开发者可以轻松地创建异步控制器,处理高并发场景。 控制器(Controller...

    Spring mvc 教程

    - **Servlet 3.0 下的 MultipartResolver**:对于 Servlet 3.0 及以上版本,Spring MVC 提供了内置的文件上传支持。 - **处理表单中的文件上传**:通过控制器方法来接收和处理上传的文件。 #### 异常处理 ...

    spring security3.0所需要的最精简的jar包

    Spring Security 是一...总之,Spring Security 3.0提供了一套完整的安全解决方案,其核心组件包括了认证、授权、Web安全和对象级别的权限控制。理解和掌握这些jar包的功能,能够帮助开发者有效地构建安全的应用程序。

    SpringSecurity3.0 Demo

    此外,它还支持与其他Spring模块的无缝集成,如Spring MVC、Spring Data等,使得在企业级应用中实现全面的安全控制变得更加容易。 总的来说,"SpringSecurity3.0 Demo"项目是一个深入学习和实践SpringSecurity的好...

    spring security3.0 demo

    4. **Role-Based Access Control (RBAC)**:Spring Security支持基于角色的访问控制,允许我们为不同的用户角色分配特定的权限。 5. **Remember Me**:Spring Security还提供了记住我(Remember-Me)服务,使用户在...

    Spring MVC 文件上传下载 后端 - Java.zip

    1. **Spring MVC 框架**:Spring MVC是Spring框架的一部分,它提供了一个用于构建Web应用的模型-视图-控制器(MVC)架构。通过使用DispatcherServlet、Controllers、Models、Views等组件,Spring MVC简化了处理HTTP...

    Spring MVC(2)

    Spring MVC结合Spring的AOP模块,可以方便地实现日志记录、权限控制、事务管理等功能。通过定义切点和通知,可以在不修改业务代码的情况下,实现对特定行为的拦截和处理。 九、单元测试与集成测试 Spring MVC提供了...

    J2EE spring mvc mybatis bootstrap HTML5 后台框架 控制台 mysql版本_spring3.0

    【源码】mysql版本_spring3.0 系统模块 1. 组织管理:角色管理,分角色组和成员,有组权限和成员权限。 2. 系统用户:对各个基本的组会员增删改查,单发、群发邮件短信,导入导出excel表格,批量删除 3. 会员管理:...

    spring mvc3 学习资料

    - 注解式控制器是Spring 3.0引入的,用于简化Spring MVC的控制器实现。 - 本部分内容详细介绍如何使用@Controller、@RequestMapping等注解来定义控制器,处理请求映射,以及如何定义返回值等。 7. 请求映射规则...

    Spring3.0就这么简单源码

    - **AOP**:提供面向切面编程,用于日志记录、事务管理、权限控制等跨切面关注点的处理。 - **数据访问**:支持多种数据访问技术,如JDBC、Hibernate、MyBatis等,提供事务管理、数据源配置等高级功能。 - **MVC**...

    spring3.0MVC注解(附实例).docx

    - 示例中的`SessionInterceptor`和`SuperUserInterceptor`是自定义的拦截器,它们可以添加到Spring MVC的处理链中,用于执行请求处理前后的额外逻辑,比如检查用户会话或权限验证。 在配置Spring MVC以支持注解时...

    spring3.0MVC注解(附实例).pdf

    Spring 3.0 的 MVC 框架引入了大量的注解,极大地简化了Web应用程序的开发。这些注解允许开发者在控制器类和方法级别声明路由、数据绑定和其他功能,而无需编写大量的XML配置。本篇文章将深入探讨Spring 3.0 MVC中的...

Global site tag (gtag.js) - Google Analytics