一、写在前面

前面我们分析了Spring boot是如何解析请求参数和如何处理相应信息的

那么它是如何进行视图解析,找到我们要跳转的视图并进行视图渲染的呢?

二、写个demo

为了研究视图解析原理,我们写一个测试代码

首先是控制器类IndexController.java

package com.decade.controller;
import com.decade.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpSession;
@Controller
public class IndexController {
    /**
     * 来登录页
     * @return 跳转登录页
     */
    @GetMapping(value = {"/","/login"})
    public String loginPage(){
        return "login";
    }
    @PostMapping("/login")
    public String main(User user, HttpSession session, Model model){
        if(StringUtils.hasLength(user.getUserName()) && "123456".equals(user.getPassword())){
            //把登陆成功的用户保存到session中
            session.setAttribute("loginUser", user);
            //登录成功重定向到main.html;  重定向防止刷新首页时表单重复提交
            return "redirect:/main.html";
        }else {
            model.addAttribute("msg","账号密码错误");
            //回到登录页面
            return "login";
        }
    }
    /**
     * 去main页面
     * @return 跳转主页面
     */
    @GetMapping("/main.html")
    public String mainPage(HttpSession session,Model model){
        //是否登录。  拦截器,过滤器
        Object loginUser = session.getAttribute("loginUser");
        if(loginUser != null){
            return "main";
        }else {
            //回到登录页面
            model.addAttribute("msg","请重新登录");
            return "login";
        }
    }
}

login.html放于templates文件夹下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="ThemeBucket">
    <link rel="shortcut icon" href="#" rel="external nofollow"  type="image/png">
    <title>Login</title>
    <link href="css/style.css" rel="external nofollow"  rel="stylesheet">
    <link href="css/style-responsive.css" rel="external nofollow"  rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
    <script src="js/html5shiv.js"></script>
    <script src="js/respond.min.js"></script>
    <![endif]-->
</head>
<body class="login-body">
<div class="container">
    <form class="form-signin" action="index.html" method="post" th:action="@{/login}">
        <div class="form-signin-heading text-center">
            <h1 class="sign-title">Sign In</h1>
            <img src="images/login-logo.png" alt=""/>
        </div>
        <div class="login-wrap">
            <label style="color: red" th:text="${msg}"></label>
            <input type="text" name="userName" class="form-control" placeholder="User ID" autofocus>
            <input type="password" name="password" class="form-control" placeholder="Password">
            <button class="btn btn-lg btn-login btn-block" type="submit">
                <i class="fa fa-check"></i>
            </button>
            <div class="registration">
                Not a member yet?
                <a class="" href="registration.html" rel="external nofollow" >
                    Signup
                </a>
            </div>
            <label class="checkbox">
                <input type="checkbox" value="remember-me"> Remember me
                <span class="pull-right">
                    <a data-toggle="modal" href="#myModal" rel="external nofollow" > Forgot Password?</a>
                </span>
            </label>
        </div>
        <!-- Modal -->
        <div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="myModal" class="modal fade">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                        <h4 class="modal-title">Forgot Password ?</h4>
                    </div>
                    <div class="modal-body">
                        <p>Enter your e-mail address below to reset your password.</p>
                        <input type="text" name="email" placeholder="Email" autocomplete="off" class="form-control placeholder-no-fix">
                    </div>
                    <div class="modal-footer">
                        <button data-dismiss="modal" class="btn btn-default" type="button">Cancel</button>
                        <button class="btn btn-primary" type="button">Submit</button>
                    </div>
                </div>
            </div>
        </div>
        <!-- modal -->
    </form>
</div>
<script src="js/jquery-1.10.2.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/modernizr.min.js"></script>
</body>
</html>

三、流程解析

我们在登录页随机输入用户名和错误的密码,然后点击登录

我们跟踪断点,他还是进入到DispatcherServlet这个类下的doDispatch()方法

然后我们走到RequestMappingHandlerAdapter类下的handleInternal()—>invokeHandlerMethod()

设置参数解析器和返回值处理器

在这里,它就会走到ServletInvocableHandlerMethod类下的invokeAndHandle()方法,通过this.invokeForRequest(webRequest, mavContainer, providedArgs)去调用控制器类中的具体方法

我们发现,如果方法的参数是一个自定义类型对象(例如demo中的User),调用完具体方法后,我们会把他放在ModelAndViewContainer中

