Java--SpringMVC概述,运行流程

一、SpringMVC概述

MVC 设计模式一般指 MVC 框架,M(Model)指数据模型层,V(View)指视图层,C(Controller)指控制层。使用 MVC 的目的是将 M 和 V 的实现代码分离,使同一个程序可以有不同的表现形式。其中,View 的定义比较清晰,就是用户界面

开发Servlet 及 JSP时,JavaBean 相当于 Model,Servlet 相当于 Controller,JSP 相当于 View。

视图层(View):负责格式化数据并把它们呈现给用户,包括数据展示、用户交互、数据验证、界面设计等功能。

控制层(Controller):负责接收并转发请求,对请求进行处理后,指定视图并将响应结果发送给客户端。

数据模型层(Model):模型对象拥有最多的处理任务,是应用程序的主体部分,它负责数据逻辑(业务规则)的处理和实现数据操作(即在数据库中存取数据)

SpringMVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet

SpringMVC 也叫 Spring web mvc。是 Spring 框架的一部分,是在 Spring3.0 后发布的。

由于 Spring MVC 本身就是 Spring 框架的一部分,可以说和 Spring 框架是无缝集成,能够使用Spring的IoC和Aop。方便整合MyBatis,Strtus,Hiberate,JPA 等其他框架

Spring MVC主要由DispatcherServlet(中央调度器)、处理器映射、处理器(控制器)、视图解析器、视图组成

SpringMVC工作流程

 1、Http请求:客户端请求提交到DispatcherServlet(中央调度器)

2、寻找处理器:由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller

3、调用处理器:DispatcherServlet将请求提交到Controller

4、调用业务处理和返回结果:Controller调用业务逻辑处理后,返回ModelAndView

5、处理视图映射并返回模型: DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

6、Http响应:视图负责将结果显示到客户端

SpringMVC组件

1、DispatcherServlet:中央调度器(前端控制器)。用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性,系统扩展性提高。由框架实现

2、HandlerMapping:处理器映射器。HandlerMapping负责根据用户请求的url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,根据一定的规则去查找,例如:xml配置方式,实现接口方式,注解方式等。由框架实现

3、Handler:处理器。Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

4、HandlAdapter:处理器适配器。通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。由框架实现。

5、ModelAndView:springmvc的封装对象,将model和view封装在一起。

6、ViewResolver:视图解析器。ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

7、View:springmvc的封装对象,是一个接口, springmvc框架提供了很多的View视图类型,包括:jspview,pdfview,jstlView、freemarkerView、pdfView等。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

二、SpringMVC项目开发步骤

1、新建一个maven的web项目,选择

maven-archetype-webapp

2、pom.xml文件加入依赖

spring-webmvc依赖,间接把spring的依赖都加入到项目;jsp,servlet依赖

<properties>
    <!-- 项目构建使用的编码,避免中文乱码 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- 源码编译 jdk 版本 -->
    <maven.compiler.source>1.8</maven.compiler.source>
    <!-- 运行代码的 jdk 版本 -->
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <!-- junit单元测试 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!--springmvc依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>

    <!-- servlet依赖 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>

  </dependencies>

  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <!-- filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 -->
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>

3、新建web.xml文件,并在该配置文件中注册SpringMVC框架的核心对象DispatcherServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 声明,注册SpringMVC的核心对象DispatcherServlet
        在Tomcat服务器启动后,创建DispatcherServlet对象实例

        DispatcherServlet在创建过程中,会同时创建SpringMVC容器对象,读取SpringMVC配置文件,把这个配置文件中的对象都创建好,
        用户发起请求时就可以直接适用对象

        Servlet初始化会执行 init() 方法;DispatcherServlet在 init() 方法中
        (1)创建容器,读取配置文件
            WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
        (2)将容器对象放入到ServletContext中
            getServletContext().setAttribute(key, ctx);
    -->
    
    <servlet>
        <servlet-name>myweb</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!-- 启动Tomcat报错,无法读取这个文件 /WEB-INF/myweb-servlet.xml
            Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/myweb-servlet.xml]
            SpringMVC创建容器对象时,默认读取的配置文件是 /WEB-INF/<servlet-name>-servlet.xml

            因此需要自定义SpringMVC读取配置文件的位置
            <init-param> :在servlet类中通过getInitParamenter(String name)方法访问初始化参数
            param-name 就是参数名;param-value就是参数值,支持多个参数
            在这个方法中通过 getInitParamter("key"); key 就是 param-name的值,来获取对应的参数值
        -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>


        <!-- tomcat启动后,创建Servlet对象
            load-on-startup:表示Tomcat启动后创建对象的顺序;
            它的值是整数,数值越小,Tomcat创建对象的时间越早,大于等于0的整数
        -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>myweb</servlet-name>

        <!-- url-pattern  拦截匹配规则的 url 请求,进入springmvc 框架处理,
        springmvc 就会去找能够处理这个url 的 handler去执行业务逻辑
        可使用两种值
            (1)使用扩展名方式,语法  *.xx , xx是自定义的扩展名,
                常用的方式 *.do, *.action, *.mvc等等
                不能使用 *.jsp
                http://localhost:8080/myweb/some.do
                http://localhost:8080/myweb/other.do
            (2)使用斜杠 "/"
        -->
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

