欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Springmvc ViewResolver设计实现过程解析

程序员文章站 2022-03-31 08:44:26
总结:viewresolver 如果要改需要自己注入到容器中并进行修改, springmvc使用的是interresourceviewresoverview不需要自己改,是springmvc根据ret...

总结:

viewresolver 如果要改需要自己注入到容器中并进行修改, springmvc使用的是interresourceviewresover
view不需要自己改,是springmvc根据return返回值选的

既然看到有modelandview直接跳转jsp的, 有请求转发的,有重定向的,这里整体是怎么设计的: (@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()里的:

Springmvc ViewResolver设计实现过程解析

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()会根据不同的路径生成不同的view, return mav 会返回jstlview, return "forward:/patch" 会返回internalresourceview, return "direct:/patch" 会返回indirectview

2. 不同的view去走不同的view.render(), 根据不同的view重写abstract void rendermergedoutputmodel方法

Springmvc ViewResolver设计实现过程解析

再来看是如何生成不同的view:[/code][code]view = resolveviewname() 进去,走到
diapatcherservlet先有viewresolver这个,用来生成不同的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 接口只有一个方法

public interface viewresolver {
  @nullable
  view resolveviewname(string viewname, locale locale) throws exception;

}

要配置具体的视图解析器,springmvc中使用的是interresourceviewresover,interresourceviewresover 和他的父类urlbasedviewresolver中都没有重写resolveviewname方法,再上一层的父类abstractcahingviewresolver实现了resolveviewname方法

Springmvc ViewResolver设计实现过程解析

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方法,所以是调用它父类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"在这里构造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" 在这里构造view
    } 

    // else fall back to superclass implementation: calling loadview.
    return super.createview(viewname, locale);          // return mav 在这里构造view
  }

关于viewresolver的代码执行顺序, 前面分析那么多,这里再打断点快速验证一下:

进dispatcherservlet的dodispatch看到就是这个解析器:

Springmvc ViewResolver设计实现过程解析

断点放在这里,

Springmvc ViewResolver设计实现过程解析

然后下一步:

Springmvc ViewResolver设计实现过程解析

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。