SpringMVC 视图解析器流程分析

Spring视图解析器(ViewResolve)

视图解析器会将Controller中String的返回值(视图名)进行拼串。

@Controller
public class HelloController{
    @RequestMapping("/hello")
    public String hello(){
        return "../../hello";
    }
}
//forward:转发到一个页面
// /hello.jsp:转发到当前项目下的hello
@RequestMapping("/handle01")
public String handler01(){
    return "forward:/hello.jsp";
}

forward前缀可以实现多重跳转

@RequestMapping("/handle01")
public String handle01(){
    return "forward:/hello.jsp";
}
@RequestMappint("/handle02")
public String handle02(){
    return "forward:/handle01";
}

redirect也可以实现上述功能。有前缀的转发和重定向操作和视图解析器就不会进行拼串。

SpringMVC视图解析原理

  1. 方法执行后的返回值会作为页面地址参考,转发或重定向到页面。
  2. 视图解析器可能会进行页面地址的拼串。
processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException);

来到页面的方法

视图渲染流程,将域中的数据在页面展示,页面就是用来渲染模型数据的。

  1. 调用render(mv,request,response);渲染页面

  2. View与ViewResolver:
    ViewResolver的作用是根据视图名(ViewName,方法的返回值)得到view对象。

  3. 怎么能根据ViewName得到View对象。

@Nullable
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) {
            //viewResolver视图解析器根据方法的返回值,得到一个View对象;
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
    }
    return null;
}
@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对象
               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);
               }
            }
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace(formatKey(cacheKey) + "served from cache");
         }
      }
      return (view != UNRESOLVED_VIEW ? view : null);
   }
}
@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.
    //如果是以redirect结尾的视图名就创建一个redirect视图对象
    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);
    }

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

    // Else fall back to superclass implementation: calling loadView.
    //如果没有前缀,就是用父类默认创建一个View对象。
    return super.createView(viewName, locale);
}

通过以上流程会创建一个InternalResourceView,返回View对象。

视图解析器得到View对象的流程就是:

  1. 所有配置的视图解析器都来根据ViewName(方法的返回值)得到对象;如果能得到就返回,得不到就换下一个视图解析器。

  2. 调用View对象的Render方法。

//将模型域中的数据暴露在request域中。
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
                                              HttpServletRequest request) throws Exception {

    model.forEach((name, value) -> {
        if (value != null) {
            request.setAttribute(name, value);
        }
        else {
            request.removeAttribute(name);
        }
    });
}

将参数中Map方法中的数据放入request域。

View对象的作用就是进行转发域重定向,将数据放在request域中。视图解析器只是为了得到视图对象,视图对象才能真正转发或者重定向到页面。

mvc:view-controller标签

path指定哪个请求

<mvc:view-controller path="/toLoginPage" view-name=""/>

该标签可以走整个SpringMVC视图解析器流程。

mvc注解驱动模式

<mvc:annotation-driven></mvc:annotation-driven>

自定义视图解析器和视图

  1. 让视图解析器工作;
  2. 得到我们的视图对象;
  3. 我们的视图对象自定义渲染逻辑
response.getWriter().write("<h1> 即将展现精彩内容</h1>");
  1. 自定义视图解析器的步骤
    1. 编写自定义的视图解析器,和视图实现类。
    2. 将视图解析器添加到ioc容器中。
public class MyMeiNvViewResolver implements ViewResolver, Ordered {

    private int order = 0;
    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        if(viewName.startsWith("meinv:")){
            return new MyView();
        }else{
            return null;
        }
    }

    //Ordered接口规定了在InternalResourcesView中获得ResourceViews的访问顺序
    @Override
    public int getOrder() {
        return order;
    }
    public void setOrder(Integer order){
        this.order = order;
    }
}
  1. 自定义View
public class MyView implements View {
    @Override
    public String getContentType() {
        return "text/html";
    }
    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("之前保存的数据:"+model);
        response.setContentType("text/html");
        response.getWriter().write("<h1> 即将展现精彩内容</h1>");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值