真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

SpringMVC源碼分析6:SpringMVC的視圖解析原理

轉(zhuǎn)自  SpringMVC視圖機(jī)制詳解[附帶源碼分析]

創(chuàng)新互聯(lián)公司是一家專業(yè)提供濰坊企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站設(shè)計(jì)制作、網(wǎng)站建設(shè)、H5建站、小程序制作等業(yè)務(wù)。10年已為濰坊眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進(jìn)行中。

目錄

  • 前言
  • 重要接口和類介紹
  • 源碼分析
  • 編碼自定義的ViewResolver
  • 總結(jié)
  • 參考資料

前言

SpringMVC是目前主流的Web MVC框架之一。

如果有同學(xué)對(duì)它不熟悉,那么請(qǐng)參考它的入門blog: http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html

本文將分析SpringMVC的視圖這部分內(nèi)容,讓讀者了解SpringMVC視圖的設(shè)計(jì)原理。

重要接口和類介紹

1. View接口

視圖基礎(chǔ)接口,它的各種實(shí)現(xiàn)類是無(wú)狀態(tài)的,因此是線程安全的。 該接口定義了兩個(gè)方法:

SpringMVC源碼分析6:SpringMVC的視圖解析原理

2. AbstractView抽象類

View接口的基礎(chǔ)實(shí)現(xiàn)類。我們稍微介紹一下這個(gè)抽象類。

首先看下這個(gè)類的屬性:

SpringMVC源碼分析6:SpringMVC的視圖解析原理

再看下抽象類中接口方法的實(shí)現(xiàn):

getContentType方法直接返回contentType屬性即可。

SpringMVC源碼分析6:SpringMVC的視圖解析原理

render方法:

SpringMVC源碼分析6:SpringMVC的視圖解析原理

3. AbstractUrlBasedView抽象類

繼承自AbstractView抽象類,增加了1個(gè)類型為String的url參數(shù)。

4. InternalResourceView類

繼承自AbstractUrlBasedView抽象類的類,表示JSP視圖。

我們看下這個(gè)類的renderMergedOutputModel方法(AbstractView抽象類定義的抽象方法,為View接口提供的render方法服務(wù))。

SpringMVC源碼分析6:SpringMVC的視圖解析原理

5. JstlView類

JSTL視圖,繼承自InternalResourceView,該類大致上與InternalResourceView類一致。

6. AbstractTemplateView抽象類

繼承自AbstractUrlBasedView抽象類,重寫了renderMergedOutputModel方法,在該方法中會(huì)調(diào)用renderMergedTemplateModel方法,renderMergedTemplateModel方法為新定義的抽象方法。

該抽象類有幾個(gè)boolean屬性exposeSessionAttributes,exposeRequestAttributes。 設(shè)置為true的話會(huì)將request和session中的鍵值和值丟入到renderMergedTemplateModel方法中的model這個(gè)Map參數(shù)中。

這個(gè)類是某些模板引擎視圖類的父類。 比如FreemarkerView,VelocityView。

7. FreeMarkerView類

繼承自AbstractTemplateView抽象類。

直接看renderMergedTemplateModel方法,renderMergedTemplateModel內(nèi)部會(huì)調(diào)用doRender方法:

SpringMVC源碼分析6:SpringMVC的視圖解析原理

8. RedirectView類

繼承自AbstractUrlBasedView,并實(shí)現(xiàn)SmartView接口。SmartView接口定義了1個(gè)boolean isRedirectView();方法。

該視圖的renderMergedOutputModel方法主要就是通過(guò)response.sendRedirect進(jìn)行重定向。

有關(guān)RedirectView方面的知識(shí)樓主另外寫了1篇博客。 http://www.cnblogs.com/fangjian0423/p/springMVC-redirectView-analysis.html

9. ViewResolver接口

視圖解釋器,用來(lái)解析視圖View,與View接口配合使用。

該接口只有1個(gè)方法,通過(guò)視圖名稱viewName和Locale對(duì)象得到View接口實(shí)現(xiàn)類:

  View resolveViewName(String viewName, Locale locale) throws Exception;

10. AbstractCachingViewResolver抽象類

帶有緩存功能的ViewResolver接口基礎(chǔ)實(shí)現(xiàn)抽象類,該類有個(gè)屬性名為viewAccessCache的以 “viewName_locale” 為key, View接口為value的Map。

該抽象類實(shí)現(xiàn)的resolveViewName方法內(nèi)部會(huì)調(diào)用createView方法,方法內(nèi)部會(huì)調(diào)用loadView抽象方法。

11. UrlBasedViewResolver類

繼承自AbstractCachingViewResolver抽象類、并實(shí)現(xiàn)Ordered接口的類,是ViewResolver接口簡(jiǎn)單的實(shí)現(xiàn)類。

SpringMVC源碼分析6:SpringMVC的視圖解析原理

該類復(fù)寫了createView方法:

SpringMVC源碼分析6:SpringMVC的視圖解析原理

