视图解析

概述

1、Spring Boot 处理请求,完成后跳转到指定页面的过程

2、视图处理方式

(1)转发

(2)重定向

(3)自定义视图

3、Spring Boot 打包方式为 jar,JSP 不支持在压缩包内编译,需要引入第三方模板引擎技术实现页面渲染

4、Spring Boot 可引入的第三方模板引擎

(1)spring-boot-starter-freemarker

(2)spring-boot-starter-groovy-templates

(3)spring-boot-starter-mustache

(4)spring-boot-starter-thymeleaf

 

原理流程

1、目标方法处理的过程中,ModelAndViewContainer 存放所有数据,包括模型数据和视图地址

2、方法的参数是一个自定义类型对象(由请求参数确定),会将其重新封装到 ModelAndViewContainer

3、任何目标方法执行完成后,都会返回 ModelAndView(模型数据和视图地址)

4、processDispatchResult 处理派发结果,即页面如何响应

5、render(mv, request, response); 进行页面渲染逻辑

6、view = resolveViewName(viewName, mv.getModelInternal(), locale, request); 渲染页面(View 接口定义页面的渲染逻辑)

(1)遍历 viewResolvers,即所有的视图解析器,判断是否可以根据当前返回值,得到 View 对象

(2)viewResolvers 包含所有视图解析器,如:ContentNegotiatingViewResolver、BeanNameViewResolver、ThymeleafViewResolver、ViewResolverComposite、lnternalResourceViewResolver

(3)ContentNegotiatingViewResolver 包含 BeanNameViewResolver、ThymeleafViewResolver、ViewResolverComposite、lnternalResourceViewResolver

(4)获取最佳匹配 View 对象

7、view.render(mv.getModelInternal(), request, response); 视图对象调用自定义的 render 进行页面渲染工作

8、Thymeleaf 底层:不同路径,视图 render 不同,视图解析器根据不同规则,渲染输出不同视图

(1)返回值以 forward: 开始:new InternalResourceView(forwardUrl); -> request.getRequestDispatcher(path).forward(request, response); -> render 为转发

(2)返回值以 redirect: 开始: new RedirectView(); -> render 为重定向

(3)返回值为普通字符串:new ThymeleafView(); -> render 为渲染页面片段,并将页面内容输出

9、源码

public class DispatcherServlet extends FrameworkServlet {

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                /*
            	mappedHandler:调用链,包含handler、interceptorList、interceptorIndex
            	handler:浏览器发送的请求所匹配的控制器方法
            	interceptorList:处理控制器方法的所有拦截器集合
            	interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行
                */
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
                //通过控制器方法创建相应的处理器适配器,调用所对应的控制器方法
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = HttpMethod.GET.matches(method);
                if (isGet || HttpMethod.HEAD.matches(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                //调用拦截器的preHandle()
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                //由处理器适配器调用具体的控制器方法,最终获得ModelAndView对象
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                //若没有视图,则以当前请求路径作为默认视图名
                applyDefaultViewName(processedRequest, mv);
                //调用拦截器的postHandle()
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            //后续处理:处理模型数据和渲染视图
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                                   new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable 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);
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }
        if (mv != null && !mv.wasCleared()) {
            //处理模型数据和渲染视图
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("No view rendering, null ModelAndView returned.");
            }
        }
        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            return;
        }
        if (mappedHandler != null) {
            //调用拦截器的afterCompletion()
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

    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;
        //从ModelAndView获取视图名
        String viewName = mv.getViewName();
        if (viewName != null) {
            //getModelInternal获取模型,resolveViewName解析视图名,获取视图对象
            view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
            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) {
                request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
                response.setStatus(mv.getStatus().value());
            }
            //视图对象调用自定义的render进行页面渲染工作
            view.render(mv.getModelInternal(), request, response);
        }
        catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error rendering view [" + view + "]", ex);
            }
            throw ex;
        }
    }

    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;
    }
}
posted @   半条咸鱼  阅读(62)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示