</web-app>

(1)中央调度器DispatcherServlet

中央调度器的全限定性类名在 导入的 Jar 文件 spring-webmvc-5.2.5.RELEASE.jar 的第一个包 org.springframework.web.servlet 下

<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

(2)</init-param>

启动Tomcat报错,无法读取这个文件 /WEB-INF/myweb-servlet.xml    

Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/myweb-servlet.xml]

SpringMVC创建容器对象时,默认读取的配置文件路径是 /WEB-INF/<servlet-name>-servlet.xml   

<servlet-name>指的是注册中央调度器<servlet-name/>标签 中指定的 Servlet 的 name 值
一般情况下,配置文件是放在类路径下,即 resources 目录下‘’因此需要自定义SpringMVC读取配
置文件的位置    

<init-param> :在servlet类中通过getInitParamenter(String name)方法访问初始化参数    

param-name:参数名;

param-value:参数值,支持多个参数    

在这个方法中通过 getInitParamter("key"); key 就是 param-name的值,来获取对应的参数值

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>

打开 DispatcherServlet 的源码,DispatcherServlet 继承自 FrameworkServlet,该类中有一个属性 contextConfigLocation,用于设置 SpringMVC 配置文件的路径及文件名。因此初始化参数的属性就来自于此 

(3)<load-on-startup/>

<load-on-startup/>的作用是,标记是否在Web服务器(这里是Tomcat)启动时会创建这个 Servlet 实例,即是否在 Web 服务器启动时调用执行该 Servlet 的 init()方法,而不是在真正访问时才创建

load-on-startup:表示Tomcat启动后创建对象的顺序;

它的值是整数,数值越小,Tomcat创建对象的时间越早,大于等于0的整数

<load-on-startup>1</load-on-startup>

(4)<url-pattern/>

url-pattern  拦截匹配规则的 url 请求,进入springmvc 框架处理, springmvc 就会去找能够处理这个url 的 handler去执行业务逻辑

(1)使用扩展名方式,语法  *.xx , xx是自定义的扩展名

常用的方式 *.do, *.action, *.mvc等等,不能使用 *.jsp        

http://localhost:8080/myweb/some.do        

http://localhost:8080/myweb/other.do    

(2)使用斜杠 "/"

<url-pattern>*.do</url-pattern>

项目自带web.xml文件如下;使用的是最低版本2.3,因此需要更改版本

(1)File ----> Project Structure...

(2)删掉项目自带的web.xml文件

(3)新增web.xml文件,并且选择版本

注:这里需要重新命名web.xml文件,如web1111.xml,如果还是使用web.xml名称,新建之后还是最低版本,因此需要重新命名!!!

(4)更改新增之后的web.xml文件名称,将其改为“web.xml”

4、创建一个发起请求的页面 index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>第一个SpringMVC项目</p>
    <p> <a href="some.do">发起some.do的请求</a> </p>
    <p> <a href="first.do">发起first.do的请求</a> </p>
    <p> <a href="other.do">发起other.do的请求</a> </p>
    <p> <a href="second.do">发起second.do的请求</a> </p>
</body>
</html>

5、创建控制器(处理器)类

(1)在类上面加入@Controller注解,创建对象,并放入到SpringMVC容器中

@Controller:表示当前类为处理器

(2)在类的方法上加入@RequestMapping注解

@RequestMapping :表示当前方法为处理器方法。该方法要对 value 属性所指定的 URI
进行处理与响应
ModelAndView 类中的 addObject()方法用于向其 Model 中添加数据。 Model 的底层为一个HashMap
Model 中的数据存储在 request 作用域中,SringMVC 默认采用转发的方式跳转到视图,本次请求结束,模型中的数据被销毁
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Controller :创建处理器对象,对象放在SpringMVC容器中
 * 位置:在类的上面
 *
 * 能处理请求的都是控制器(处理器),也叫做后端控制器(back Controller)
 */
