美文网首页
SpringMVC-View和ViewResolver

SpringMVC-View和ViewResolver

作者: 张明学 | 来源:发表于2020-07-26 18:56 被阅读0次

springmvc由HandlerAdapter执行具体的handler后,返回的是ModelAndView对象,如何映射到具体的视图,生成页面返回到浏览器,就需要ViewResolver和View来操作了。

View的解析流程

1、org.springframework.web.servlet.DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
   try {
      ModelAndView mv = null;
      Exception dispatchException = null;
      try {
         ...
         // Actually invoke the handler.
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                ...
      }
      // 目标方法执行完成后的视图处理
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
      ...
   }
   ....
}

2、在processDispatchResult方法中调用了DispatcherServlet#render方法

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
      @Nullable Exception exception) throws Exception {
   ....
   // Did the handler return a view to render?
   if (mv != null && !mv.wasCleared()) {
      render(mv, request, response);
      ...
   }
}

3、org.springframework.web.servlet.DispatcherServlet#render

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
     ...
   View view;
   String viewName = mv.getViewName();
   if (viewName != null) {
      // 根据viewName找查resolve
      view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
     ...
   }
   else {
      // No need to lookup: the ModelAndView object contains the actual View object.
      view = mv.getView();
   }
     ...
   try {
      if (mv.getStatus() != null) {
         response.setStatus(mv.getStatus().value());
      }
      // 获取渲染的视图
      view.render(mv.getModelInternal(), request, response);
   }
   ...
}

resolveViewName方法如下:

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;
}

viewResolvers则是DispatcherServlet初始化时设置的,并且经过order排序之后的

4、org.springframework.web.servlet.view.AbstractView#render

public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
      HttpServletResponse response) throws Exception {
   Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
   prepareResponse(reuest, response);
   // 获取OutputStreaml输出的内容,不用同视图解决有不同的实现
   renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}

FastJsonJsonView的renderMergedOutputModel实现

protected void renderMergedOutputModel(Map<String, Object> model, //
                                       HttpServletRequest request, //
                                       HttpServletResponse response) throws Exception {

    ByteArrayOutputStream outnew = new ByteArrayOutputStream();
        
    int len = JSON.writeJSONString(outnew, //
            fastJsonConfig.getCharset(), //
            value, //
            fastJsonConfig.getSerializeConfig(), //
            fastJsonConfig.getSerializeFilters(), //
            fastJsonConfig.getDateFormat(), //
            JSON.DEFAULT_GENERATE_FEATURE, //
            fastJsonConfig.getSerializerFeatures());
  
    ServletOutputStream out = response.getOutputStream();
    outnew.writeTo(out);
    outnew.close();
    out.flush();
}

InternalResourceView的renderMergedOutputModel的实现

protected void renderMergedOutputModel(
      Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
   exposeModelAsRequestAttributes(model, request);
   exposeHelpers(request);
   String dispatcherPath = prepareForRendering(request, response);
   RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
   if (useInclude(request, response)) {
      response.setContentType(getContentType());
      rd.include(request, response);
   }else {
      rd.forward(request, response);
   }
}

常用的ViewResolver

ViewResolver的主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对象呈现给客户端的是View对象本身,而ViewResolver只是把逻辑视图名称解析为对象的View对象。View接口的主要作用是用于处理视图,然后返回给客户端。

IDE根据一个接口生产它的关系图方法:接口下右键Diagrams->Show Diagram,然后选中接口右键Show Implementations

ViewResolver.png
  • AbstractCachingViewResolver

    这是一个抽象类,这种视图解析器会把它曾经解析过的视图保存起来,然后每次要解析视图的时候先从缓存里面找,如果找到了对

    应的视图就直接返回,如果没有就创建一个新的视图对象,然后把它放到一个用于缓存的map中,接着再把新建的视图返回。使用这

    种视图缓存的方式可以把解析视图的性能问题降到最低。

  • UrlBasedViewResolver

    它是对ViewResolver的一种简单实现,而且继承了 AbstractCachingViewResolver,主要就是提供的一种拼接URL的方式来解析视图,它可以让我们通过prefix属性指定一个指定的前缀,通过suffix属性指定一个指定的后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是指定的视图URL了。如prefix=/WEB-INF/jsps/suffix=.jsp,返回的视图名称viewName=test/indx, 则UrlBasedViewResolver解析出来的视图URL就是/WEB-INF/jsps/test/index.jsp

  • InternalResourceViewResolver

    InternalResourceViewResolver会把返回的视图名称都解析为InternalResourceView对象,InternalResourceView会把Controller处理器方法返回的模型属性都存放到对应的request属性中,然后通过RequestDispatcher在服务器端把请求forword重定向到目标URL。

相关文章

网友评论

      本文标题:SpringMVC-View和ViewResolver

      本文链接:https://www.haomeiwen.com/subject/kclglktx.html