SpringMVC

作者: BeYearn | 来源:发表于2019-01-11 14:38 被阅读0次
    图片.png

    Spring的MVC框架主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。

    1. DispatcherServlet 接口

    Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。

    2. HandlerMapping接口

    能够完成客户请求到Controller映射。

    3. Controller接口

    需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。
    Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。
    从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
    

    4. ViewResolver接口

    Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。

    运行过程

    1. 客户端请求提交到DispatcherServlet
    2. 由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller。HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个 HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
    3. DispatcherServlet将请求提交到Controller
    4. Controller调用业务逻辑处理后,返回ModelAndView
    5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
    6. 视图负责将结果显示到客户端

    DispatcherServlet是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:
    1. 截获符合特定格式的URL请求。
    2. 初始化DispatcherServlet上下文对应的WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。
    3. 初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。

    拦截器原理

    HandlerInterceptor拦截器接口

    package org.springframework.web.servlet; 
    public interface 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; 
    }
    

    使用时 需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现,spring也提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法。

    • preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现);返回值:true表示继续流程(如调用下一个拦截器或处理器); false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
    • postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
    • afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。

    拦截器处理机制

    中断流程中,比如是HandlerInterceptor2中断的流程(preHandle返回false),此处仅调用它之前拦截器的preHandle返回true的afterCompletion方法。

    DispatcherServlet内部是如何工作 (伪代码)

    //doDispatch方法 
    //1、处理器拦截器的预处理(正序执行) 
    HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); 
    if (interceptors != null) { 
        for (int i = 0; i < interceptors.length; i++) { 
        HandlerInterceptor interceptor = interceptors[i]; 
            if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { 
                //1.1、失败时触发afterCompletion的调用 
                triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); 
                return; 
            } 
            interceptorIndex = i;//1.2、记录当前预处理成功的索引 
    } 
    } 
    //2、处理器适配器调用我们的处理器 
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 
    //当我们返回null或没有返回逻辑视图名时的默认视图名翻译(详解4.15.5 RequestToViewNameTranslator) 
    if (mv != null && !mv.hasView()) { 
        mv.setViewName(getDefaultViewName(request)); 
    } 
    //3、处理器拦截器的后处理(逆序) 
    if (interceptors != null) { 
    for (int i = interceptors.length - 1; i >= 0; i--) { 
          HandlerInterceptor interceptor = interceptors[i]; 
          interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); 
    } 
    } 
    //4、视图的渲染 
    if (mv != null && !mv.wasCleared()) { 
    render(mv, processedRequest, response); 
        if (errorView) { 
            WebUtils.clearErrorRequestAttributes(request); 
    } 
    //5、触发整个请求处理完毕回调方法afterCompletion 
    triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
    
    //==============================
    // triggerAfterCompletion方法 
    private void triggerAfterCompletion(HandlerExecutionChain mappedHandler, int interceptorIndex, 
            HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { 
        // 5、触发整个请求处理完毕回调方法afterCompletion (逆序从上面预处理成功的索引处的拦截器执行) 
        if (mappedHandler != null) { 
            HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); 
            if (interceptors != null) { 
                for (int i = interceptorIndex; i >= 0; i--) { 
                    HandlerInterceptor interceptor = interceptors[i]; 
                    try { 
                        interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex); 
                    } 
                    catch (Throwable ex2) { 
                        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); 
                    } 
                } 
            } 
        } 
    }  
    

    spring-mvc配置:

    <!--配置拦截器, 多个拦截器,顺序执行 -->
        <mvc:interceptors> 
               <mvc:interceptor>
                       <!--  
                           /**的意思是所有文件夹及里面的子文件夹 
                           /*是所有文件夹,不含子文件夹 
                           /是web项目的根目录
                         --> 
                       <mvc:mapping path="/**" /> 
                       <!-- 需排除拦截的地址 -->  
                       <!--  <mvc:exclude-mapping path="/userController/login"/>  -->
                        <!-- <mvc:exclude-mapping path="/js/**" />
                        <mvc:exclude-mapping path="/css/**" />
                        <mvc:exclude-mapping path="/image/**" />  -->
                       <bean id="commonInterceptor" class="org.shop.interceptor.MyInterceptor"></bean> 
    <!--这个类就是我们自定义的Interceptor -->
              </mvc:interceptor> 
              <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法  -->
        </mvc:interceptors>
    

    相关文章

      网友评论

          本文标题:SpringMVC

          本文链接:https://www.haomeiwen.com/subject/ztatdqtx.html