@Controller
public class MyController {
    /**
     * SpringMVC中使用方法来处理用户提交的请求;方法可以自定义,也可以有多种返回值,多种参数,方法名称自定义
     *
     * @RequestMapping : 请求映射;作用是把一个请求地址和一个方法绑定在一起
     *                  一个请求指定一个方法处理
     *
     *      属性:value;是一个String,表示请求的URI地址(some.do)
     *          value的值必须是唯一的,不能重复;使用时,推荐地址以  "/"开始
     *
     *      位置:1、在方法上面,常用;2、在类上面
     *
     *      注:使用@RequestMapping修饰的方法叫做处理器方法或者控制器方法
     *         使用@RequestMapping修饰的方法可以处理请求,类似Servlet中的doGet,doPost
     *
     *      返回值:ModelAndView,表示本次请求的处理结果
     *          Model:数据,请求处理完成后,要显示给用户的数据、
     *          View:视图,如jsp等
     */
    @RequestMapping(value = {"/some.do","first.do"})
    public ModelAndView doSome(){ // doGet()----service请求处理
        //处理 some.do请求,相当于service调用处理完成
        ModelAndView mdv = new ModelAndView();

        /**
         * 添加数据,框架在请求的最后把数据放入到request作用域
         * request.setAttribute("msg","欢迎使用springmvc做web开发");
         */
        mdv.addObject("msg","欢迎使用SpringMVC做web开发");
        mdv.addObject("fun","执行的是doSome方法");

        /**
         * 指定视图,指定视图的完整路径
         * 框架对视图进行forward转发操作,request.getRequestDispather("/show.jsp).forward(...)
         */
        /**
         * jsp页面放在 /webapp 目录下,
         * 用户可以通过输入对应地址 http://localhost:8081/springmvc-1-war/show.jsp 直接访问
         */
        //mdv.setViewName("/show.jsp");

        /**
         * jsp页面放在 /webapp/WEB-INF/view 目录下,
         * 输入对应地址 http://localhost:8081/springmvc-1-war/WEB-INF/view/show11.jsp 无法访问,访问报错,更加安全
         * WEB-INF目录下的jsp页面就必须要通过请求才能访问,是要求隐藏性的,只让客户通过请求访问而不是直接访问jsp页面
         */
        //mdv.setViewName("/WEB-INF/view/show11.jsp");

        /**
         * 配置视图解析器。可以使用逻辑名称(文件名),指定视图
         * SpringMVC会使用视图解析器的前缀 + 逻辑名称 + 后缀 拼接成完整路径(字符串连接操作)
         * "/WEB-INF/view/" + "show11" + ".jsp"
         */
        mdv.setViewName("show11");

        return mdv;
    }

    @RequestMapping(value = {"/other.do","/second.do"})
    public ModelAndView doOther(){
        ModelAndView mv  = new ModelAndView();
        mv.addObject("msg","====欢迎使用SpringMVC做web开发====");
        mv.addObject("fun","执行的是doOther方法");
        mv.setViewName("other");
        return mv;
    }
}

6、创建一个结果的 show.jsp,显示处理结果

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>/webapp/show.jsp从request作用域获取数据</h3>
    <h3>msg数据:${msg}</h3><br/>
    <h3>fun数据:${fun}</h3>
</body>
</html>

这里需要注意 show.jsp目录位置

/**
         * 指定视图,指定视图的完整路径
         * 框架对视图进行forward转发操作,request.getRequestDispather("/show.jsp).forward(...)
         */
        /**
         * jsp页面放在 /webapp 目录下,
         * 用户可以通过输入对应地址 http://localhost:8081/springmvc-1-war/show.jsp 直接访问
         */
        mdv.setViewName("/show.jsp");

        /**
         * jsp页面放在 /webapp/WEB-INF/view 目录下,
         * 输入对应地址 http://localhost:8081/springmvc-1-war/WEB-INF/view/show11.jsp 无法访问,访问报错,更加安全
         * WEB-INF目录下的jsp页面就必须要通过请求才能访问,是要求隐藏性的,只让客户通过请求访问而不是直接访问jsp页面
         */
        mdv.setViewName("/WEB-INF/view/show11.jsp");

(1)jsp页面放在 /webapp 目录下

用户可以通过输入对应地http://localhost:8081/springmvc-1-war/show.jsp 直接访问

(2)jsp页面放在 /webapp/WEB-INF/view 目录下

 输入对应地址 http://localhost:8081/springmvc-1-war/WEB-INF/view/show11.jsp 无法访问,访问报错,更加安全

WEB-INF目录下的jsp页面就必须要通过请求才能访问,是要求隐藏性的,只让客户通过请求访问而不是直接访问jsp页面

7、创建SpringMVC的配置文件(和spring的配置文件一样)

工程的类路径即 src 目录下创建 SpringMVC 的配置文件 springmvc.xml

(1)声明组件扫描器,指定@Controller注解所在的包名

(2)声明视图解析器,处理视图

