在线咨询

深入剖析Spring Web源码(十三) - 处理器映射,处理器适配器以及处理器的实现 - 处理器的实现架构 - 简单控制器


2.2.2.3 处理器的实现架构

作为总控制器的派遣器Servlet将得到的处理器传递给支持此处理器的处理器适配器,处理器适配器然后调用处理器中适当的处理器方法,最后返回处理结果给派遣器Serlvet。

处理器架构中并没有简单的处理器接口定义,任何一个对象类型都可以成为处理器,每个类型的处理器都有一个对应的处理器适配器,用于将HTTP请求适配给一定类型的处理器。

处理器根据类型分为简单控制器,注解控制器和HTTP请求处理器。我们在讨论基于流程的实现的小节中,已经对每种类型中的典型实现类进行了剖析。下面我们就对不同类型的处理器进行详细的剖析。

  

 4.2.2.3.1 简单控制器

  

简单控制器是最常用的处理器类型,它有一个简单的接口定义,接口有唯一的处理器方法,方法接受HTTP请求对象和HTTP响应对象作为参数,并且返回模型和视图对象。当派遣器Servlet派遣一个HTTP请求到简单控制器处理器适配器,简单控制器处理器适配器就会传递HTTP请求对象和HTTP响应对象给简单控制器的处理器方法,控制器处理器方法调用服务层的业务逻辑处理方法后返回模型和视图对象,模型和视图对象最后返回给派遣器Servlet。

简单控制器接口有很多抽象的或者具体的实现类,每个层次的类都实现一个独立的逻辑功能。如下类图所示,

 

图表 4‑31

从上图我们可以看到,简单控制器架构的实现比较复杂,它有很多的抽象实现类和具体的实现类,有些类之间互相独立,有些类是继承自其他类,设计和实现这些类有着不同的目的,实现不同的功能。下面通过功能对这些类实现进行分类。

l         抽象命令控制器(AbstractCommandController)

抽象命令控制器根据请求参数自动绑定一个命令类实例,子类实现根据绑定的命令类实例完成服务层的业务逻辑的调用后,最后决定跳转到某一个视图。它用来处理一个单一的直线式的流程。

l         抽象Form控制器(AbstractFormController)

抽象Form控制器也根据请求参数自动绑定一个命令类实例,它用来处理一个基于Form的流程,包括Form的显示,提交和取消。它是一个抽象类,但是它有不同的实现类实现不同的Form流程。下面我们具体介绍其三个实现类。

n         简单Form控制器(SimpleFormController)

简单的Form控制器用来处理一个具有两个状态的Form处理流程。他们是显示Form状态和提交Form状态。通过配置Form视图和成功视图,简单的Form控制器就可以开始工作了。第一次请求页面时,它使用HTTP GET协议,简单Form控制器自动显示Form视图。当Form提交的时候,它使用HTTP POST协议,简单Form控制器就进行服务层次的逻辑调用,最后显示成功视图。

 

图表 4‑32

n         可取消的Form控制器(CancellableFormController)

可取消的Form控制器是简单Form控制器的子类。它除了拥有显示Form状态和提交Form状态还增加了一个取消Form状态。如果一个Form提交中带有取消参数,则显示取消视图。

 

图表 4‑33

n         抽象导航控制器(AbstractWizardFormController)

抽象导航控制器更加复杂,它拥有更多的状态,它拥有一个或者多个页面状态,一个取消状态和一个完成状态。当一个Form加载时,它显示第一个页面,然后,通过页面提交的参数可以在不同的页面进行导航。当一个提交中包含取消参数或者完成参数,则显示取消视图或者完成视图。这是一个抽象类,子类可以根据业务需要在显示取消和完成试图前进行服务层次的业务逻辑的处理。

 

图表 4‑34

l         多动作控制器(MultiActionController)

多动作控制器是用于处理多个HTTP请求的处理器。它根据HTTP请求URL映射得到应该调用的处理器方法,通过反射调用处理器方法,并且封装返回结果作为模型和视图返回给简单控制器适配器。每个处理器方法可以有一个对应的最后修改方法,最后修改方法名是处理器方法名加上LastModified后缀构成的。最后修改方法也是通过反射调用并且返回结果的。

 

