- 浏览: 236623 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
shuhucy:
必须赞啊,源码理解的很深,解决一个困扰两天的问题
Spring AOP源码分析(八)SpringAOP要注意的地方 -
sealinesu:
精彩
Spring事务源码分析(一)Spring事务入门 -
whlt20090509:
"WEB-INF/view目录下有一个简单的hell ...
SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门 -
hai0378:
兄台 算我一个,最近在研究dubbo motan 及 zk ...
ZooKeeper源码研究寻求小伙伴 -
zpkbtzmbw:
看懂了,原理
SpringMVC源码总结(五)Tomcat的URIEncoding、useBodyEncodingForURI和CharacterEncodingFilter
SpringMVC源码总结(十一)mvc:interceptors拦截器介绍
- 博客分类:
- SpringMVC源码分析
本文章针对mvc:interceptors标签进行介绍,它的注册过程以及在访问时的拦截过程。
首先说下接口HandlerInterceptor,它有如下三个方法:
正常情况下,对于preHandle就是在在处理函数之前先执行,然后再执行处理函数,接着执行postHandle,最后再执行afterCompletion。afterCompletion无论是否出错是肯定要执行的,而postHandle则不是,不一定会执行。之后看源代码就知道他们的执行情况。
AsyncHandlerInterceptor接口则增添了afterConcurrentHandlingStarted方法,对于此还未研究,先不讨论。
HandlerInterceptorAdapter则默认实现了上述的接口,所以当我们仅仅要实现某个方法时,只需继承HandlerInterceptorAdapter,然后覆盖相应的方法。
然后我们就写一个类继承HandlerInterceptorAdapter来进行实验:LoginInterceptor如下:
没有做具体的内容,仅仅是打印出一些信息,方便查看执行顺序。
该接口的基本内容说完了,然后就看下它的配置说明:
其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。直接配置的bean那就代表对所有的请求进行拦截,而对于mvc:interceptor则代表有着更精细的控制。
而mvc:interceptors的属性path-matcher则表示配置一个自定义的PathMatcher,它主要用来处理路径的匹配规则,默认采用的PathMatcher为AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。
对于本工程来说具体的配置如下:
然后就进行源代码分析:
如何来处理xml文件中所配置的这些HandlerInterceptor的呢?
对于mvc:interceptors的解析同样需要我们去看BeanDefinitionParser的实现类,最终会找到InterceptorsBeanDefinitionParser:
这里就引出来MappedInterceptor的结构类型:
到这里就很明白了,虽然在mvc:interceptors标签中,配置interceptor形式不一样,但是最终都将以MappedInterceptor形式存储,同时来看下MappedInterceptor的match的方法:
这里便是PathMatcher对于excludePatterns、includePatterns 的使用规则,同时表明本身的PathMatcher若为空,则使用外部传来的PathMatcher。
至此解析mvc:interceptors标签的过程就完成了。它们最终会注册到ApplicationContext的上下文环境中,等待被使用。
谁会是他们的使用者呢?我们慢慢来看:
对于每一个请求,HandlerMapping都会找到对应的handler,并最终封装成一个HandlerExecutionChain,这个HandlerExecutionChain包含有handler和它对应的interceptors,HandlerExecutionChain如下:
既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。
使用者:AbstractHandlerMapping,它的属性有:
这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher。接下来我们看下AbstractHandlerMapping的初始化方法:
detectMappedInterceptors探测ApplicationContext中已经解析过的MappedInterceptor,如下:
全部存放到AbstractHandlerMapping的mappedInterceptors属性上。
然后我们继续看看在请求到来时的具体拦截过程:
对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。代码如下:
这里便是找到一个合适的HandlerMapping,继续看下hm.getHandler(request)这个方法。
这里便是找到对应请求的handler。getHandlerExecutionChain(handler, request)这里便是构建HandlerExecutionChain的地方:
对于我们关注的重点为它会遍历AbstarctHandlerMapping的mappedInterceptors属性,然后使用默认的pathMatcher,即AntPathMatcher来判断当前的请求是否符合拦截条件,若符合则将mappedInterceptor放进HandlerExecutionChain 中。
至此一个HandlerExecutionChain便构建好了,包含一个handler和这个handler对应的interceptor。然后看下interceptor的执行过程:
先看重点1:
执行preHandle方法,一旦有一个preHandle返回false,则触发triggerAfterCompletion:
看下这里的for循环的条件,从interceptorIndex开始到0,逆序执行interceptor.afterCompletion。
重点2 postHandle:
这个没有什么特殊,preHandle只有参数HttpServletRequest和HttpServletResponse,而postHandle则加入了返回结果ModelAndView,我们可以对ModelAndView进行进一步的修改,此时的view(若有)还没有经过渲染。
重点3 :
这里可以看到,如果有view,则渲染完成之后,才会执行triggerAfterCompletion,同时不再拥有对ModelAndView的处理(已经完成了渲染)。所以我们就可以看到当有view时,afterCompletion和postHandle的明显区别。
重点4:当执行过程发生异常时,也会执行interceptor的afterCompletion方法。
这里要做下说明,对于preHandler方法是获取不到处理函数的参数值的,如果想对处理函数的参数值进行拦截处理,则要使用Spring AOP。
首先说下接口HandlerInterceptor,它有如下三个方法:
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
正常情况下,对于preHandle就是在在处理函数之前先执行,然后再执行处理函数,接着执行postHandle,最后再执行afterCompletion。afterCompletion无论是否出错是肯定要执行的,而postHandle则不是,不一定会执行。之后看源代码就知道他们的执行情况。
AsyncHandlerInterceptor接口则增添了afterConcurrentHandlingStarted方法,对于此还未研究,先不讨论。
HandlerInterceptorAdapter则默认实现了上述的接口,所以当我们仅仅要实现某个方法时,只需继承HandlerInterceptorAdapter,然后覆盖相应的方法。
然后我们就写一个类继承HandlerInterceptorAdapter来进行实验:LoginInterceptor如下:
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); super.afterCompletion(request, response, handler, ex); } @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("afterConcurrentHandlingStarted"); super.afterConcurrentHandlingStarted(request, response, handler); }
没有做具体的内容,仅仅是打印出一些信息,方便查看执行顺序。
该接口的基本内容说完了,然后就看下它的配置说明:
<mvc:interceptors path-matcher="xxx"> <mvc:interceptor> <mvc:mapping path="xxx"/> <mvc:exclude-mapping path="xxxx"/> <bean class="xxxx"></bean> </mvc:interceptor> <bean class="com.lg.mvc.interceptor.LoginInterceptor" /> </mvc:interceptors>
其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。直接配置的bean那就代表对所有的请求进行拦截,而对于mvc:interceptor则代表有着更精细的控制。
而mvc:interceptors的属性path-matcher则表示配置一个自定义的PathMatcher,它主要用来处理路径的匹配规则,默认采用的PathMatcher为AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。
对于本工程来说具体的配置如下:
<mvc:interceptors> <bean class="com.lg.mvc.interceptor.LoginInterceptor" /> </mvc:interceptors>
然后就进行源代码分析:
如何来处理xml文件中所配置的这些HandlerInterceptor的呢?
对于mvc:interceptors的解析同样需要我们去看BeanDefinitionParser的实现类,最终会找到InterceptorsBeanDefinitionParser:
public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compDefinition); //判断是否自定义了PathMatcher RuntimeBeanReference pathMatcherRef = null; if (element.hasAttribute("path-matcher")) { pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher")); } //获取所有的interceptor,在这里我们可以看到所有的interceptor最终都会构建成一个 //MappedInterceptor List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean", "ref", "interceptor"); for (Element interceptor : interceptors) { RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); mappedInterceptorDef.setSource(parserContext.extractSource(interceptor)); mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); ManagedList<String> includePatterns = null; ManagedList<String> excludePatterns = null; Object interceptorBean; if ("interceptor".equals(interceptor.getLocalName())) { includePatterns = getIncludePatterns(interceptor, "mapping"); excludePatterns = getIncludePatterns(interceptor, "exclude-mapping"); Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean", "ref").get(0); interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null); } else { interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null); } mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns); mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns); mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean); if (pathMatcherRef != null) { mappedInterceptorDef.getPropertyValues().add("pathMatcher", pathMatcherRef); } String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef); parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName)); } parserContext.popAndRegisterContainingComponent(); return null; }
这里就引出来MappedInterceptor的结构类型:
private final String[] includePatterns; private final String[] excludePatterns; private final HandlerInterceptor interceptor; private PathMatcher pathMatcher;
到这里就很明白了,虽然在mvc:interceptors标签中,配置interceptor形式不一样,但是最终都将以MappedInterceptor形式存储,同时来看下MappedInterceptor的match的方法:
public boolean matches(String lookupPath, PathMatcher pathMatcher) { PathMatcher pathMatcherToUse = (this.pathMatcher != null) ? this.pathMatcher : pathMatcher; if (this.excludePatterns != null) { for (String pattern : this.excludePatterns) { if (pathMatcherToUse.match(pattern, lookupPath)) { return false; } } } if (this.includePatterns == null) { return true; } else { for (String pattern : this.includePatterns) { if (pathMatcherToUse.match(pattern, lookupPath)) { return true; } } return false; } }
这里便是PathMatcher对于excludePatterns、includePatterns 的使用规则,同时表明本身的PathMatcher若为空,则使用外部传来的PathMatcher。
至此解析mvc:interceptors标签的过程就完成了。它们最终会注册到ApplicationContext的上下文环境中,等待被使用。
谁会是他们的使用者呢?我们慢慢来看:
对于每一个请求,HandlerMapping都会找到对应的handler,并最终封装成一个HandlerExecutionChain,这个HandlerExecutionChain包含有handler和它对应的interceptors,HandlerExecutionChain如下:
private final Object handler; private HandlerInterceptor[] interceptors; private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1;
既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。
使用者:AbstractHandlerMapping,它的属性有:
private PathMatcher pathMatcher = new AntPathMatcher(); private final List<Object> interceptors = new ArrayList<Object>(); private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>(); private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();
这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher。接下来我们看下AbstractHandlerMapping的初始化方法:
protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.mappedInterceptors); initInterceptors(); }
detectMappedInterceptors探测ApplicationContext中已经解析过的MappedInterceptor,如下:
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) { mappedInterceptors.addAll( BeanFactoryUtils.beansOfTypeIncludingAncestors( getApplicationContext(), MappedInterceptor.class, true, false).values()); }
全部存放到AbstractHandlerMapping的mappedInterceptors属性上。
然后我们继续看看在请求到来时的具体拦截过程:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); //略 }
对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。代码如下:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
这里便是找到一个合适的HandlerMapping,继续看下hm.getHandler(request)这个方法。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } return getHandlerExecutionChain(handler, request); }
这里便是找到对应请求的handler。getHandlerExecutionChain(handler, request)这里便是构建HandlerExecutionChain的地方:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); chain.addInterceptors(getAdaptedInterceptors()); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) { if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain; }
对于我们关注的重点为它会遍历AbstarctHandlerMapping的mappedInterceptors属性,然后使用默认的pathMatcher,即AntPathMatcher来判断当前的请求是否符合拦截条件,若符合则将mappedInterceptor放进HandlerExecutionChain 中。
至此一个HandlerExecutionChain便构建好了,包含一个handler和这个handler对应的interceptor。然后看下interceptor的执行过程:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //重点1 这里执行interceptor的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //这里执行处理函数 try { // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); //重点2:这里执行interceptor的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //重点3:这里执行interceptor的afterCompletion方法 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } //重点4:当出现异常时,仍然执行afterCompletion方法 catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
先看重点1:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { if (getInterceptors() != null) { for (int i = 0; i < getInterceptors().length; i++) { HandlerInterceptor interceptor = getInterceptors()[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }
执行preHandle方法,一旦有一个preHandle返回false,则触发triggerAfterCompletion:
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { if (getInterceptors() == null) { return; } for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } }
看下这里的for循环的条件,从interceptorIndex开始到0,逆序执行interceptor.afterCompletion。
重点2 postHandle:
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { if (getInterceptors() == null) { return; } for (int i = getInterceptors().length - 1; i >= 0; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; interceptor.postHandle(request, response, this.handler, mv); } }
这个没有什么特殊,preHandle只有参数HttpServletRequest和HttpServletResponse,而postHandle则加入了返回结果ModelAndView,我们可以对ModelAndView进行进一步的修改,此时的view(若有)还没有经过渲染。
重点3 :
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
这里可以看到,如果有view,则渲染完成之后,才会执行triggerAfterCompletion,同时不再拥有对ModelAndView的处理(已经完成了渲染)。所以我们就可以看到当有view时,afterCompletion和postHandle的明显区别。
重点4:当执行过程发生异常时,也会执行interceptor的afterCompletion方法。
这里要做下说明,对于preHandler方法是获取不到处理函数的参数值的,如果想对处理函数的参数值进行拦截处理,则要使用Spring AOP。
发表评论
-
SpringMVC源码总结(十二)ViewResolver介绍
2014-09-10 06:43 2263首先我们先看看ModelAndView中重要的View接口。 ... -
SpringMVC源码总结(十)自定义HandlerMethodArgumentResolver
2014-09-04 07:45 7368上一篇文章介绍了HandlerMethodArgumentRe ... -
SpringMVC源码总结(九)HandlerMethodArgumentResolver介绍
2014-09-02 06:24 12389本文章主要介绍HandlerMethodArgumentRes ... -
SpringMVC源码总结(八)类型转换PropertyEditor的背后
2014-08-30 17:13 4836PropertyEditor是Spring最初 ... -
SpringMVC源码总结(七)mvc:annotation-driven中的HttpMessageConverter
2014-08-27 22:32 6570这一篇文章主要介绍下HttpMessageConverter整 ... -
SpringMVC源码总结(六)mvc:annotation-driven中的HandlerMethodReturnValueHandler
2014-08-26 06:21 6516经过了两篇的乱码说明,要重新回到mvc:annotation- ... -
SpringMVC源码总结(五)Tomcat的URIEncoding、useBodyEncodingForURI和CharacterEncodingFilter
2014-08-22 06:32 7330继续上一章节的乱码问题。上一篇文章仅仅说了设置Tomcat的U ... -
SpringMVC源码总结(四)由StringHttpMessageConverter引出的客户端服务器端之间的乱码过程分析
2014-08-20 22:49 3629继续上一篇文章遗留的乱码问题,引出从客户端数据到服务器端的乱码 ... -
SpringMVC源码总结(三)mvc:annotation-driven和mvc:message-converters简单介绍
2014-08-19 06:58 10124上一篇文章讲述了最简单的mvc:annotation-driv ... -
SpringMVC源码总结(二)mvc:annotation-driven以及@Controller和@RequestMapping的那些事
2014-08-16 22:47 8631上一篇文章让我们了解HandlerMapping和Handle ... -
SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
2014-08-16 22:42 14694刚接触SpringMVC,对它的xml文件配置一直比较模模糊糊 ...
相关推荐
在SpringMVC的配置中,我们可以通过`<mvc:interceptors>`标签来声明和配置拦截器。每个拦截器由`<mvc:interceptor>`标签定义,并通过`<mvc:mapping>`指定拦截的URL模式。例如: ```xml <mvc:interceptors> <mvc:...
下面将详细介绍创建和配置Spring MVC拦截器的步骤。 1. **创建自定义拦截器** 首先,我们需要创建一个实现`HandlerInterceptor`接口的类。这个接口包含三个方法: - `preHandle(HttpServletRequest request, ...
在Spring MVC中,Interceptor(拦截器)是一种强大的机制,它允许开发者在请求处理前后执行自定义逻辑,而不必侵入到Controller代码中。本篇文章主要探讨了Interceptor的使用及其源码解析,帮助深入理解其工作原理。...
2. 注册拦截器:将创建的Interceptor实例添加到SpringMVC的配置中。在Spring的XML配置文件中,你可以使用`<mvc:interceptors>`标签来注册拦截器,或者在Java配置中使用`addInterceptors()`方法。 3. 配置拦截规则:...
此外,如果需要在全局范围内改变应用的`Locale`,可以创建一个自定义的`HandlerInterceptor`,在拦截器中处理`Locale`的切换逻辑。这样,当用户请求特定的URL时,系统会自动更新`Locale`,并重定向到原来的请求URL,...
在`/springmvc-servlet.xml`或`applicationContext.xml`配置文件中,可以找到`<mvc:interceptors>`标签来配置拦截器。 最后,国际化支持让应用能够适应不同语言环境。SpringMVC通过`MessageSource`接口和资源文件...
总结起来,非注解方式配置Spring MVC涉及的主要步骤包括:配置DispatcherServlet、扫描Controller、设置视图解析器、处理模型数据、配置拦截器、处理异常、定制消息转换器、映射资源以及实现国际化。这种方式虽然比...
9. **Interceptors**: 拦截器允许在请求处理前后执行额外的逻辑,如记录日志、权限检查或缓存管理。 10. **Internationalization (i18n)**: Spring MVC支持国际化,可以依据用户的语言设置返回不同的消息和视图。 ...
9. **拦截器(Interceptors)**:SpringMVC支持使用拦截器来执行全局的请求预处理和后处理,如登录验证、权限控制等。 10. **异常处理**:项目会包含统一的异常处理机制,确保在出现错误时,能够提供友好的错误提示...
例如,我们可以添加一个简单的拦截器: ```xml <mvc:interceptors> </mvc:interceptors> ``` 在项目中,我们可能还需要配置数据访问层(DAO)和业务逻辑层(Service)。这部分通常通过Spring的AOP(面向切面编程...
- **spring-mvc.xml**: 主要用于配置视图解析器、拦截器等。例如,可以配置`InternalResourceViewResolver`来解析JSP视图路径。 - **daoContext.xml**: 这个文件主要用于配置数据源和事务管理器,以及DAO组件的扫描...
10. **Interceptors**:拦截器,可以实现请求预处理和后处理,如权限控制、日志记录等。 **云音乐网站系统特点可能包括:** 1. **用户模块**:用户注册、登录、个人信息管理等功能。 2. **音乐搜索**:支持关键词...
通过深入学习SpringMVC的源码,开发者不仅可以了解每个组件的工作原理,还能发现性能优化点,如调整HandlerMapping和HandlerAdapter的优先级,自定义拦截器,以及优化视图解析过程。这种深入的理解对于提升代码质量...
在servlet-context.xml中,我们定义视图解析器、拦截器、bean的扫描路径、以及自定义的处理器映射和适配器。 3. **HandlerMapping**:这个组件负责将请求映射到相应的处理器(Controller)。可以是基于注解的映射,...
通过这个简单的 SpringMVCDemo,我们可以学习到如何在 MyEclipse 中创建一个 Spring MVC 项目,理解拦截器的工作原理以及如何实现和注册拦截器。此外,还可以涉及其他 Spring MVC 相关的知识点,如控制器...
5. **MVC拦截器(Interceptor)** - 可以在请求处理前后执行自定义逻辑,如登录检查、权限验证等。 - 配置在`servlet-context.xml`中的`<mvc:interceptors>`标签内。 6. **SpringMVC与Spring整合** - 共享Spring...
5. **拦截器(Interceptors)** 拦截器可以预处理请求和后处理响应,提供诸如认证、授权、日志记录等功能。通过实现HandlerInterceptor接口或者使用@Interceptor注解,可以自定义拦截器。 6. **异常处理** Spring...
7. **拦截器(Interceptors)**:可以预处理和后处理请求,实现如权限检查、日志记录等功能。 掌握这些基础知识后,你可以进一步探索Spring MVC的高级特性,如异步处理、RESTful API设计、AOP(面向切面编程)在...
- Interceptors(拦截器):SpringMVC中的拦截器可以用来在请求处理之前进行权限检查,阻止未经授权的访问。 4. **数据库设计**: - 角色表:存储角色信息,如角色ID、角色名称等。 - 权限表:存储权限信息,...