1. 程式人生 > >View 渲染

View 渲染

視圖解析 tag amp .com abs trac fix prot lin

在Spring MVC 中,controllers不負責具體的頁面渲染,僅僅是調用業務邏輯並返回model數據給view層,至於view層具體怎麽展現,由專門的view層具體負責,這就是MVC模式,業務層與展示層是松耦合的。那麽,Spring MVC是如何解耦合請求處理邏輯和頁面渲染的呢?

視圖解析器

請求進入DispathServlet後,通過HandlerMapping找到對應的HandlerExecutionChain,
最後交由HandlerAdapter來執行最終Handler【也就是Controller中的Action】,最終得到ModelAndView,然後再次交給DispatchServlet來處理,並執行render方法處理渲染邏輯,如下:

 1protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
2 Locale locale =
3 (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
4 response.setLocale(locale);
5
6 View view;
7 String viewName = mv.getViewName();
8 if (viewName != null) {
9 // 通過ViewResolver 來獲取真正的View對象
10 view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
11
12 }
13 }
14 else {
15 view = mv.getView();
16 }
17 }
18 try {
19 if (mv.getStatus() != null) {
20 response.setStatus(mv.getStatus().value());
21 }
22 //通過執行View對象的render方法來真正執行視圖渲染的邏輯
23 view.render(mv.getModelInternal(), request, response);
24 }
25 catch (Exception ex) {
26 throw ex;
27 }
28 }

 1    protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
2 Locale locale, HttpServletRequest request) throws Exception {
3
4 if (this.viewResolvers != null) {
5 for (ViewResolver viewResolver : this.viewResolvers) {
6//遍歷ViewResolver集合 來獲取合適的ViewResolver 對象
7 View view = viewResolver.resolveViewName(viewName, locale);
8 if (view != null) {
9 return view;
10 }
11 }
12 }
13 return null;
14 }

Spring MVC其實就是通過遍歷ViewResolvers這種視圖解析器集合,根據視圖名來找到找到真正的物理視圖【view頁面】,對於普通的JSP頁面,最常用到的view resolver就是InternalResourceViewResolver,它有兩個屬性,一個是匹配物理view的前綴,一個是後綴。前綴一般就是view頁面的路徑位置,後綴就是文件的格式,而前綴後綴之間的就是邏輯view名稱。

1<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
2 <property name="prefix" value="/WEB-INF/views/" />
3 <property name="suffix" value=".jsp" />
4</bean>
5

比如按照上面的配置,如果controller返回的邏輯view名稱是home的話,InternalResourceViewResolver會根據這個邏輯view名home找到其對應的實際物理view:/WEB-INF/views/home.jsp。

下面我們在看下視圖解析器的定義如下,就一個方法resolveViewName,根據視圖名稱和Local對象得到最終的View視圖

1public interface ViewResolver {
2 @Nullable
3 View resolveViewName(String viewName, Locale locale) throws Exception;
4}

視圖渲染

如上,通過視圖解析器ViewResolver 最終會得到視圖View,然後會通過調用View對象的render方法來真正執行視圖渲染的邏輯,View對象的定義如下

1public interface View {
2
3 String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
4
5
6 void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
7 throws Exception;
8
9}

不同的實現類有不同的視圖效果:

1、VelocityView是用來和Velocity框架結合生成頁面視圖

2、FreeMarkerView是用來和FreeMarker框架結合生成頁面視圖

3、JstlView是用來生成jstl頁面

4、RedirectView是生成頁面跳轉視圖的。

看下View的實現邏輯AbstractView源碼如下

 1    public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
2 HttpServletResponse response) throws Exception {
3
4//將model和request中的參數全部放到mergedModel中
5Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
6//存放頭部信息
7 prepareResponse(request, response);
8////將mergedModel中的參數值放到request中
9 renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
10 }

其實就根據ModelAndView和Request中的數據,加載視圖,然後寫入到Response中(先設置ContentType),最後輸出給用戶。

微信公眾號:宋坤明
更多精彩請參考 完整版系列 請參考此博文 也可以直接關註我

技術分享圖片

View 渲染