图表 4‑35

l         Servlet相关控制器

Servlet相关控制器和简单Servlet处理器适配器功能类似,他们都实现将HTTP请求适配到一个已存的Servlet实现。但是,简单Servlet处理器适配器需要在Web应用程序环境中定义Servlet Bean,并且Servlet没有机会进行初始化和析构。

n         Servlet包装控制器(ServletWrappingController)

Servlet包装控制器内部封装了一个Servlet实例,内部封装的Servlet实例对外并不开放,对于程序的其他范围是不可见的。封装的Servlet实例有机会进行初始化和析构。Servlet包装控制器适配所有的HTTP请求到内部封装的Servlet实例进行处理。它通常用于对已存Servlet的逻辑重用上。

n         Servlet转发控制器(ServletForwardingController)

Servlet包装控制器将所有的HTTP请求转发给一个在web.xml中定义的Servlet。Web容器会对这个定义在web.xml的标准Servlet进行初始化和析构。

       下面我们将用一个表格来总结Servlet封装相关对象异同。

      

Servlet 封装对象

管理范围

初始化和析构

服务调用方式

SimpleServletHandlerAdaptor

Web应用程序环境

没有

直接

ServletWrappingController

控制器内部

直接

ServletForwardingController

web.xml

Servlet派遣器

l         视图转发控制器

n         URL文件名视图控制器(UrlFilenameViewController)

URL文件名视图控制器通过将URL翻译成为视图名,并且返回。

n         可参数化视图控制器(ParameterizableViewController)

可参数化视图控制器简单的返回配置的视图名。

在前面一些小结中,分析了基于不同流程的实现,我们已经对简单Form控制器及其父类的实现进行了深入剖析和代码注释,这里将只对其他类进行剖析和代码注释。

抽象命令控制器继承自基本命令控制器。前面小结分析到,基本命令控制器提供了创建命令对象和通过HTTP请求参数对命令对象进行绑定和校验的功能方法。抽象命令控制器使用这些方法实现一个线性的流程,首先创建命令对象,然后绑定校验命令对象,最后传递命令对象到抽象的方法进行业务逻辑的处理。子类应该根据业务逻辑实现此方法。如下代码所示,

public   abstract   class  AbstractCommandController  extends  BaseCommandController {

 

     public  AbstractCommandController() {

    }

 

     public  AbstractCommandController(Class commandClass) {

        setCommandClass(commandClass);

    }

 

     public  AbstractCommandController(Class commandClass, String commandName) {

        setCommandClass(commandClass);

        setCommandName(commandName);

    }

 

 

    @Override

     protected  ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)

             throws  Exception {

         //  根据命令类型,创建命令对象

        Object command = getCommand(request);

       

         //  绑定命令对象到 HTTP 请求参数,并且校验

        ServletRequestDataBinder binder = bindAndValidate(request, command);

       

         //  构造绑定结果对象

        BindException errors =  new  BindException(binder.getBindingResult());

       

         //  调用业务逻辑处理方法

         return  handle(request, response, command, errors);

    }

 

     //  子类根据业务逻辑实现此方法,它通常不适用于 Form 流程,它适用于一个简单的 AJAX 请求

     protected   abstract  ModelAndView handle(

            HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)

             throws  Exception;

 

}

可取消的Form控制器继承自简单的Form控制器。我们知道,简单Form控制器支持具有两种状态的Form流程,既显示Form视图状态和显示成功视图状态。可取消的Form控制器则增加了一个显示取消视图状态。如下代码所示,

public   class  CancellableFormController  extends  SimpleFormController {

 

     //  缺省的代表取消请求的参数键值

     private   static   final  String  PARAM_CANCEL  = "_cancel";

 

     private  String cancelParamKey =  PARAM_CANCEL ;

 

     private  String cancelView;

 

     public   final   void  setCancelParamKey(String cancelParamKey) {

         this .cancelParamKey = cancelParamKey;

    }

 

     public   final  String getCancelParamKey() {

         return   this .cancelParamKey;

    }

 

     //  当接收到一个取消请求,显示这个取消视图

