Springmvc ViewResolver設(shè)計(jì)實(shí)現(xiàn)過程解析
總結(jié):
ViewResolver 如果要改需要自己注入到容器中并進(jìn)行修改, springmvc使用的是InterResourceViewResover
view不需要自己改,是springmvc根據(jù)return返回值選的
既然看到有ModelAndView直接跳轉(zhuǎn)jsp的, 有請(qǐng)求轉(zhuǎn)發(fā)的,有重定向的,這里整體是怎么設(shè)計(jì)的: (@ResponseBody的在此不作展開)
HiController:
@Controller public class HiController { @RequestMapping("/hi") public ModelAndView getHi() { ModelAndView mav = new ModelAndView("me"); return mav; } @RequestMapping("/yes") public String forwardYes() { return "forward:patch"; } @RequestMapping("/no") public String RedirectNo() { return "redirect:patch"; } @ResponseBody @RequestMapping("/patch") public String redirectNo() { return "from forward or redirect request"; // 這種情況沒有view,在這里不討論 } }
主要代碼:
DispatcherServlet.doDispatch()里的:
DispatcherServlet.render方法:
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 = resolveViewName(viewName, mv.getModelInternal(), locale, request); // 1 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.isTraceEnabled()) { logger.trace("Rendering view [" + view + "] "); } try { if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } view.render(mv.getModelInternal(), request, response); // 2 } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "]", ex); } throw ex; } }
1. view = resolveViewName()會(huì)根據(jù)不同的路徑生成不同的view, return mav 會(huì)返回JstlView, return "forward:/patch" 會(huì)返回InternalResourceView, return "direct:/patch" 會(huì)返回IndirectView
2. 不同的view去走不同的view.render(), 根據(jù)不同的view重寫abstract void renderMergedOutputModel方法
再來看是如何生成不同的view:[/code][code]view = resolveViewName() 進(jìn)去,走到
DiapatcherServlet先有ViewResolver這個(gè),用來生成不同的view
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }
ViewResolver 接口只有一個(gè)方法
public interface ViewResolver { @Nullable View resolveViewName(String viewName, Locale locale) throws Exception; }
要配置具體的視圖解析器,springMVC中使用的是InterResourceViewResover,InterResourceViewResover 和他的父類UrlBasedViewResolver中都沒有重寫resolveViewName方法,再上一層的父類AbstractCahingViewResolver實(shí)現(xiàn)了resolveViewName方法
AbstractCahingViewResolver:
@Override @Nullable public View resolveViewName(String viewName, Locale locale) throws Exception { if (!isCache()) { return createView(viewName, locale); } else { Object cacheKey = getCacheKey(viewName, locale); View view = this.viewAccessCache.get(cacheKey); if (view == null) { synchronized (this.viewCreationCache) { view = this.viewCreationCache.get(cacheKey); if (view == null) { // Ask the subclass to create the View object. view = createView(viewName, locale); if (view == null && this.cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null && this.cacheFilter.filter(view, viewName, locale)) { this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); } } } } else { if (logger.isTraceEnabled()) { logger.trace(formatKey(cacheKey) + "served from cache"); } } return (view != UNRESOLVED_VIEW ? view : null); } }
InterResourceViewResover中沒有createView方法,所以是調(diào)用它父類UrlBasedViewResolver的createView方法:
@Override protected View createView(String viewName, Locale locale) throws Exception { // If this resolver is not supposed to handle the given view, // return null to pass on to the next resolver in the chain. if (!canHandle(viewName, locale)) { return null; } // Check for special "redirect:" prefix. if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); String[] hosts = getRedirectHosts(); if (hosts != null) { view.setHosts(hosts); } return applyLifecycleMethods(REDIRECT_URL_PREFIX, view); // return "direct:/patch"在這里構(gòu)造view } // Check for special "forward:" prefix. if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); InternalResourceView view = new InternalResourceView(forwardUrl); return applyLifecycleMethods(FORWARD_URL_PREFIX, view); // return "forward:/patch" 在這里構(gòu)造view } // Else fall back to superclass implementation: calling loadView. return super.createView(viewName, locale); // return mav 在這里構(gòu)造view }
關(guān)于ViewResolver的代碼執(zhí)行順序, 前面分析那么多,這里再打斷點(diǎn)快速驗(yàn)證一下:
進(jìn)DispatcherServlet的doDispatch看到就是這個(gè)解析器:
斷點(diǎn)放在這里,
然后下一步:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫分表
本文主要介紹了SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫分表,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Java集合的總體框架相關(guān)知識(shí)總結(jié)
今天帶大家學(xué)習(xí)Java集合框架的相關(guān)知識(shí),文中有非常詳細(xì)的圖文介紹,對(duì)正在學(xué)習(xí)Java的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05Java中使用正則表達(dá)式獲取網(wǎng)頁中所有圖片的路徑
這篇文章主要介紹了Java中使用正則表達(dá)式獲取網(wǎng)頁中所有圖片的路徑,本文直接給出實(shí)例代碼,需要的朋友可以參考下2015-06-06Java實(shí)現(xiàn)的百度語音識(shí)別功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的百度語音識(shí)別功能,較為簡(jiǎn)明扼要的分析了Java調(diào)用百度語音接口相關(guān)操作步驟,并給出了具體的語音識(shí)別用法代碼示例,需要的朋友可以參考下2018-08-08