父類(AbstractCachingViewResolver)的createView方法內(nèi)部會(huì)調(diào)用loadView抽象方法,UrlBasedViewResolver實(shí)現(xiàn)了這個(gè)抽象方法:

SpringMVC源碼分析6:SpringMVC的視圖解析原理

SpringMVC源碼分析6:SpringMVC的視圖解析原理

下面對(duì)UrlBasedViewResolver做1個(gè)test,配置如下:


  
  
  
  
      
      *  
        
    
  
  
    
      
    
  
  
    
      testvalue
    
  

我們看到:以InternalResourceView這個(gè)JSP視圖作為視圖;viewNames我們?cè)O(shè)置了*,這里的*代表全部視圖名(這個(gè)viewNames屬性不設(shè)置也可以,代表全部視圖名都處理);http響應(yīng)頭部contentType信息:text/html;charset=utf-8;attributesMap和attributes傳入的Map和Properties參數(shù)都會(huì)被丟入到staticAttributes屬性中,這個(gè)staticAttributes會(huì)被設(shè)置成AbstractView的staticAttributes屬性,也就是request域中的參數(shù)。

SpringMVC源碼分析6:SpringMVC的視圖解析原理

SpringMVC源碼分析6:SpringMVC的視圖解析原理

SpringMVC源碼分析6:SpringMVC的視圖解析原理

我們看到request域中沒有設(shè)置mytest和testvalue值。但是頁(yè)面中會(huì)顯示,因?yàn)槲覀兣渲昧薬ttributesMap和attributes參數(shù)。

如果我們把viewNames中的"*“改成"index1”。那么就報(bào)錯(cuò)了,因?yàn)樘幚硪晥D名的時(shí)候index匹配不上index1。

SpringMVC源碼分析6:SpringMVC的視圖解析原理

12. InternalResourceViewResolver類

繼承自UrlBasedViewResolver,以InternalResourceView作為視圖,若項(xiàng)目中存在“javax.servlet.jsp.jstl.core.Config”該類,那么會(huì)以JstlView作為視圖。重寫了buildView方法,主要就是為了給InternalResourceView視圖設(shè)置屬性。

13. AbstractTemplateViewResolver類

繼承自UrlBasedViewResolver,重寫了buildView方法,主要就是構(gòu)造AbstractTemplateView以及為它設(shè)置相應(yīng)的屬性。

14. FreeMarkerViewResolver類

繼承自AbstractTemplateViewResolver,將視圖設(shè)置為FreeMarkerView。

15. ModelAndView對(duì)象

顧名思義,帶有視圖和Model屬性的一個(gè)模型和視圖類。

SpringMVC源碼分析6:SpringMVC的視圖解析原理

值得注意的是,這個(gè)視圖屬性是一個(gè)Object類型的數(shù)據(jù),可以直接是View接口的實(shí)現(xiàn)類或者視圖名(字符串)。

源碼分析

下面我們來(lái)分析SpringMVC處理視圖的源碼。

SpringMVC在處理請(qǐng)求的時(shí)候,通過(guò)RequestMappingHandlerMapping得到HandlerExecutionChain,然后通過(guò)RequestMappingHandlerAdapter得到1個(gè)ModelAndView對(duì)象,之后通過(guò)processDispatchResult方法處理。

processDispatchResult方法如下:

SpringMVC源碼分析6:SpringMVC的視圖解析原理

SpringMVC源碼分析6:SpringMVC的視圖解析原理

如果配置的ViewResolver如下:


  
  

那么就是使用InternalResourceViewResolver來(lái)解析視圖。

之前分析過(guò),InternalResourceViewResolver重寫了UrlBasedViewResolver的buildView方法。但是還是會(huì)調(diào)用UrlBasedViewResolver的buildView方法。

SpringMVC源碼分析6:SpringMVC的視圖解析原理

最終得到InternalResourceView或JstlView視圖。這兩個(gè)視圖的render方法本文介紹重要接口及類的時(shí)候已分析。

PS:DispathcerServlet中的viewResolvers屬性是個(gè)集合,如果存在多個(gè)ViewResolver對(duì)象,必定會(huì)有優(yōu)先級(jí)的問(wèn)題,這部分的內(nèi)容請(qǐng)參考樓主的另一篇博客:

http://www.cnblogs.com/fangjian0423/p/spring-Ordered-interface.html

編碼自定義的ViewResolver

下面,我們就來(lái)編寫自定義的ViewResolver。

自定義的ViewResolver處理視圖名的時(shí)候,遇到 “jsp:” 開頭的會(huì)找jsp頁(yè)面,遇到 “freemarker:” 開頭的找freemarker頁(yè)面。