     public   final   void  setCancelView(String cancelView) {

         this .cancelView = cancelView;

    }

 

     public   final  String getCancelView() {

         return   this .cancelView;

    }

 

 

    @Override

     protected   boolean  isFormSubmission(HttpServletRequest request) {

         //  除了普通的 Form 提交请求,还包括具有取消参数的请求

         return   super .isFormSubmission(request) || isCancelRequest(request);

    }

 

    @Override

     protected   boolean  suppressValidation(HttpServletRequest request, Object command) {

         //  取消请求不需要校验参数

         return   super .suppressValidation(request, command) || isCancelRequest(request);

    }

 

    @Override

     protected  ModelAndView processFormSubmission(

            HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)

             throws  Exception {

 

         //  特殊处理取消请求

         if  (isCancelRequest(request)) {

             return  onCancel(request, response, command);

        }

         else  {

             return   super .processFormSubmission(request, response, command, errors);

        }

    }

 

     protected   boolean  isCancelRequest(HttpServletRequest request) {

         //  存在取消参数,则是取消请求

         return  WebUtils.hasSubmitParameter(request, getCancelParamKey());

    }

 

     protected  ModelAndView onCancel(HttpServletRequest request, HttpServletResponse response, Object command)

             throws  Exception {

         //  代理到处理取消的处理器

         return  onCancel(command);

    }

 

     protected  ModelAndView onCancel(Object command)  throws  Exception {

         //  简单的返回取消视图

         return   new  ModelAndView(getCancelView());

    }

 

}

抽象导航控制器继承自抽象Form控制器。抽象Form控制器定义了两个状态,显示Form视图状态和显示成功视图状态。抽象导航控制器扩展了它的实现,拥有多个页面状态也一个取消视图状态和一个完成视图状态。它能够在不同的页面之间进行导航。它适用于一个模块有非常多的输入数据,以至于需要多个Tab页面进行输入。如下代码注释,

public   abstract   class  AbstractWizardFormController  extends  AbstractFormController {

 

     //  代表完成请求的参数

     public   static   final  String  PARAM_FINISH  = "_finish";

 

     //  代表取消请求的参数

     public   static   final  String  PARAM_CANCEL  = "_cancel";

 

     //  代表导航到一个新页面的参数

     public   static   final  String  PARAM_TARGET  = "_target";

 

     //  代表当前的页面,这个参数也存在在 request 或者 session

     public   static   final  String  PARAM_PAGE  = "_page";

 

     //  所有的页面视图

     private  String[] pages;

 

     private  String pageAttribute;

 

     private   boolean  allowDirtyBack =  true ;

 

     private   boolean  allowDirtyForward =  false ;

 

 

     public  AbstractWizardFormController() {

         // AbstractFormController sets default cache seconds to 0.

         super ();

 

         // Always needs session to keep data from all pages.

         //  需要在 Session 中保存命令对象

        setSessionForm( true );

 

         // Never validate everything on binding ->

         // wizards validate individual pages.

        setValidateOnBinding( false );

    }

 

     public   final   void  setPages(String[] pages) {

         //  至少有一个页面,第一个页面表现作为传统的 Form 视图

         if  (pages ==  null  || pages.length == 0)  {

             throw   new  IllegalArgumentException("No wizard pages defined");

        }

         this .pages = pages;

    }

 

     public   final  String[] getPages() {

         return   this .pages;

    }

 

     protected   final   int  getPageCount() {

         return   this .pages.length;

    }

 

     public   final   void  setPageAttribute(String pageAttribute) {

         this .pageAttribute = pageAttribute;

    }

 

     public   final  String getPageAttribute() {

         return   this .pageAttribute;

    }

 

     public   final   void  setAllowDirtyBack( boolean  allowDirtyBack) {

         this .allowDirtyBack = allowDirtyBack;

    }

 

     public   final   boolean  isAllowDirtyBack() {

         return   this .allowDirtyBack;

    }

 

     public   final   void  setAllowDirtyForward( boolean  allowDirtyForward) {

         this .allowDirtyForward = allowDirtyForward;

    }

 

     public   final   boolean  isAllowDirtyForward() {

         return   this .allowDirtyForward;

    }

 

