springmvc 之视图解析器源码分析
来源:互联网 发布:mysql-5.5.57安装 编辑:程序博客网 时间:2024/05/18 15:56
springmvc在处理器方法中通常返回的是逻辑视图,如何定位到真正的页面,就需要通过视图解析器。
springmvc里提供了多个视图解析器,InternalResourceViewResolver就是其中之一:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/PAGE/" /> <property name="suffix" value=".jsp" /> </bean>
现在源码分析什么时候用到视图解析器
拿doGet方法举例子
FrameworkServlet类
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //省略 doService(request, response); //省略 }
DispatcherServlet 类
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { //省略 doDispatch(request, response); //省略 }
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { //省略 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); //省略 }
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, 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); //如果自己配置了自定义的HandlerExceptionResolver将会在这个方法里处理 这个放到下一篇说吧 mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } if (mv != null && !mv.wasCleared()) { // 解析视图并进行视图的渲染 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } //省略 }
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { //省略 // 由ViewResolver解析View view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); //省略 //视图在渲染时会把Model传入 view.render(mv.getModelInternal(), request, response); }
循环遍历你配置的视图解析器,viewResolvers是进过order排序的
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; }
我们这里是InternalResourceViewResolver继承了AbstractCachingViewResolver
该方法首先会判断有没有缓存,要是有缓存,它会先去缓存中通过viewName查找是否有View对象的存在,要是没有,它会通过viewName创建一个新的View对象,并将View对象存入缓存中,这样再次遇到同样的视图名的时候就可以直接在缓存中取出View对象了
@Override 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.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); if (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]"); } } } } } return (view != UNRESOLVED_VIEW ? view : null); } }
AbstractCachingViewResolver
protected View createView(String viewName, Locale locale) throws Exception { return loadView(viewName, locale); }
InternalResourceViewResolver继承了UrlBasedViewResolver
UrlBasedViewResolver
protected View loadView(String viewName, Locale locale) throws Exception { AbstractUrlBasedView view = buildView(viewName); View result = applyLifecycleMethods(viewName, view); return (view.checkResource(locale) ? result : null); }
UrlBasedViewResolver的buildView方法会获取一个View对象,这个对象会将视图以什么格式呈现给用户,例如如果是jsp显示呈现给用户的话,那这个view对象就是JstlView,默认的是JstlView。在这个方法中我们看到了getPrefix() + viewName + getSuffix()这样一段代码,这就是对视图路径的一个拼接了,getPrefix()方法获取前缀,也就是我们在配置文件中配置的 <property name="prefix" value="/WEB-INF/PAGE/"/>
的value中的值了,getSuffix()方法就是获取后缀值了,也就是我们在配置文件中配置的<property name="suffix" value=".jsp"/>
的value中的值。这样就将将视图的物理路径找到了,并赋值到View的URL属性中去。
protected AbstractUrlBasedView buildView(String viewName) throws Exception { AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); view.setUrl(getPrefix() + viewName + getSuffix()); String contentType = getContentType(); if (contentType != null) { view.setContentType(contentType); } view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); Boolean exposePathVariables = getExposePathVariables(); if (exposePathVariables != null) { view.setExposePathVariables(exposePathVariables); } Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes(); if (exposeContextBeansAsAttributes != null) { view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes); } String[] exposedContextBeanNames = getExposedContextBeanNames(); if (exposedContextBeanNames != null) { view.setExposedContextBeanNames(exposedContextBeanNames); } return view; }
就这样我们得到了一个View对象,这个视图的name就是逻辑视图名,因为当将View对象放在缓存的时候,我们可以通过逻辑视图名在缓存中找出View对象。我们在获取到View对象的时候,我们还要将View进行渲染,并呈现给用户。我们再来看看View中的render方法。
View是个接口,View由AbstractView实现。AbstractView中的render方法
@Override public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Rendering view with name '" + this.beanName + "' with model " + model + " and static attributes " + this.staticAttributes); } //主要是将一些属性填充到Map中 Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); //主要是对response头进行了一些属性设置 prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }
renderMergedOutputModel方法由AbstractView的孙子类InternalResourceView实现
InternalResourceView的renderMergedOutputModel方法
我们获取到视图的物理路径,然后将这段路径传给RequestDispatcher对象,再调用RequestDispatcher的forward方法将页面呈现给用户,这样就走完了视图的解析了。
@Override protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // Expose the model object as request attributes. exposeModelAsRequestAttributes(model, request); // Expose helpers as request attributes, if any. exposeHelpers(request); // Determine the path for the request dispatcher. String dispatcherPath = prepareForRendering(request, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!"); } // If already included or response already committed, perform include, else forward. if (useInclude(request, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } rd.include(request, response); } else { // Note: The forwarded resource is supposed to determine the content type itself. if (logger.isDebugEnabled()) { logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } rd.forward(request, response); } }
- springmvc 之视图解析器源码分析
- springMVC源码分析--ViewResolver视图解析器(一)
- Javaweb学习之SpringMVC视图解析器的分析
- springmvc之视图和视图解析器
- springmvc之视图和视图解析器
- SpringMVC 各类 视图解析器分析
- SpringMVC 各类 视图解析器分析
- Springmvc视图解析器InternalResourceViewResolver问题分析
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
- springMVC源码解析--ViewResolver视图解析器执行(三)
- SpringMVC介绍之视图解析器ViewResolver
- SpringMVC介绍之视图解析器ViewResolver
- SpringMVC介绍之视图解析器ViewResolver
- SpringMVC介绍之视图解析器ViewResolver
- SpringMVC介绍之视图解析器ViewResolver
- SpringMVC介绍之视图解析器ViewResolver
- SpringMVC介绍之视图解析器ViewResolver
- SpringMVC介绍之视图解析器ViewResolver
- 用类描述计算机中的CPU速度和硬盘的容量
- King
- 写给人类的机器学习 四、神经网络和深度学习
- 1.unity3d Astar pathfinding 第一个例子
- 使用node解析yaml文件
- springmvc 之视图解析器源码分析
- Mybatis(配置)
- Spring环境搭建
- Android--(12)--Fragment+ActionBar实现页面导航
- 在myeclipse中开发servlet
- Oracle安装报错:" Oracle Net Configuration Assistant" 失败
- elk安装教程2017
- StartActivity路上的mParent
- JAVA之冒泡排序—实现双色球机选小程序