断点继续深入,我们走到了HandlerMethodReturnValueHandlerComposite类下的handleReturnValue(),这里它会使用this.selectHandler(returnValue, returnType)去获取自己适合的返回值解析器

然后我们进入到ViewNameMethodReturnValueHandler这个返回值解析器

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    if (returnValue instanceof CharSequence) {
    	// 获取视图名称
        String viewName = returnValue.toString();
        mavContainer.setViewName(viewName);
        // 判断是否是重定向页面
        if (this.isRedirectViewName(viewName)) {
            mavContainer.setRedirectModelScenario(true);
        }
    } else if (returnValue != null) {
        throw new UnsupportedOperationException("Unexpected return type: "   returnType.getParameterType().getName()   " in method: "   returnType.getMethod());
    }
}

重点:我们可以发现,目标方法处理的过程中,所有数据都会被放在 ModelAndViewContainer 里面。包括数据和视图地址

经过上述处理之后,我们返回到RequestMappingHandlerAdapter类中

ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);

这行代码会将ModelAndViewContainer 中的数据放到ModelAndView中

然后返回到DispatcherServlet这个类中,处理派发结果(页面该如何响应)的关键代码this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);

我们进入该方法进行分析

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

String viewName = mv.getViewName();获取视图名称

view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);循环遍历当前系统中所有的视图解析器尝试是否能根据当前返回值得到View对象,符合条件的视图解析器为ContentNegotiatingViewResolver(ContentNegotiationViewResolver 里面包含了下面所有的视图解析器,内部还是利用下面所有视图解析器得到视图对象),最后返回的视图对象为ThymeleafView

下面是几种不同返回值所对应的视图对象

  • 返回值以 forward: 开始: new InternalResourceView(forwardUrl); —> 转发,底层为request.getRequestDispatcher(path).forward(request, response);
  • 返回值以 redirect: 开始: new RedirectView() —> render底层就是重定向
  • 返回值是普通字符串: new ThymeleafView()—>通过对应的解析处理,并通过writer输出流写出到页面

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

大家也可以输入正确的用户名和密码,debug一下重定向是如何解析的

到此这篇关于SpringBoot视图解析实现原理深入分析的文章就介绍到这了,更多相关SpringBoot视图解析内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

SpringBoot视图解析实现原理深入分析的更多相关文章

  1. SpringBoot本地磁盘映射问题

    这篇文章主要介绍了SpringBoot本地磁盘映射问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

    这篇文章主要介绍了java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源),文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

  3. SpringBoot整合Javamail实现邮件发送的详细过程

    日常开发过程中,我们经常需要使用到邮件发送任务,比方说验证码的发送、日常信息的通知等,下面这篇文章主要给大家介绍了关于SpringBoot整合Javamail实现邮件发送的详细过程,需要的朋友可以参考下

  4. SpringBoot详细讲解视图整合引擎thymeleaf

    这篇文章主要分享了Spring Boot整合使用Thymeleaf,Thymeleaf是新一代的Java模板引擎,类似于Velocity、FreeMarker等传统引擎,关于其更多相关内容,需要的小伙伴可以参考一下

  5. Springboot集成mybatis实现多数据源配置详解流程

    在日常开发中,若遇到多个数据源的需求,怎么办呢?通过springboot集成mybatis实现多数据源配置,简单尝试一下,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  6. SpringBoot使用Minio进行文件存储的实现

    本文主要介绍了SpringBoot使用Minio进行文件存储的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  7. 解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能

    这篇文章主要介绍了SpringBoot中使用LoadTimeWeaving技术实现AOP功能,AOP面向切面编程,通过为目标类织入切面的方式,实现对目标类功能的增强,本文给大家介绍的非常详细,需要的朋友可以参考下

  8. 详解springboot测试类注解

    这篇文章主要介绍了springboot测试类注解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  9. SpringBoot实现过滤器和拦截器的方法

    大家应该都晓得实现过滤器需要实现 javax.servlet.Filter 接口,而拦截器会在处理指定请求之前和之后进行相关操作,配置拦截器需要两步,本文通过实例代码给大家介绍SpringBoot 过滤器和拦截器的相关知识,感兴趣的朋友一起看看吧

  10. SpringBoot中使用@scheduled定时执行任务的坑

    本文主要介绍了SpringBoot中使用@scheduled定时执行任务的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部