    @Override

     protected   final   void  onBindAndValidate(HttpServletRequest request, Object command, BindException errors)

         throws  Exception {

 

        onBindAndValidate(request, command, errors, getCurrentPage(request));

    }

 

     //  针对不同的页面进行特殊的绑定和校验

     protected   void  onBindAndValidate(HttpServletRequest request, Object command, BindException errors,  int  page)

         throws  Exception {

    }

 

    @Override

     protected   boolean  isFormSubmission(HttpServletRequest request) {

         //  除了 Form 提交请求,完成请求和取消请求都被视为 Form 提交

         return   super .isFormSubmission(request) || isFinishRequest(request) || isCancelRequest(request);

    }

 

    @Override

     protected   final  Map referenceData(HttpServletRequest request, Object command, Errors errors)

         throws  Exception {

 

         return  referenceData(request, command, errors, getCurrentPage(request));

    }

 

     protected  Map referenceData(HttpServletRequest request, Object command, Errors errors,  int page)

         throws  Exception {

 

         return  referenceData(request, page);

    }

 

     //  针对不同的页面有不同的引用数据

     protected  Map referenceData(HttpServletRequest request,  int  page)  throws  Exception {

         return   null ;

    }

 

    @Override

     protected  ModelAndView showForm(

            HttpServletRequest request, HttpServletResponse response, BindException errors)

         throws  Exception {

       

         //  第一次请求显示第一个页面,相当于传统的 Form 视图

         return  showPage(request, errors, getInitialPage(request, errors.getTarget()));

    }

 

     protected   final  ModelAndView showPage(HttpServletRequest request, BindException errors,  int page)

         throws  Exception {

       

         //  校验它是一个合法的页面

         if  (page >= 0 && page < getPageCount(request, errors.getTarget())) {

             if  (logger.isDebugEnabled()) {

                logger.debug("Showing wizard page " + page + " for form bean '" + getCommandName() + "'");

            }

 

             // Set page session attribute, expose overriding request attribute.

            Integer pageInteger =  new  Integer(page);

            String pageAttrName = getPageSessionAttributeName(request);

             if  (isSessionForm()) {

                 if  (logger.isDebugEnabled()) {

                    logger.debug("Setting page session attribute [" + pageAttrName + "] to: " + pageInteger);

                }

                request.getSession().setAttribute(pageAttrName, pageInteger);

            }

            request.setAttribute(pageAttrName, pageInteger);

 

             // Set page request attribute for evaluation by views.

            Map controlModel =  new  HashMap();

             if  ( this .pageAttribute !=  null ) {

                controlModel.put( this .pageAttribute,  new  Integer(page));

            }

           

             //  取得具体某一页的视图名

            String viewName = getViewName(request, errors.getTarget(), page);

           

             //  显示视图

             return  showForm(request, errors, viewName, controlModel);

        }

 

         else  {

             throw   new  ServletException("Invalid wizard page number: " + page);

        }

    }

 

     protected   int  getPageCount(HttpServletRequest request, Object command) {

         return  getPageCount();

    }

 

     //  每一个页面对应一个视图名,他们按照顺序存储

     protected  String getViewName(HttpServletRequest request, Object command,  int  page) {

         return  getPages()[page];

    }

 

     //  默认情况下,第一个页面就是初始化页面

     protected   int  getInitialPage(HttpServletRequest request, Object command) {

         return  getInitialPage(request);

    }

 

     protected   int  getInitialPage(HttpServletRequest request) {

         return  0;

    }

 

     protected  String getPageSessionAttributeName(HttpServletRequest request) {

         return  getPageSessionAttributeName();

    }

 

     protected  String getPageSessionAttributeName() {

         return  getClass().getName() + ".PAGE." + getCommandName();

    }

 

    @Override

