摘要:概述本章開始進入另一重要的組件,即視圖組件,處理視圖組件使用兩個主要的接口是和。接口的作用是用于處理視圖進行渲染。延用之前的介紹流程,本章分兩部分進行闡述啟動初始化和請求處理。
概述
本章開始進入另一重要的組件,即視圖組件,Spring MVC處理視圖組件使用兩個主要的接口是ViewResolver和View。根據名稱可知,ViewResolver即視圖解析器,其作用是把邏輯視圖名稱解析為真正的視圖,然后通過View對象進行渲染。View接口的作用是用于處理視圖進行渲染。
延用之前的介紹流程,本章分兩部分進行闡述:啟動初始化和請求處理。
本系列文章是基于Spring5.0.5RELEASE。
ViewResolver初始化Spring MVC初始化視圖解析器策略與初始化其他策略一樣,其入口是DispatcherSerlvet的initStrategies(context)方法,代碼如下:
/** *初始化策略對象 */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); // 初始化視圖解析器ViewResolver initViewResolvers(context); initFlashMapManager(context); }
看過之前文章的可以了解,此方法是Spring MVC初始化策略組件的入口。針對視圖解析器組件,調用initViewResolver(context)方法,加載視圖處理策略,該方法源碼如下:
private void initViewResolvers(ApplicationContext context) { // viewResolvers是視圖解析器集合,接收到用戶請求時,從該屬性變量中獲取到Spring MVC使用的視圖解析器 this.viewResolvers = null; // 是否從Spring上下文中加載ViewResolver,detectAllViewResolvers屬性變量默認為true,可在web部署描述文件中修改 if (this.detectAllViewResolvers) { // Find all ViewResolvers in the ApplicationContext, including ancestor contexts. // 按接口類型ViewResolver查找全部 // key為bean的id(name),value為bean的class對象 MapmatchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.viewResolvers = new ArrayList<>(matchingBeans.values()); // We keep ViewResolvers in sorted order. // 對ViewResolver進行排序,通過Ordered接口實現 AnnotationAwareOrderComparator.sort(this.viewResolvers); } } else { try { // 從Spring上下文中加載指定名字為"viewResolver"的bean,作為視圖解析器 ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class); this.viewResolvers = Collections.singletonList(vr); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we"ll add a default ViewResolver later. } } // Ensure we have at least one ViewResolver, by registering // a default ViewResolver if no other resolvers are found. // 為了確保至少有一個ViewResolver視圖解析器,Spring MVC配置了默認的ViewResolver // 在DispatcherServlet.properties文件中定義,默認為InternalResourceViewResolver if (this.viewResolvers == null) { this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); if (logger.isDebugEnabled()) { logger.debug("No ViewResolvers found in servlet "" + getServletName() + "": using default"); } } }
至此,Spring MVC即完成加載初始化ViewResolver視圖解析器,即Spring MVC以具備解析處理邏輯視圖名稱的能力。
ViewResolver使用ViewResolver的使用是指用戶發起請求到Spring,Spring MVC經過HandlerMapping查找處理的handler,然后通過HandlerAdapter進行適配后處理用戶請求,返回ModelAndView,最后使用ViewResolver對ModelAndView進行解析,即把邏輯視圖名解析為真正的視圖對象,由視圖對象進行渲染的過程。
用戶的請求處理流程由DispatcherServlet的doDispatcher(request,response)方法進行控制,主要代碼如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... ... // 找到請求對應的handler mappedHandler = getHandler(processedRequest); ... ... // 找到對應handler的適配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); ... ... // 執行用戶請求的攔截器前置處理方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 調用實際的handler處理方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ... ... // 設置默認的邏輯視圖名稱 // 如果handler返回null或者ViewName屬性為null時,Spring進行取視圖規則為:前綴+url+后綴 // 比如訪問url為:http://localhost:8086/test,前綴配置/WEB-INF/jsp,后綴配置為.jsp,那么最終查找的是:/WEB-INF/jsp/test.jsp applyDefaultViewName(processedRequest, mv); // 執行用戶請求的攔截器后置處理方法 mappedHandler.applyPostHandle(processedRequest, response, mv); ... ... // processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } /* *處理結果 */ private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable 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? // 調用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); } } /* *渲染ModelAndView */ protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; // 獲取邏輯視圖名稱 String viewName = mv.getViewName(); if (viewName != null) { // We need to resolve the view name. // 根據邏輯視圖名解析視圖,返回View對象 // 此處是視圖解析器使用入口,見下面的方法 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name "" + mv.getViewName() + "" in servlet with name "" + getServletName() + """); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name "" + getServletName() + """); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name "" + getServletName() + """); } try { if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } // 調用View的render方法進行視圖渲染 view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name "" + getServletName() + """, ex); } throw ex; } } @Nullable protected View resolveViewName(String viewName, @Nullable Map總結model, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { // 調用ViewResovler接口入口方法 View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }
本章概述了Spring MVC加載視圖解析器策略,并且找到了ViewResolver的入口方法,下面的章節繼續學習ViewResolver接口的實現類。
最后創建了qq群方便大家交流,可掃描加入,同時也可加我qq:276420284,共同學習、共同進步,謝謝!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69637.html
摘要:概述本節學習下的功能,簡單來說,該類的作用就是把多個視圖解析器進行組裝,內部使用存儲配置使用的視圖解析器。總結本章介紹了類,根據測試,了解到屬性不影響中配置使用的視圖解析器順序。 概述 本節學習下ViewResolverComposite的功能,簡單來說,該類的作用就是把多個ViewResolver視圖解析器進行組裝,內部使用list存儲配置使用的視圖解析器。 本系列文章是基于Spri...
摘要:概述上篇學習了視圖解析器作用及處理流程,為我們提供了豐富的視圖解析器見下圖本系列文章是基于。該視圖解析器是根據處理器返回的邏輯視圖名稱,在應用上下文中查找該名稱的視圖對象視圖對象就是的對象。 概述 上篇學習了Spring MVC ViewResolver視圖解析器作用及處理流程,Spring為我們提供了豐富的視圖解析器(見下圖):showImg(https://segmentfault...
摘要:概述本章繼續學習另一個實現類解析器,該類的主要作用是根據同一請求的某些策略,選擇對應的進行渲染。可以把理解為適配器,對不同類型進行適配。值得注意的是處理的為同一個。本系列文章是基于。實戰需求目標實現后綴名或參數控制,顯示不同的視圖。 概述 本章繼續學習ViewResolver另一個實現類ContentNegotiatingViewResolver解析器,該類的主要作用是根據同一請求的某...
摘要:與一樣,該類繼承抽象類,并且通過外部的屬性文件定義邏輯視圖名稱與真正的視圖對象的關系,屬性文件默認是下的,可以通過或屬性來指定,該屬性指的是文件的基名稱,也就是說以屬性值開頭的屬性文件。 概述 本章再學習另外兩個ViewResolver,分別是XmlViewResolver和ResourceBundleViewResolver,從功能上說,這兩個視圖解析器都是從外部資源文件中查找視圖V...
摘要:此解析器與差不多,更改下配置文件中的類全路徑即可。總結本章介紹了以及三個視圖解析器。這部分內容有點兒多,我會盡快結束。 概述 通過上幾篇的學習,我們分析了并試驗了ViewResolverComposite、BeanNameViewResolver和ContentNegotiatingViewResolver,這三個類都直接實現ViewResolver接口。Spring MVC提供了很多...
閱讀 2436·2019-08-30 15:52
閱讀 2237·2019-08-30 12:51
閱讀 2833·2019-08-29 18:41
閱讀 2812·2019-08-29 17:04
閱讀 811·2019-08-29 15:11
閱讀 1720·2019-08-28 18:02
閱讀 3603·2019-08-26 10:22
閱讀 2510·2019-08-26 10:12