- 浏览: 57519 次
- 性别:
- 来自: 长沙
文章分类
最新评论
-
springaop_springmvc:
spring mvc demo教程源代码下载,地址:http: ...
spring mvc3.0权限控制 -
wwjjkk:
<div class="quote_title ...
spring mvc3.0权限控制 -
wwjjkk:
AnnotationMethodHandlerAdapter里 ...
spring mvc3.0权限控制 -
Durian:
投隐藏的都不厚道,javaeye处处体现了歧视,侮辱和群殴。
...
喜欢吉他的程序员 -
ray_linn:
直接隐藏之
喜欢吉他的程序员
新项目中用到了Spring mvc3.0,之后又升级到3.0.4,因为对静态资源处理有更好支持
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 配置文件如下:
修改源码后的 AnnotationMethodHandlerAdapter类如下:
呃,看错了,当我什么也没错
这句话非常好,本来准备学习spring应用在新项目上,看来还是不要搞为好
spring 还是用的很普遍的. 不用就OUT了.
原本:A直接关联B
你的做法是:A关联C再用C关联B,何必呢?
这个用不到spring mvc3.0的注解新特性。
如果你用了springmvc3.0里面的路径变量特性,你一定要写正则表达式,而我在文章中已经提到,
所以你没必要去写正则了,因为他那里面已经写了跟你类似的工作,源码改动不大。万一要用更高级springmvc的版本特性,你只需花几分钟,大可再改一次,但这种需求,估计一年以内是碰不到的。
开源的东西最大的好处即为,在需要的时候能查看和修改源码。
p.s. 此Class应该为springmvc3.0新特性的核心部分,所以略显复杂。
兄弟,请看代码的621行,这个地方就是关键点。不理解请站内信。
<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; } }
评论
24 楼
springaop_springmvc
2015-08-16
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)
{
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呢
借问一下,为什么不推荐使用SimpleFormController呢
这个用不到spring mvc3.0的注解新特性。
17 楼
freesea
2010-12-07
the type SimpleFormController is deprecated
借问一下,为什么不推荐使用SimpleFormController呢
借问一下,为什么不推荐使用SimpleFormController呢
16 楼
leiyuch
2010-12-07
在需要权限控制的方法上加上自定义注解
Override preHandle方法 加入自己的判断
大概应该是下面这样的代码
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
for (Annotation annotation : handlerMethod.getAnnotations())
{
if (annotation instanceof NeedSession)
{
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">
同时配置
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
14 楼
caoyangx
2010-12-06
spring security不能满足你?
下一次可能会有用struts做持久化的文章出现。
下一次可能会有用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实现的,方法之前加个自定义的注释
方法级的权限控制我是用AOP实现的,方法之前加个自定义的注释
兄弟,请看代码的621行,这个地方就是关键点。不理解请站内信。
7 楼
redwave
2010-11-25
楼主,恨死你了!帖了一堆源码
方法级的权限控制我是用AOP实现的,方法之前加个自定义的注释
方法级的权限控制我是用AOP实现的,方法之前加个自定义的注释
6 楼
jiangshaolin
2010-10-12
<div class="quote_title">dominic6988 写道</div>
<div class="quote_div">
<p>这么长的代码有几个人有耐心看完啊</p>
</div>
<p>不要把所有代码都仔细看完,看几个关键点,等会我用红色把它标出来。</p>
<div class="quote_div">
<p>这么长的代码有几个人有耐心看完啊</p>
</div>
<p>不要把所有代码都仔细看完,看几个关键点,等会我用红色把它标出来。</p>
5 楼
dominic6988
2010-10-12
<p>这么长的代码有几个人有耐心看完啊</p>
发表评论
-
Spring笔记
2012-12-04 15:07 0Bean初始化步骤 1:构造程序或者工厂方法创建Bean实例 ... -
Iterator.next()做参数的问题
2011-12-15 19:18 920java中,以下代码无法正确运行。 Iterator it ... -
《代码大全2》随思一
2011-07-30 09:32 1083我不打算把《代码大全2》从头到尾一字不漏的看一遍,真没必要,只 ... -
java中final类型的初始化问题
2011-03-05 17:52 1954今日读到开源项目中一段源代码,发现对final类型的field ... -
关于Base64工具类并发问题
2010-12-09 09:50 3128为减少对象创建次数,一般会做如下编码: package ... -
关于url映射
2010-03-05 22:56 1827最近在新项目中想使用一个映射规则,如下: URL映射过程(严格 ... -
浏览Jdon网站发现一篇好文章
2009-01-17 20:37 1165引用 yinyousong: 很多程 ... -
javaeye网站有问题
2008-07-30 10:39 966打开javaeye网站的时候,有时候,只要鼠标一动,整个屏幕就 ... -
SSH整合出错,折腾了好几天了,请教一下各位兄弟,感激不尽
2008-04-19 01:38 1230java.lang.NullPointerException ...
相关推荐
Spring MVC 3.0是Spring框架的一个重要组成部分,专门用于构建Web应用程序的模型-视图-控制器(MVC)架构。这个版本引入了许多增强功能,提高了开发效率和灵活性。结合Hibernate,一个流行的Java持久化框架,可以...
4. **MVC interceptors**:拦截器允许在请求处理前后执行自定义逻辑,用于权限控制、日志记录等场景。 5. **HandlerExceptionResolvers**:异常处理器,用于统一处理Controller抛出的异常。 6. **Tiles view ...
Spring 3.0 MVC 是一个基于Java的企业级框架,用于构建Web应用程序,特别是控制器、视图和模型组件的分离。这个“spring3.0Mvc简单示例”旨在帮助开发者快速理解并入门Spring MVC的基本概念和操作流程。让我们深入...
通过这个Spring 3.0 MVC中文教程,你将学习到如何配置Spring MVC环境,创建控制器,处理请求,进行数据绑定和验证,以及如何利用拦截器和视图解析器优化你的Web应用。实践案例会帮助你更好地理解和应用这些概念,...
在Spring 3.0中,Spring MVC引入了强大的注解支持,使得开发Web应用程序变得更加简洁高效。本节将深入探讨Spring MVC注解及其在实际应用中的实现方式。 首先,Spring MVC注解允许开发者以声明式的方式配置控制器,...
此外,书中还会讲解如何集成其他Spring模块,如Spring Security进行权限控制,以及与MyBatis或Hibernate等持久层框架的整合。 总之,《Spring_MVC_3.0实战指南》是学习和掌握Spring MVC 3.0不可或缺的资源,无论你...
这个版本提供了认证和授权功能,可以实现用户的登录、权限控制、会话管理等。Spring Security可以轻松集成到Spring MVC中,通过配置安全拦截器,对特定的URL进行访问控制,确保只有经过身份验证和授权的用户才能访问...
你可能会用到Spring的AOP(面向切面编程)来实现事务管理,以及Spring Security来控制portlet的访问权限。 总结一下,使用Spring MVC Portlet 3.0开发IBM WebSphere Portlet应用涉及的主要知识点有: - Portlet 3.0...
首先,Spring MVC 4基于Servlet 3.0规范,这意味着它可以利用异步处理能力,提高了Web应用的性能。通过AsyncSupport和AsyncConfigurer接口,开发者可以轻松地创建异步控制器,处理高并发场景。 控制器(Controller...
- **Servlet 3.0 下的 MultipartResolver**:对于 Servlet 3.0 及以上版本,Spring MVC 提供了内置的文件上传支持。 - **处理表单中的文件上传**:通过控制器方法来接收和处理上传的文件。 #### 异常处理 ...
Spring Security 是一...总之,Spring Security 3.0提供了一套完整的安全解决方案,其核心组件包括了认证、授权、Web安全和对象级别的权限控制。理解和掌握这些jar包的功能,能够帮助开发者有效地构建安全的应用程序。
此外,它还支持与其他Spring模块的无缝集成,如Spring MVC、Spring Data等,使得在企业级应用中实现全面的安全控制变得更加容易。 总的来说,"SpringSecurity3.0 Demo"项目是一个深入学习和实践SpringSecurity的好...
4. **Role-Based Access Control (RBAC)**:Spring Security支持基于角色的访问控制,允许我们为不同的用户角色分配特定的权限。 5. **Remember Me**:Spring Security还提供了记住我(Remember-Me)服务,使用户在...
1. **Spring MVC 框架**:Spring MVC是Spring框架的一部分,它提供了一个用于构建Web应用的模型-视图-控制器(MVC)架构。通过使用DispatcherServlet、Controllers、Models、Views等组件,Spring MVC简化了处理HTTP...
Spring MVC结合Spring的AOP模块,可以方便地实现日志记录、权限控制、事务管理等功能。通过定义切点和通知,可以在不修改业务代码的情况下,实现对特定行为的拦截和处理。 九、单元测试与集成测试 Spring MVC提供了...
【源码】mysql版本_spring3.0 系统模块 1. 组织管理:角色管理,分角色组和成员,有组权限和成员权限。 2. 系统用户:对各个基本的组会员增删改查,单发、群发邮件短信,导入导出excel表格,批量删除 3. 会员管理:...
- 注解式控制器是Spring 3.0引入的,用于简化Spring MVC的控制器实现。 - 本部分内容详细介绍如何使用@Controller、@RequestMapping等注解来定义控制器,处理请求映射,以及如何定义返回值等。 7. 请求映射规则...
- **AOP**:提供面向切面编程,用于日志记录、事务管理、权限控制等跨切面关注点的处理。 - **数据访问**:支持多种数据访问技术,如JDBC、Hibernate、MyBatis等,提供事务管理、数据源配置等高级功能。 - **MVC**...
- 示例中的`SessionInterceptor`和`SuperUserInterceptor`是自定义的拦截器,它们可以添加到Spring MVC的处理链中,用于执行请求处理前后的额外逻辑,比如检查用户会话或权限验证。 在配置Spring MVC以支持注解时...
Spring 3.0 的 MVC 框架引入了大量的注解,极大地简化了Web应用程序的开发。这些注解允许开发者在控制器类和方法级别声明路由、数据绑定和其他功能,而无需编写大量的XML配置。本篇文章将深入探讨Spring 3.0 MVC中的...