     protected  ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response)

             throws  Exception {

 

         return  showNewForm(request, response);

    }

 

    @Override

     protected   final  ModelAndView processFormSubmission(

            HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)

             throws  Exception {

 

         int  currentPage = getCurrentPage(request);

         // Remove page session attribute, provide copy as request attribute.

        String pageAttrName = getPageSessionAttributeName(request);

         if  (isSessionForm()) {

             if  (logger.isDebugEnabled()) {

                logger.debug("Removing page session attribute [" + pageAttrName + "]");

            }

            request.getSession().removeAttribute(pageAttrName);

        }

        request.setAttribute(pageAttrName,  new  Integer(currentPage));

 

         // cancel?

         if  (isCancelRequest(request)) {

             if  (logger.isDebugEnabled()) {

                logger.debug("Cancelling wizard for form bean '" + getCommandName() + "'");

            }

             return  processCancel(request, response, command, errors);

        }

 

         // finish?

         if  (isFinishRequest(request)) {

             if  (logger.isDebugEnabled()) {

                logger.debug("Finishing wizard for form bean '" + getCommandName() + "'");

            }

             return  validatePagesAndFinish(request, response, command, errors, currentPage);

        }

 

         // Normal submit: validate current page and show specified target page.

         if  (!suppressValidation(request, command, errors)) {

             if  (logger.isDebugEnabled()) {

                logger.debug("Validating wizard page " + currentPage + " for form bean '" + getCommandName() + "'");

            }

            validatePage(command, errors, currentPage,  false );

        }

 

         // Give subclasses a change to perform custom post-procession

         // of the current page and its command object.

        postProcessPage(request, command, errors, currentPage);

 

         int  targetPage = getTargetPage(request, command, errors, currentPage);

         if  (logger.isDebugEnabled()) {

            logger.debug("Target page " + targetPage + " requested");

        }

         if  (targetPage != currentPage) {

             if  (!errors.hasErrors() || ( this .allowDirtyBack && targetPage < currentPage) ||

                    ( this .allowDirtyForward && targetPage > currentPage)) {

                 // Allowed to go to target page.

                 return  showPage(request, errors, targetPage);

            }

        }

 

         // Show current page again.

         return  showPage(request, errors, currentPage);

    }

 

     protected   int  getCurrentPage(HttpServletRequest request) {

         // Check for overriding attribute in request.

        String pageAttrName = getPageSessionAttributeName(request);

        Integer pageAttr = (Integer) request.getAttribute(pageAttrName);

         if  (pageAttr !=  null ) {

             return  pageAttr.intValue();

        }

         // Check for explicit request parameter.

        String pageParam = request.getParameter( PARAM_PAGE );

         if  (pageParam !=  null ) {

             return  Integer. parseInt (pageParam);

        }

         // Check for original attribute in session.

         if  (isSessionForm()) {

            pageAttr = (Integer) request.getSession().getAttribute(pageAttrName);

             if  (pageAttr !=  null ) {

                 return  pageAttr.intValue();

            }

        }

         throw   new  IllegalStateException(

                "Page attribute [" + pageAttrName + "] neither found in session nor in request");

    }

 

     protected   boolean  isFinishRequest(HttpServletRequest request) {

         return  WebUtils.hasSubmitParameter(request,  PARAM_FINISH );

    }

 

     protected   boolean  isCancelRequest(HttpServletRequest request) {

         return  WebUtils.hasSubmitParameter(request,  PARAM_CANCEL );

    }

 

     protected   int  getTargetPage(HttpServletRequest request, Object command, Errors errors,  int currentPage) {

         return  getTargetPage(request, currentPage);

    }

 

     protected   int  getTargetPage(HttpServletRequest request,  int  currentPage) {

         //  缺省情况下,  _target 参数代表要导航的目标页面

         return  WebUtils.getTargetPage(request,  PARAM_TARGET , currentPage);

    }

 

     private  ModelAndView validatePagesAndFinish(

            HttpServletRequest request, HttpServletResponse response, Object command, BindException errors,

             int  currentPage)  throws  Exception {

 

         // In case of binding errors -> show current page.

         if  (errors.hasErrors()) {

             return  showPage(request, errors, currentPage);

        }

 

         if  (!suppressValidation(request, command, errors)) {

             // In case of remaining errors on a page -> show the page.

             for  ( int  page = 0; page < getPageCount(request, command); page++) {

                validatePage(command, errors, page,  true );

                 if  (errors.hasErrors()) {

                     return  showPage(request, errors, page);

                }

            }

        }

 

         // No remaining errors -> proceed with finish.

         return  processFinish(request, response, command, errors);

    }

   

     protected   void  validatePage(Object command, Errors errors,  int  page,  boolean  finish) {

        validatePage(command, errors, page);

    }

 

     protected   void  validatePage(Object command, Errors errors,  int  page) {

    }

 

     //  子类根据业务逻辑改写

     protected   void  postProcessPage(HttpServletRequest request, Object command, Errors errors,  int page)

             throws  Exception {

    }

 

     //  子类根据业务逻辑改写

     protected   abstract  ModelAndView processFinish(

            HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)

             throws  Exception;

 

     //  子类根据业务逻辑改写

     protected  ModelAndView processCancel(

            HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)

             throws  Exception {

 

         throw   new  ServletException(

                "Wizard form controller class [" + getClass().getName() + "] does not support a cancel operation");

    }

 

}