public class CustomViewResolver extends UrlBasedViewResolver {
  public static final String JSP_URL_PREFIX = "jsp:";
  public static final String FTL_URL_PREFIX = "freemarker:";
  private static final boolean jstlPresent = ClassUtils.isPresent(
            "javax.servlet.jsp.jstl.core.Config", CustomViewResolver.class.getClassLoader());
  private Boolean exposePathVariables = false;
  private boolean exposeRequestAttributes = false;
  private boolean allowRequestOverride = false;
  private boolean exposeSessionAttributes = false;
  private boolean allowSessionOverride = false;
  private boolean exposeSpringMacroHelpers = true;
  public CustomViewResolver() {
      this.setViewClass(FreeMarkerView.class);
  }  
  @Override
  protected AbstractUrlBasedView buildView(String viewName) throws Exception { 
    if(viewName.startsWith(FTL_URL_PREFIX)) {
        return buildFreemarkerView(viewName.substring(FTL_URL_PREFIX.length()));
    } else if(viewName.startsWith(JSP_URL_PREFIX)) {
        Class viewCls = jstlPresent ? JstlView.class : InternalResourceView.class;
        return buildView(viewCls, viewName.substring(JSP_URL_PREFIX.length()), getPrefix(), ".jsp");
    } else {
        //默認(rèn)以freemarker處理
        return buildFreemarkerView(viewName);
    }
  }
  private AbstractUrlBasedView build(Class viewClass, String viewName, String prefix, String suffix) { 
    AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
    view.setUrl(prefix + viewName + suffix);
    String contentType = getContentType();
    if (contentType != null) {
        view.setContentType(contentType);
    }
    view.setRequestContextAttribute(getRequestContextAttribute());
    view.setAttributesMap(getAttributesMap());
    if (this.exposePathVariables != null) {
        view.setExposePathVariables(exposePathVariables);
    }
    return view;    
  }
  private AbstractUrlBasedView buildFreemarkerView(String viewName) throws Exception { 
    AbstractTemplateView view = (AbstractTemplateView) build(FreeMarkerView.class, viewName, "", getSuffix());
    view.setExposeRequestAttributes(this.exposeRequestAttributes);
    view.setAllowRequestOverride(this.allowRequestOverride);
    view.setExposeSessionAttributes(this.exposeSessionAttributes);
    view.setAllowSessionOverride(this.allowSessionOverride);
    view.setExposeSpringMacroHelpers(this.exposeSpringMacroHelpers);
    return view;      
  }
  //get set方法省略
}

xml配置:


  
  
  
  
  
  
  

  
  
  
    
      10
      zh_CN
      yyyy-MM-dd
      yyyy-MM-dd
      #.##
    
  

簡(jiǎn)單解釋一下:CustomViewResolver解析視圖名的時(shí)候,判斷 “jsp:” 和 “freemarker:” 開頭的名字,如果是 “jsp:” 開頭的,如果有JSTL依賴,構(gòu)造JSTLView視圖,否則構(gòu)造InternalResourceView視圖。如果是 “freemarker:” 構(gòu)造FreemarkerView。在構(gòu)造視圖之前分別會(huì)設(shè)置一些屬性。

xml配置:配置prefix是為了給jsp視圖用的,freemarker視圖不需要prefix,因?yàn)镕reemarkerView內(nèi)部會(huì)使用配置的FreeMarkerConfigurer,并用FreeMarkerConfigurer內(nèi)部的templateLoaderPath屬性作為前綴,配置的suffix是為了讓FreemarkerView使用,當(dāng)后綴。

最后附上Controller代碼:

@Controller
@RequestMapping(value = "/tvrc")
public class TestViewResolverController {
    @RequestMapping("jsp")
    public ModelAndView jsp(ModelAndView view) {
        view.setViewName("jsp:trvc/index");
        return view;
    }
    @RequestMapping("/ftl")
    public ModelAndView freemarker(ModelAndView view) {
        view.setViewName("freemarker:trvc/index");
        return view;
    }
}

視圖 /WEB-INF/view/trvc/index.jsp 中的的內(nèi)容是輸出

This is jsp page

視圖 /WEB-INF/view/trvc/index.ftl 中的的內(nèi)容是輸出

This is freemarker page

SpringMVC源碼分析6:SpringMVC的視圖解析原理

SpringMVC源碼分析6:SpringMVC的視圖解析原理

總結(jié)

本文分析了SpringMVC中的視圖機(jī)制,View和ViewResolver這兩個(gè)接口是視圖機(jī)制的核心,并分析了幾個(gè)重要的View和ViewResolver接口實(shí)現(xiàn)類,最終寫了一個(gè)區(qū)別jsp和freemarker視圖的ViewResolver實(shí)現(xiàn)類,讓讀者更加理解視圖機(jī)制。

希望這篇文章能幫助讀者了解SpringMVC視圖機(jī)制。

文中難免有錯(cuò)誤,希望讀者能夠指明出來(lái)。

SpringMVC源碼分析6:SpringMVC的視圖解析原理


文章名稱:SpringMVC源碼分析6:SpringMVC的視圖解析原理
轉(zhuǎn)載注明:http://weahome.cn/article/jsjgec.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部