<!-- 声明SpringMVC框架中的视图解析器,设置视图文件的路径:InternalResourceViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀:视图文件的路径 -->
        <property name="prefix" value="/WEB-INF/view/" />
        <!-- 后缀:视图文件的扩展名 -->
        <property name="suffix" value=".jsp" />
    </bean>
        /**
         * 配置视图解析器。可以使用逻辑名称(文件名),指定视图
         * SpringMVC会使用视图解析器的前缀 + 逻辑名称 + 后缀 拼接成完整路径(字符串连接操作)
         * "/WEB-INF/view/" + "show11" + ".jsp"
         */
        mdv.setViewName("show11");
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 声明组件扫描器 -->
    <context:component-scan base-package="com.mycompany.controller" />

    <!-- 声明SpringMVC框架中的视图解析器,设置视图文件的路径:InternalResourceViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀:视图文件的路径 -->
        <property name="prefix" value="/WEB-INF/view/" />
        <!-- 后缀:视图文件的扩展名 -->
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

8、启动Tomcat,或者未修改Java代码,只修改 jsp 代码,重启资源即可配置如下

IDEA下更改jsp界面后(或者静态资源界面),一般要手动update或者reploy,这里可以设置tomcat来解决

 选择Edit Configurations...

默认是Tomcat的【Server】选项, On Frame Deactivation选项这里如果 只有 Do nothing,看如下配置

On Upate Action 与 On Frame Deactivation  这两个选项的设置,依赖于 项目的部署方式 是war包 还是 exploded 

 选择【Deployment】,添加一个启动项目,这里必须选择 exploded 为后缀的war包!!!

在选择【Server】查看,On Frame Deactivation  选项的设置就会出现【Update resources】选项,选择即可

这时重启Tomcat,就会多了选项【Update resources】和【Update classes and resources】

(1)如果重启Tomcat,选择【Restart server】

(2)如果只修改 jsp 或者 html 页面,选择【Update resources】

整个项目结构如下

启动Tomcat之后,在浏览器中输入访问地址即可

http://localhost:8081/springmvc-1-war/

三、DispatcherServlet创建容器,请求过程源码解析

DispatherServlet 负责接收用户的所有请求,用户把请求给了DispatherServlet, 之后DispatherServlet把请求转发给我们的Controller对象,Controller对象处理请求

index.jsp-----> DispatherServlet(Servlet) ---- > 转发,分配给 ---> Controller对象(@Controller注解创建的对象)

SpringMVC请求的处理流程

(1)index.jsp 发起 some.do 请求

(2)tomcat(web.xml--url-pattern知道 *.do的请求给DispatcherServlet)

(3)DispatcherServlet(根据springmvc.xml配置知道 some.do---doSome())

(4)DispatcherServlet把some.do转发个MyController.doSome()方法

(5)框架执行doSome() 把得到ModelAndView进行处理, 转发到show.jsp

简化的方式:some.do----> DispatcherServlet ----> MyController

1、DispatcherServlet创建容器

DispatcherServlet在创建过程中,会同时创建SpringMVC容器对象,读取SpringMVC配置文件,把这个配置文件中的对象都创建好, 用户发起请求时就可以直接适用对象

DispatcherServlet初始化会执行 init() 方法;

DispatcherServlet在 init() 方法中

(1)创建容器,读取配置文件

WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");

(2)将容器对象放入到ServletContext中

getServletContext().setAttribute(key, ctx);

public class DispatcherServlet extends FrameworkServlet

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {

       public final void init() throws ServletException {
            this.initServletBean();
       }
}

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
    protected final void initServletBean() throws ServletException {
             try {
                this.webApplicationContext = this.initWebApplicationContext();
                this.initFrameworkServlet();
            } 
        }

    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }

                    this.configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }

        if (wac == null) {
            wac = this.findWebApplicationContext();
        }

        if (wac == null) {
            wac = this.createWebApplicationContext(rootContext);
        }

        if (!this.refreshEventReceived) {
            synchronized(this.onRefreshMonitor) {
                this.onRefresh(wac);
            }
        }

        if (this.publishContext) {
            String attrName = this.getServletContextAttributeName();
            this.getServletContext().setAttribute(attrName, wac);
        }

        return wac;
    }
}
        

2、DispatcherServlet请求过程

public class DispatcherServlet extends FrameworkServlet

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware

public abstract class HttpServlet extends GenericServlet {
    
}

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
    protected void service(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException {
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
            super.service(request, response);
        } else {
            this.processRequest(request, response);
        }
    }

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doService(request, response);
    }
}


public class DispatcherServlet extends FrameworkServlet {
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { 
        this.doDispatch(request, response);
    }


    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }
        }
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值