Servlet包装控制器简单的封装了一个内部的Servlet实例。如下代码所示,

public   class  ServletWrappingController  extends  AbstractController

     implements  BeanNameAware, InitializingBean, DisposableBean {

   

     //  包装的 Servlet 类名,它必须是一个 Servlet 的完全实现类

     private  Class servletClass;

 

     // Servlet 的名称

     private  String servletName;

 

     // Servlet 的初始化参数

     private  Properties initParameters =  new  Properties();

 

     //  可选的 Bean

     private  String beanName;

 

     //  创建的内部 Servlet 实例

     private  Servlet servletInstance;

 

 

     public   void  setServletClass(Class servletClass) {

         this .servletClass = servletClass;

    }

 

 

     public   void  setServletName(String servletName) {

         this .servletName = servletName;

    }

 

     public   void  setInitParameters(Properties initParameters) {

         this .initParameters = initParameters;

    }

 

     public   void  setBeanName(String name) {

         this .beanName = name;

    }

 

     //  初始化方法继承

     public   void  afterPropertiesSet()  throws  Exception {

         // servlet 类必须存在,而且是 Servlet 的一个实现类

         if  ( this .servletClass ==  null ) {

             throw   new  IllegalArgumentException("servletClass is required");

        }

         if  (!Servlet. class .isAssignableFrom( this .servletClass)) {

             throw   new  IllegalArgumentException("servletClass [" +  this .servletClass.getName() +

                "] needs to implement interface [javax.servlet.Servlet]");

        }

       

         //  如果 Servlet 名不存在,使用 Bean

         if  ( this .servletName ==  null ) {

             this .servletName =  this .beanName;

        }

       

         //  创建一个 Servlet 实例

         this .servletInstance = (Servlet)  this .servletClass.newInstance();

       

         //  模拟调用 Servlet 的初始化方法

         this .servletInstance.init( new  DelegatingServletConfig());

    }

 

    @Override

     protected  ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)

         throws  Exception {

 

         //  适配 Servlet 的服务方法,用于重用已存的 Servlet 实现的逻辑

         this .servletInstance.service(request, response);

         return   null ;

    }

 

 

     public   void  destroy() {

         //  模拟调用析构方法

         this .servletInstance.destroy();

    }

 

 

     private   class  DelegatingServletConfig  implements  ServletConfig {

 

         public  String getServletName() {

             //  配置的 Sevlet 名或者 Bean

             return  servletName;

        }

 

         public  ServletContext getServletContext() {

             //  Web 应用程序环境传递进来的真正的 Sevlet 环境

             return  ServletWrappingController. this .getServletContext();

        }

 

         public  String getInitParameter(String paramName) {

             //  可配置的初始化参数

             return  initParameters.getProperty(paramName);

        }

 

         public  Enumeration getInitParameterNames() {

             return  initParameters.keys();

        }

    }

 

}

Servlet转发控制器通过Servlet转发派遣器转发HTTP请求到一个标准的web.xml定义的Servlet组件。如下代码所示,

public   class  ServletForwardingController  extends  AbstractController  implements  BeanNameAware {

 

     // Servlet 名称

     private  String servletName;

 

     //  如果没有制定 Servlet 名称,则使用 Bean 名称

     private  String beanName;

   

     public   void  setServletName(String servletName) {

         this .servletName = servletName;

    }

 

     public   void  setBeanName(String name) {

         this .beanName = name;

         if  ( this .servletName ==  null ) {

             this .servletName = name;

        }

    }

 

 

    @Override

     protected  ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)

             throws  Exception {

 

         //  取得 Servlet 的转发派遣器

        RequestDispatcher rd = getServletContext().getNamedDispatcher( this .servletName);

         if  (rd ==  null ) {

             throw   new  ServletException("No servlet with name '" +  this .servletName + "' defined in web.xml");

        }

         // If already included, include again, else forward.

         if  (useInclude(request, response)) {

            rd.include(request, response);

             if  (logger.isDebugEnabled()) {

                logger.debug("Included servlet [" +  this .servletName +

                        "] in ServletForwardingController '" +  this .beanName + "'");

            }

        }

         else  {

             //  使用容器提供的请求派遣功能,转发 HTTP 请求到 Servlet 进行处理

            rd.forward(request, response);

             if  (logger.isDebugEnabled()) {

                logger.debug("Forwarded to servlet [" +  this .servletName +

                        "] in ServletForwardingController '" +  this .beanName + "'");

            }

        }

         return   null ;

    }

 

     protected   boolean  useInclude(HttpServletRequest request, HttpServletResponse response) {

         //  如果它是显示的包含请求或者它已经设置的响应状态代码

         return  (WebUtils.isIncludeRequest(request) || response.isCommitted());

    }

 

}

 

URL文件名视图控制器继承自抽象URL视图控制器。抽象URL视图控制器通过URL决定视图名称,并且返回包含此视图的模型和视图对象。然后,具体如何映射URL到视图名,子类需要根据业务逻辑进行实现。如下代码所示,

public   abstract   class  AbstractUrlViewController  extends  AbstractController {

 

    @Override

     protected  ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {

         //  取得查找路径,用于日志

        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

       

         //  根据请求 URL 决定视图名

        String viewName = getViewNameForRequest(request);

         if  (logger.isDebugEnabled()) {

            logger.debug("Returning view name '" + viewName + "' for lookup path [" + lookupPath +"]");

        }

         return   new  ModelAndView(viewName);

    }

   

     // 子类根据业务逻辑实现映射过程

     protected   abstract  String getViewNameForRequest(HttpServletRequest request);

 

}

 

public   class  UrlFilenameViewController  extends  AbstractUrlViewController {

     protected  String getViewNameForRequest(HttpServletRequest request) {

         //  提取基于请求映射的路径或者查找路径

        String uri = extractOperableUrl(request);

         return  getViewNameForUrlPath(uri);

    }

   

     protected  String extractOperableUrl(HttpServletRequest request) {

         //  首先使用基于请求映射的路径

        String urlPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);

       

         //  如果没有基于请求映射的路径,则使用查找路径

         if  (!StringUtils.hasText(urlPath)) {

            urlPath = getUrlPathHelper().getLookupPathForRequest(request);

        }

         return  urlPath;

    }

   

     protected  String getViewNameForUrlPath(String uri) {

        String viewName =  this .viewNameCache.get(uri);

         if  (viewName ==  null ) {

             //  URI 中提取视图名

            viewName = extractViewNameFromUrlPath(uri);

             //  添加配置的前缀和后缀

            viewName = postProcessViewName(viewName);

             this .viewNameCache.put(uri, viewName);

        }

         return  viewName;

    }

   

     protected  String extractViewNameFromUrlPath(String uri) {

         //  去除前缀 / 好后缀 .*

         int  start = (uri.charAt(0) == '/' ? 1 : 0);

         int  lastIndex = uri.lastIndexOf(".");

         int  end = (lastIndex < 0 ? uri.length() : lastIndex);

         return  uri.substring(start, end);

    }

   

     protected  String postProcessViewName(String viewName) {

         return  getPrefix() + viewName + getSuffix();

    }

}

可参数化视图控制器的代码非常简单,这里不再进行代码注释。

转载请注明出处【 http://sishuok.com/article-detail.html?t=article-118&n=5372 】