程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

Java【SpringMVC:核心源码、映射规则、参数绑定】

发布于2021-05-29 21:15     阅读(1308)     评论(0)     点赞(4)     收藏(5)


文章目录

引入

问答题:
	SpringMVC是什么?
    SpringMVC的总控制器是什么?有哪些作用?
    SpringMVC中的三大组件是什么?作用是什么?
    口述SpringMVC框架的加载流程? ★
    口述SpringMVC执行流程? ★
    @RequestMapping注解的作用?有哪些参数?参数什么意思?
    SpringMVC可以接收哪些类型的参数?接收规则是什么?
编程题:
	SpringMVC入门案例
    使用@RequestMapping注解中的所有参数
    获取请求携带的所有数据
============================================================
问答题:
	SpringMVC是什么?
        springMVC依托于spring实现的基于MVC架构的web层的轻量级实现的框架;
        MVC:
			M:model,模型是对数据的封装
            v:view,视图,向用户展示的效果,jsp,html,json
            c:controller,控制,调度器,用于处理请求,将model和view进行合并输入    
    SpringMVC的总控制器是什么?有哪些作用?
        DispatcherServlet,本质上就是一个servlet
                作用:
                	1.核心调度器,用于接收和响应用户的请求;
                    2.springmvc内部调用各个组件(3大组件)完成用户请求  
    SpringMVC中的三大组件是什么?作用是什么?
          处理器映射器:HandlerMapping,作用:根据请求url路径查找对应的处理器;
          处理器适配器:
                	因为处理器有3中实现方案【2中基于实现接口,一种基于注解实现(主流)】
                    通过适配器适配处理器,然后再调用执行
                    最后返回ModelAndView给DispatcherServlet
          视图解析器:
                	将DispatcherServlet获取的view逻辑视图转换成物理视图,最后返回给DispatcherServlet
                	
口述SpringMVC框架的加载流程? ★
           1.项目引入相关依赖,然后打war包部署;
                	jar:spring-webmvc  servlet-api  jsp-api
           2.tomcat启动后加载web.xml
           3.初始化 DispatcherServlet,然后读取contextConfigLocation下指定springmvc.xml,最后 完成spring IOC容器的初始化; 
           4.注册核心组件,其中包含springmvc的3大核心组件;             
    口述SpringMVC执行流程? ★
            1.浏览器发送请求,被tomcat获取,然后DispatcherServlet处理请求;
            2.DispatcherServlet解析请求获取url地址,然后调用处理器映射器,根据url地址查找对应的handler处理器(处理器方法的全限定名称);
            3.DispatcherServlet调用处理器适配器,适配具体的处理器适配器调用处理器完成请求处理,最后返回ModelAndView;  
            4. DispatcherServlet调用视图解析器,将逻辑视图转换成物理视图,然后返回; 
            5. DispatcherServlet将model和物理视图渲染输入给浏览器;           
    @RequestMapping注解的作用?有哪些参数?参数什么意思?
            作用:建立请求url对应的处理器方法之间的关系;
            参数:
                所有的属性对应的值,都可以是数组;
                path/value:指定请求url
                method:设置请求的方式,get post delete  put    
                params:限制请求必须携带的参数;
                headers:限制请求头中必须携带指定的信息;
    SpringMVC可以接收哪些类型的参数?接收规则是什么?
                1.基本数据类型+string :请求的参数名称与方法的形参名称一致即可;
                2.VO类型: 请求的参数名称与VO中属性的名称一致即可; 
                3.复杂类型:
                     3.1 数组 请求的参数名称与数组的名称一致即可; 
                     3.2 List<基本类型> 封装到VO下,然后请求的参数名称与VO下的集合对应的名称一致即可;
                     3.3 List<VO>  前端请求的参数按照list的索引位指定对应vo属性对应的值 list[0].name=xxx  list[0].age=xxx
                     3.4 Map  前端的数据需要按照k-v格式组装: map[key]=v

1、三层架构概念

  • 表现层:负责数据展示

  • 业务层:负责业务处理

  • 数据层:负责数据操作

在这里插入图片描述

2、Servlet概念

Servlet:
	运行在服务器上的java小程序.
    本质上就是java代码,这个java代码可以被web服务器调用
    【1】生命周期:
		实例化,创建一个对象放内存
        默认第一次请求Servlet,会创建Servlet对象,并调用init方法进行初始化操作
        load-on-startup: 设置servlet的初始化时机
        取值: 正整数,值越小优先级越高
        初始化,创建完对象后,调用对象的方法进行初始化 
        init(): 初始化方法
        	当对象实例化完毕后,立即调用init方法完成初始化工作, 1service(): 提供服务
        	每次请求来的时候,tomcat都会调用service方法提供服务, 请求一次执行一次
        destory(): 销毁方法
        	当对象从内存中移除前调用destory方法进行销毁工作, 1次
     【2Servletconfig
         作用:为每个Servlet都提供初始化参数(设置servlet私有配置参数);
         eg:
         1.web.xml配置:
		 <servlet>
            <servlet-name>servletDemo</servlet-name>
            <servlet-class>com.itheima.web.servlet.ServletDemo</servlet-class>
            <!--配置初始化参数-->
            <init-param>
                <!--用于获取初始化参数的key-->
                <param-name>key</param-name>
                <!--初始化参数的值-->
                <param-value>value</param-value>
            </init-param>
         </servlet>	
          2.java代码
            @Override
            public void init(ServletConfig config) throws ServletException {
                //get config and do something
                 //config.getInitParameter("key");
            }3ServletContext
           ServletContext对象,它是应用上下文对象;
           每一个应用有且【只有一个】ServletContext对象;
           它可以实现让应用中所有Servlet间的数据共享;
          eg: 
			1.web.xml配置:
                <!--配置应用初始化参数-->
                <context-param>
                    <!--用于获取初始化参数的key-->
                    <param-name>servletContextInfo</param-name>
                    <!--初始化参数的值-->
                    <param-value>This is application scope</param-value>
                </context-param>
             2.java代码示例:
                getServletContext();
                getInitParameter("servletContextInfo");

一、SpringMVC概述

1、MVC架构概念

MVC(Model View Controller) 是一种软件设计典范。
    主要作用是将视图展示和业务控制代码分离开来。 
 
- Model(模型)数据模型,用于封装数据
- View(视图)页面视图,用于展示数据 jsp  ,html,json,xml等
- Controller(控制器)处理用户交互的调度器,用于根据用户需求处理程序逻辑Servlet 、SpringMVC等
    
# 思考:MVC架构跟三层架构是什么关系
可以这样理解:
1.MVC把三层架构中的web层再度进行了分化,分成了控制器、视图、模型。 
2.三层架构的目的是【解耦】,mvc的目的是实现web层系统的【职责划分】。 

在这里插入图片描述

MVC架构在三层架构中的位置图示

在这里插入图片描述

2、SpringMVC

SpringMVCSpring对MVC架构的一种实现,属于轻量级的WEB框架。 
它通过一个简单的**注解**就可以让一个普通的Java类成为控制器,这种**低侵入性的设计**使得他备受业界欢迎 
同时他还支持RestFul风格的编程风格。

SpringMVC是spring对web层进行的封装,提供的MVC架构
M(模型): 
Model可以叫做数据模型层,说白了就是用来封装数据的
    例如:
    用户发送注册请求,那么请求的信息会被SpingMMVC封装到User实体类中,这个实体类就属于Model层;
    用户发送查询个人信息的请求,那么后台也会将个人信息封装到一个User类型,数据同样也是Model层;

V(视图): 
View说白了就是SpringMVC响应请求的一种数据展示(最终的执行结果):
    例如:
    SpringMVC响应的数据方式:JSP、json、xml、html等

C(控制): 
控制层就用来处理交互的部分,接收用户请求,然后执行业务等流程,最终反馈结果;
[控制器]本质上就是一个Servlet,一切请求都访问这个Servlet,在这个Servlet中进行调度。
SpringMVC可以通过一个简单的注解,就能让浏览器访问到对应的方法。 @RequestMapping("/请求路径")
总之,这个唯一的Servlet核心控制器会【根据请求的url匹配基于注解的url】,完成请求处理;
    
# SpringMVC能干什么
 1)Spring框架集成,如:(IOC,AOP)
 2) 支持Restful风格
 3) 进行更简洁的Web层开发
 4) 支持灵活的URL到页面控制器的映射
 5) 非常容易与其他视图技术集成,如:VelocityFreeMarker等等
 6) 因为模型数据不存放在特定的API里,而是放在一个Model(Map数据结构实现,因此很容易被其他框架使用)
 7) 非常灵活的数据验证、格式化和数据绑定机制、能使用任何对象进行数据绑定,不必实现特定框架的API
 8) 更加简单、强大的异常处理
 9) 对静态资源的支持
 10) 支持灵活的本地化、主题等解析

在这里插入图片描述

二、SpringMVC 入门案例

1、步骤tomcat7插件运行

需求: 通过浏览器访问SpringMVC框架返回一个jsp页面
1、创建web项目,编写pom.xml(指定工程war打包方式),引入坐标
2、 配置核心Servlet编写web.xml文件,在web.xml文件中【配置核心控制器】
3 、编写SpringMVC配置文件 spring-mvc.xml约束【处理器适配器,处理器映射器,视图解析器】
**4、编写业务处理器**
**5、编写响应页面**
**6Tomcat插件的使用**

2、代码演示

1、创建web项目, 编写pom.xml(指定工程war打包方式),引入坐标

 <packaging>war</packaging>
  <!-- 导入jar包依赖 -->
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

2、 配置核心Servlet编写web.xml文件,在web.xml文件中【配置核心控制器】

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
           version="3.0">
    <!--
        服务器启动时只会加载web项目的核心配置文件 web.xml
    -->
    <!-- 配置SpringMVC的核心Servlet: 前端控制器 (由SpringMVC框架提供)-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置SpringMVC的核心配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!-- 我们给前端控制器配置的路径为 / (缺省匹配)可以匹配浏览器发送的所以请求
             注意: jsp除外
         -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

3 、编写SpringMVC配置文件 spring-mvc.xml约束【处理器适配器,处理器映射器,视图解析器】

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启包扫描 -->
    <context:component-scan base-package="com.example"></context:component-scan>

    <!-- 配置视图解析器: 生成前缀和后缀 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/webapp/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 将可能使用到的处理器适配器,处理器映射器,视图解析器统统的加载到内存中 -->
    <mvc:annotation-driven/>
</beans>

4、编写业务处理器

package com.example.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
 * 编写处理器方法
 */
@Controller
public class HelloController {
    /**
     * @RequestMapping :
     *      作用: 建立请求路径与此方法的对应关系
     * @return
     */
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("hello springmvc....");
        // 如果直接返回字符串,则代表请求转发
        return "success";
    }
}

5、编写响应页面

在Webapp/pages/ 下定义success.jsp

success.jsp响应页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>执行成功...</h1>
</body>
</html>

6、Tomcat插件的使用

开发中,直接使用tomcat会有繁琐的配置,我们可以使用maven支持的tomcat插件,提高开发效率;

直接在pom文件中添加tomcat插件:

    <build>
        <plugins>
            <!-- tomcat7插件,运行命令: mvn tomcat7:run -DskipTests -->
            <!-- 配置Tomcat插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <uriEncoding>UTF-8</uriEncoding>
                    <port>8080</port>
                    <path>/</path>
                </configuration>
            </plugin>
            <!--<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>-->
        </plugins>
    </build>

**运行方式1:**双击运行

在这里插入图片描述

**运行方式2:**配置成maven命令运行

在这里插入图片描述

在这里插入图片描述

3、入门案例执行流程

【1】启动初始化顺序

资源准备阶段:
(1)打包好war包,部署到Tomcat中==》mavne的自动发布插件完成
(2)Tomcat启动,加载web.xml文件

(3)初始化【前端控制器】dispatcherServlet的配置
(4)根据<param-name>的容器配置contextConfigLocation加载springmvc.xml配置
(5)根据spring-mvc.xml配置 完成spring IOC容器的初始化;

时序图:

在这里插入图片描述

【2】请求处理顺序

(1)浏览器发起 http://localhost:8080/hello 请求
(2)Tomcat调用dispatcherServlet拦截/hello
(3)dispatcherServlet调用一个处理器,根据请求路径[/hello]找对对应的处理方法
(这里指被@RequestMapping注释的方法)【处理器映射器】
-处理器映射器:处理浏览器请求,根据路径映射到指定发方法;
eg:  /hello --> com.heima.controller.HelloController #hello(){} 方法

(4)dispatcherServlet找到方法后,调用另外一种处理器,
 执行HelloController中的hello()方法【处理器适配器】
-处理器适配器:
适配处理器handler类型(在这里对应的处理器是hello()方法);
处理入参,把对应的参数直接封装为一个实体;

(5)HelloController中的hello()方法有返回值,创建ModelAndVIew(包含响应数据,页面)
(6)dispatcherServlet调用视图解析器,组装响应对象,然后把页面返回给浏览器【视图解析器】
-视图解析器:
把方法返回的ModelAndVIew,进行页面和数据的整合,标签根据传入的view进行页面跳转

在这里插入图片描述

【3】开发流程

1.创建web项目 war包
2.导入相关jar包坐标
    spring-webmvc
    servlet
    jsp
3.web.xml文件中配置 总控制器
    DispatcherServlet: 调度的Servlet
        指定springmvc的配置文件
        设置初始化时机
        配置DispatcherServlet拦截规则
4.编写springmvc的配置文件
    开启包扫描
<context:component-scan base-package="com.example">
    设置视图解析器,生成前缀和后缀 	 org.springframework.web.servlet.view.InternalResourceViewResolver
5.编写我们的处理器 handler
    @Controller
    HelloController.java
    处理器适配器
    @RequestMapping("/hello")
    public String hello(){
        return "success";
    }     

三、核心原理分析

1、SpringMVC执行原理

在这里插入图片描述

在这里插入图片描述

1、前端控制器:DispatcherServlet 
是整体流程控制的中心,调用其它组件处理用户的请求,有效的降低了组件间的耦合性;
2、处理器:Handler,业务处理的核心类。
通常由我们自己编写,比如:HelloController类等;
【处理器映射器】:负责根据URL请求找到对应的Handler处理器(请求的URL与Controller方法的关系)
【处理器适配器】:将请求参数解析转换成处理器的入参,并调用处理器执行的组件; 
【视图解析器】: 将处理器执行的结果生成View视图(将逻辑视图转换成物理视图)
视图:View,最终产出结果, 常用视图如:jsp、 html  

【1】服务器启动流程
SpringMVC加载流程: 
    1.当服务器启动时,只会加载web.xml文件
    2.初始化核心控制器:DispatcherServlet
    3.在核心控制器初始化方法中(initStrategies:初始化策略),完成组件的加载
    	处理器映射器:HandlerMapping
            [建立绑定路径与方法全限定名的对应关系]
        处理器适配器:HandlerAdapter
            [适配处理器的实现方式,调用指定的类反射执行处理器方法]
        视图解析器:ViewResolver
            [根据逻辑视图生成对应的物理视图,并将物理视图返回]
【2】执行请求流程
SpringMVC执行流程:
	1.浏览器发起请求给服务器
    2.DispatcherServlet接收来自浏览器的请求
    3.调用处理器映射器,根据请求路径找到对应的方法全限定名,并返回给核心控制器
    4.调用处理器适配器,找到对应的方法实现,并调用指定的实现类反射执行方法
    5.调用视图解析器,根据逻辑视图找到对应的物理视图
    6.生成响应

2、SpringMVC的三大核心组件

在SpringMVC的运行流程中我们可以发现DispatcherServlet负责整体调度工作而实际工作的是三大组件

【1】HandlerMapping处理器映射器

作用: 根据请求路径找到对应的方法(处理器)
	在服务器启动,SpringMVC的配置文件加载时,会扫描指定的包,
	当扫描到@RequestMapping注解时,会建立请求路径与当前方法(处理器)的对应关系 
    
处理器: Handler
    指的就是我们自己编写的java代码(web层的Controller)

【2】HandlerAdapter处理器适配器

作用: 反射调用方法执行
    根据请求路径找到对应的【类或方法】时,判断(适配)当前处理器的实现方式,
	并调用指定的处理器适配器类执行,处理器适配器类执行,就可以让方法执行了.
处理器的实现方式有多种
    (把一个普通类变成处理器的方式,一旦一个类变成了处理器,SpringMVC就可以使用反射技术调用此方法执行了):
	方式1: 自定义一个类,实现Controller接口,重写handleRequest方法
        SimpleControllerHandlerAdapter
    方式2: 自定义一个类,实现HttpRequestHandler接口,重写handleRequest方法
        HttpRequestHandlerAdapter
    方式3: 自定义一个类,在方法上添加@RequestMapping注解  ★★★★★
        RequestMappingHandlerAdapter
        
-----------------------------------------------------------
        if(处理器实现了 Controller接口){
            // 调用处理接口类的处理器适配器执行
        }else if(处理器实现了 HttpRequestHandler接口){
            // 调用处理接口类的处理器适配器执行
        }else if(处理器类上面有注解){
            // 调用处理注解的处理器适配器执行
        }
-----------------------------------------------------------
尽管springmvc框架默认配置了处理器映射器和适配器。在企业项目中,我们还是需要显示配置处理器映射器和适配器。配置的目的:增加其它应用的配置
  xmlns:mvc="http://www.springframework.org/schema/mvc"
    
    <!--管理controller的bean-->
    <context:component-scan base-package="com.itheima.project"/>
    
    <!--
        显示配置处理器映射器和处理器适配器,说明:
            第一步:导入mvc名称空间和约束
            第二步:通过注解驱动标签配置
       -->
    <mvc:annotation-driven/>   

在这里插入图片描述

【3】ViewResolver视图解析器

作用: 根据逻辑视图匹配到物理的视图,并将物理视图返回给总控制器(核心控制)
    (根据返回的视图名称,找到具体的视图位置)
    
根据视图的名称将其解析为 View 类型的视图,如通过 ModelAndView 中的视图名称将其解析成 ViewView 是用来渲染页面的,也就是将 Model 填入模板中,生成 html 或其他格式的文件 
    
-----------------------------------------------------------
关于视图解析器,有几个配置很重要 
@RequestMapping("/hello") 
public String hello(){ 
    System.out.println("Hello world"); 
    return "success"; 
}

<!-- 配置视图的前后缀 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
    <!--前缀--> 
    <property name="prefix" value="/pages/" /> 
    <!--后缀--> 
    <property name="suffix" value=".jsp" /> 
</bean>
    
<!-- 可能使用到的处理器适配器,处理器映射器,视图解析器统统的加载到内存中,方便后续使用 -->
 <mvc:annotation-driven/>
自动加载 RequestMappingHandlerMapping处理映射 和 RequestMappingHandlerAdapter处理适配器 ) 
可 用 在 SpringMVC.xml 配 置 文 件 中 使 用<mvc:annotation-driven>替代注解处理器和适配器的配置。

DispatchterServlet.properties组件属性文件

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

# 处理器映射器
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

# 处理器适配器
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

# 视图解析器
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

3、请求跟踪【源码分析】

【1】项目启动初始化【前端控制器】配置

web.xml中配置的前端控制器:

<!-- 配置前端控制器:DispatcherServlet -->
  <servlet>
    <servlet-name>spring-helloworld</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载spring-mvc主文件 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:spring-mvc.xml</param-value>
    </init-param>
    <!-- 配置什么时候加载前端控制器,说明:
      1.配置大于等于1的整数,表示在tomcat启动的时候加载
      2.配置小于0的整数,表示在第一次请求到达的时候加载
     -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring-helloworld</servlet-name>
    <!-- 配置请求url规则,说明:
       1.*.do,表示以.do结尾的请求进入前端控制器
       2./,表示所有请求都进入前端控制器
    -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

DispatcherServlet源码分析 【默认加载 web.xml的配置】

public class DispatcherServlet extends FrameworkServlet {
    ......
    //定义DispatcherServlet的默认策略名
    private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
	......
        
    //从属性文件加载默认策略实现
    static {
            try {
                ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
                defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
            }
            catch (IOException ex) {
                throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
            }
        }
    ......
        
  =============================初始化(策略)各个组件================================
        
    protected void initStrategies(ApplicationContext context) {
        // 初始化MultipartResolver 用来处理上传文件 默认是没有处理的,需要在上下文添加MultipartResolver处理器
        initMultipartResolver(context);
        // 初始化LocaleResolver 配置国际化的
        initLocaleResolver(context);
        // 初始化ThemeResolver 通过主题控制页面风格
        initThemeResolver(context);
        ----------------------------------------------------------------
        // 初始化HandlerMappings 由定义请求和处理程序对象之间映射的对象实现
        initHandlerMappings(context);  【处理器映射器】
        // 初始化HandlerAdapters
        initHandlerAdapters(context);  【处理器适配器】
        ----------------------------------------------------------------
        // 初始化HandlerExceptionResolvers 异常处理
        initHandlerExceptionResolvers(context);
        // 初始化RequestToViewNameTranslator
        initRequestToViewNameTranslator(context);
        ----------------------------------------------------------------
        // 初始化ViewResolvers
        initViewResolvers(context);  【视图解析器】
        ----------------------------------------------------------------
        // 初始化FlashMapManager
        initFlashMapManager(context);
    }
        
  ================================加载默认策略 ==============================
    protected <T> List<T> getDefaultStrategies(
        ApplicationContext context, Class<T> strategyInterface) {
		......
	}
}

在这里插入图片描述

【2】(前端控制器)拦截 HTTP请求

客户端发送HTTP请求 --》被DispatcherServlet所拦截 , DispatcherServlet类的核心方法doService()执行

doService()中的核心逻辑由 doDispatch方法执行初始化组件

    ============================doService方法==================================
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (this.logger.isDebugEnabled()) {
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
            this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
        }
    
    ...............省略....................
    
      try {
            this.doDispatch(request, response); // doDispatch初始化创建
        } finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot);
            }

        }

    ==========================doDispatch方法==================================

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;   // 定义封装了handler及拦截器
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    //检测是否是文件上传内容
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    // 【获取的处理器映射器】
            		// 这里返回的不是一个具体的controller,而是HandlerExecutionChain
            		// 封装了handler及拦截器
                    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);
                    
                    ...............省略....................
                        
					// 【实际处理器适配器执行方法,返回视图】
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    
                     ...............省略....................

				// 【渲染结果】
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
	...................................
            } catch (Throwable var23) {
	...................................
            }

        } finally {
	...................................
    }
}

   ==============processDispatchResult【处理派遣结果-》渲染结果】===========
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 (mv != null && !mv.wasCleared()) {
	...................................
        }
    }

【3】(处理器映射器)RequestMappingHandlerMapping

getHandler(processedRequest)方法实际上 --》 是从HandlerMapping中 --》找到url和Controller的对应关系 ,

具体实现是在抽象类AbstractHandlerMapping中。

在这里插入图片描述

而RequestMappingHandlerMapping是使用注解方式时所使用的处理器映射器

在这里插入图片描述

【4】(处理器适配器)RequestMappingHandlerAdapter

**doDispatch方法中带着 --》从getHandler(processedRequest)**获得mappedHandler

调用 --》getHandlerAdapter(mappedHandler.getHandler())方法,

获得在ApplicationObjectSupport中初始化的List handlerAdapters

–》 其对应HandlerAdapter

在这里插入图片描述

【5】(视图解析器)ViewResolver

返回视图mv 之后,调用processDispatchResult() 方法完成视图解析

this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		.......

		if (mv != null && !mv.wasCleared()) {
            
           ==========渲染模板===================
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
	 ...............省略....................
	}


=======================调用Viewrender()方法去渲染=======================
 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
        response.setLocale(locale);
        String viewName = mv.getViewName();
        View view;
 	...............省略....................

        try {
            if (mv.getStatus() != null) {
                response.setStatus(mv.getStatus().value());
            }
			//  View接口的实现类AbstractViewrender 中的render()方法
            view.render(mv.getModelInternal(), request, response);
            
        } catch (Exception var8) {
   ...............省略....................
        }
    }

View接口的抽象类public abstract class AbstractView 中的render()方法

    public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
  ...............省略....................
        Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);
        this.prepareResponse(request, response);
        ========//渲染输出结果=======
        this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);
    }

public class InternalResourceView extends AbstractUrlBasedView

InternalResourceView 类的 renderMergedOutputModel()方法

@Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// 将模型对象设置为请求属性
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);

		// 获取请求转发对象
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		......
        //请求转发
		rd.forward(request, response);
		}
	}

小结:架构图解

浏览器访问服务器时的执行流程

在这里插入图片描述

在这里插入图片描述

四、SpringMVC请求映射规则

追踪一下RequestMappingHandlerMapping的初始化代码:

@Nullable
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        
		//根据RequestMapping的注解创建请求映射详细
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
		RequestCondition<?> condition = (element instanceof Class ?
				getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
		return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
	}

这里从代码中我们可以发现@RequestMapping启到了关键性作用

@CrossOrigin
解决跨域问题

1、@RequestMapping

绑定路径:
完全匹配: /user/addUserServlet /userServlet
目录匹配: /* 、 /user/*
后缀名匹配: *.do 、 *.jsp 、 *.abc
缺省匹配: / (匹配除jsp以外的所有路径)

/**
 * @RequestMapping: 建立请求路径与方法的对应关系
 *      使用位置:
 *          类上: 窄化路径
 *              /类上的路径/方法上的路径
 *          方法上: 建立请求路径与方法的对应关系
 * value或者path: 用来指定路径,默认选项 
 * method: 用来限定请求的方式 
 * params: 用来限定请求参数 
 * headers: 用来限定请求头
 * 以上的属性可以单独使用,也可以组合使用,组合使用时,
 * 必须同时满足才行。
 */

@Controller
public class Demo1Controller {
    /**
     * 完全匹配:
     *      RequestMapping中的路径怎么写,浏览器就怎么访问,必须完全匹配
     * @return
     */
    @RequestMapping("/aa/demo01")
    public String demo01(){
        System.out.println("demo01方法执行了");
        return "success"; // 请求转发到success页面
    }

    /**
     * 目录匹配
     * @return
     */
    @RequestMapping("/bb/*")
    public String demo02(){
        System.out.println("demo02方法执行了");
        return "success"; // 请求转发到success页面
    }

    /**
     * 后缀名匹配
     *  必须以 * 开头
     * @return
     */
    @RequestMapping("*.do")
    public String demo03(){
        System.out.println("demo03方法执行了");
        return "success"; // 请求转发到success页面
    }
}

【1】基本使用

@RequestMapping是Spring演示Web应用程序中最常被用到的注解之一。

这个注解会将HTTP请求映射到MVC和REST控制器的处理方法上。

@RequestMapping可以使用在控制器类的级别或方法的级别上使用 。

【1】基本用法
@RequestMapping的基本使用
@RequestMapping的默认映射
@RequestMapping在类级别和方法级别上的作用

【1.2】实现
1、配置pom.xml
2、配置spring-mvc.xml
3、配置web.xml
4、新增succeed.jsp
4、新建BasicController
【演示】

配置pom.xml


  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example.project</groupId>
  <artifactId>springmvc-02request-mapping</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>springmvc-02request-mapping</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!--spring版本-->
    <spring.version>5.1.11.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>springmvc-02request-mapping</finalName>
    <plugins>
      <!-- tomcat7插件,命令: mvn tomcat7:run -DskipTests -->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <uriEncoding>utf-8</uriEncoding>
          <port>8080</port>
          <path>/platform</path>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

配置spring-mvc.xml

    <!--配置扫描路径-->
    <context:component-scan base-package="com.ahcfl.controller"/>

    <!--显示配置处理器映射器和处理器适配器,说明:
            第一步:导入mvc名称空间和约束
            第二步:通过注解驱动标签配置-->
    <mvc:annotation-driven/>

配置web.xml

  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <!--前端控制器DispatcherServlet加载-->
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--初始化加载spring-mvc配置-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:spring-mvc.xml</param-value>
    </init-param>
    <!--配置1:表示启动就加载
        配置0:表示懒加载-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <!--配置/代表拦截所有路径-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

新增succeed.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>springmvc-@RequestMapping</title>
</head>
<body>
这个是requestMapping的${content}用法!
</body>
</html>

新增BasicController

package com.ahcfl.controller
    
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:基本用法
 */
//声明bean
@Controller
//使用限定类的请求路径
@RequestMapping(value = "basic")
public class BasicController {

    /**
     * @Description 此次不限定名称则表示为默认请求方法
     */
    @RequestMapping
    public ModelAndView defaultMapping(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "默认");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }

    /**
     * @Description 限定方法访问路径
     */
    @RequestMapping(value = "succeed")
    public ModelAndView succeed(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "基本");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }
}

测试
分别访问观察结果:

访问http://localhost:8080/platform/basic

访问http://localhost:8080/platform/basic/succeed

【小结】
@RequestMapping的基本使用
 	先访问类上映射路径,再根据方法路径进一步细化请求
@RequestMapping的默认配置
	不写value值即为默认请求路径

【2】多个url访问

掌握@requestMapping的ant风格的请求路径
【演示】

添加MultipathController

package com.ahcfl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:多路径请求映射
 */
@Controller
@RequestMapping(value = "/multipath")
public class MultipathController {

    //@RequestMapping 支持统配符以及ANT风格的路径
    @RequestMapping(value = {"/succeed","succ*","/test/succeed"})
    public ModelAndView succeed(){
        ModelAndView modelAndView = new ModelAndView();
        Map<String,Object> map = new HashMap<>();
        map.put("content", "多路径");
        modelAndView.addAllObjects(map);
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        return  modelAndView;
    }
}

【小结】
测试发现,访问下列路径:
http://localhost:8080/platform/multipath/succeed
http://localhost:8080/platform/multipath/succaaaaa
http://localhost:8080/platform/multipath/test/succeed
都是可以访问得的,且结果是一样的。

【3】HTTP的各种请求处理

 Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 
 比如 GET, PUT, POST, DELETE 以及 PATCH。  
 掌握@RequestMapping的method配置
【演示】

新增DoMethodController

package com.ahcfl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:处理http的各种请求方式
 */
@Controller
@RequestMapping(value = "domethod")
public class DoMethodController {

    /**
     * @Description get方式
     * method指定访问方式
     */
    @RequestMapping(value = "getmethod",method = RequestMethod.GET)
    public ModelAndView getMethod(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "getmethod");
        modelAndView.addAllObjects(map);
        return modelAndView;

    }

    /**
     * @Description post方式
     */
    @RequestMapping(value = "postmethod",method = RequestMethod.POST)
    public ModelAndView postMethod(){
//构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "postmethod");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }
}



postman工具测试
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

【小结】
@RequestMapping中的  method属性用于限制http的请求方式

【4】处理动态url【扩展】

前面我们使用@RequestMapping处理的路径都是固定的路径,那么怎么动态路径又是怎么处理的呢?

【演示】

新增DoUrlController

package com.ahcfl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:动态路径匹配
 */
@Controller
@RequestMapping(value = "dourl")
public class DoUrlController {

    @RequestMapping(value = "{matchUrl}")
    public ModelAndView matchUrl() {
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String, Object> map = new HashMap<>();
        map.put("content", "动态路径");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }

    @RequestMapping(value = "{matchUr1}/{matchUr12}")
    public ModelAndView matchUrl2() {
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String, Object> map = new HashMap<>();
        map.put("content", "动态路径2");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }
}


【4.3】小结
1、@requestMapping的多路径使用{}占位符来实现
@RequestMapping(value = "{matchUrl}")匹配路径
	http://localhost:8080/platform/dourl/a
	http://localhost:8080/platform/dourl/user
@RequestMapping(value = "{matchUrl}/{matchUrl2}")
	http://localhost:8080/platform/dourl/a/1
	http://localhost:8080/platform/dourl/user/1

2、【使用场景】
提供第三方接口时使用,需要配合参数绑定使用

2、@RequestMapping 子类注解

【介绍】

在这里插入图片描述

@RequestMapping 子类注解列表

注解等价于适用场景
@GetMapping@RequestMapping(method = RequestMethod.GET)GET:得到资源
@PutMapping@RequestMapping(method = RequestMethod.PUT)PUT:修改整体内容
@PostMapping@RequestMapping(method = RequestMethod.POST)POST:新增内容
@DeleteMapping@RequestMapping(method = RequestMethod.DELETE)DELETE:删除内容
@PatchMapping@RequestMapping(method = RequestMethod.PATCH)PATCH:修改部分内容
这些标签也可以根据请求方式不同,来限定url的映射关系
掌握@requestMapping的子类用法:【相同路径请求,因请求方式不同而映射的方法不同】

【演示】

新增SonMappingController

package com.ahcfl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:RequestMapping 子类注解
 */
@Controller
@RequestMapping(value = "sonmapping")
public class SonMappingController {

    @GetMapping
    public ModelAndView get(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "get");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }

    @PostMapping
    public ModelAndView post(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "post");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }

    @PutMapping
    public ModelAndView put(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "put");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }

    @DeleteMapping
    public ModelAndView delete(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "delete");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }

    @PatchMapping
    public ModelAndView patch(){
        //构建对象视图对象
        ModelAndView modelAndView = new ModelAndView();
        //指定视图
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        //传递参数,接受map对象
        Map<String,Object> map = new HashMap<>();
        map.put("content", "patch");
        modelAndView.addAllObjects(map);
        return modelAndView;
    }
}


postman测试

【小结】

@RequestMapping子类:
    请求路径相同
        http://localhost:8080/platform/sonmapping
    但是请求方式不同,执行的方法也不同

五、SpringMVC参数绑定

0、参数绑定的概念

# 什么是参数绑定?
例如:
登陆一个网站的时候,填写账号和密码,然后传给controller,
controller需要接受传递过来的账号和密码,登陆成功之后需要返回信息给前台页面,
这个接受和传递都可以叫做参数绑定。
处理器映射器RequestMappingHandlerMapping找到对应urls与Controller的关系后,
后续交给 处理器适配器RequestMappingHandlerAdapter来处理,
在处理之前由 RequestMappingHandlerAdapter完成参数的绑定,

那么我们看下 RequestMappingHandlerAdapter.java类的afterPropertiesSet()方法初始化
相关方法参数解析器。(源码line:481)
@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
		initControllerAdviceCache();
        
		//初始化默认参数解析器
		if (this.argumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
        
        //初始化绑定参数@InitBinder解析器
		if (this.initBinderArgumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
        
        //初始化默认返回解析器
		if (this.returnValueHandlers == null) {
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

我们看下初始化默认参数解析器

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

		// 基本注解参数绑定
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ServletModelAttributeMethodProcessor(false));
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new RequestHeaderMapMethodArgumentResolver());
		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());

		// 基础类型参数绑定
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RedirectAttributesMethodArgumentResolver());
		resolvers.add(new ModelMethodProcessor());
		resolvers.add(new MapMethodProcessor());
		resolvers.add(new ErrorsMethodArgumentResolver());
		resolvers.add(new SessionStatusMethodArgumentResolver());
		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		resolvers.add(new ServletModelAttributeMethodProcessor(true));

		return resolvers;
	}

由此我们可以知道 【参数的绑定】 是在【处理器适配器】中完成的。下面我们看下各种类型绑定方式

# SpringMVC支持的参数类型有 
1、基本数据类型 
2、string
2、vo类型(View object,浏览器携带的所有数据封装成的对象叫做vo) 
3、复杂类型: 数组类型  集合类型   
		
# 说明
如果请求中携带这些类型的数据,SpringMVC会自动帮我们接收,并传递给方法进行使用,
【方法上的形参名称必须要和请求参数名称保持一致】

1、基本类型和String

只需要保证前端传递的参数名称跟方法的形参名称一致就好。

SpringMVC接收的参数 默认都是String类型的,它内部会进行一个自动转型。

package com.ahcfl.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("params")
public class Demo4Controller {
    /**
     * SpringMVC获取请求携带的参数
     */
    /**
     * 原生API: 使用Servlet提供的Request对象
     * 该对象直接在方法中传入即可
     */
    @RequestMapping("test01")
    public String test01(HttpServletRequest request){
        // 获取请求参数
        String username = request.getParameter("username");
        String age = request.getParameter("age");
        System.out.println(username+" : "+age);
        return "success";
    }

    /**
     * 获取基本类型或String类型数据
     *      方法上形参名称必须和请求携带的参数名称保持一致
     * @return
     */
    @RequestMapping("test02")
    public String test02(String username,Integer age){
        System.out.println(username+" : "+age);
        return "success";
    }
}

<form action="/params/test01" method="get">
        用户名: <input type="text" name="username" value="景甜"> <br>
        年龄: <input type="text" name="age" value="18"> <br>
        <input type="submit" value="携带基本类型和String类型的数据">
    </form>
    <form action="/params/test02" method="get">
        用户名: <input type="text" name="username" value="大幂幂"> <br>
        年龄: <input type="text" name="age" value="18"> <br>
        <input type="submit" value="携带基本类型和String类型的数据">
    </form>

2、vo类型

VO(View Object) 简单的java对象,用于封装请求携带的数据

只需要保证前端传递的参数名称跟 VO中的属性名称(set方法)一致就好。

 /**
     * 获取请求携带的参数,将请求携带的参数封装到vo对象中
     *      vo对象: value object
     *          一个普通的java类对象
     *      规则:
     *          请求参数的名称必须和对象中的属性名保持一致
     * @return
     */
    @RequestMapping("test03")
    public String test03(UserVo userVo){
        System.out.println(userVo);
        return "success";
    }
package com.ahcfl.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserVo {
    private String username;
    private Integer age;
}
<form action="/params/test03" method="get">
        用户名: <input type="text" name="username" value="景甜"> <br>
        年龄: <input type="text" name="age" value="18"> <br>
        <input type="submit" value="请求参数封装到VO对象中">
</form>

3、数组类型

只需要保证前端传递的参数名称跟方法中的数组形参名称一致就好。

 <form action="/params/test04" method="get">
        用户名: <input type="text" name="username" value="景甜"> <br>
        年龄: <input type="text" name="age" value="18"> <br>
        爱好: <input type="checkbox" name="hobbys" value="smoke"> 抽烟
        <input type="checkbox" name="hobbys" value="drink"> 喝酒
        <input type="checkbox" name="hobbys" value="makehair"> 烫头 <br>
        <input type="submit" value="请求参数封装到数组中">
 </form>
 	/**
     * 获取请求携带的多个值,封装到数组中
     * @param hobbys
     * @return
     */
    @RequestMapping("test04")
    public String test03(String[] hobbys,String username,Integer age){
        System.out.println(username+" : "+age);
        System.out.println(Arrays.toString(hobbys));
        return "success";
    }

4、集合类型

获取集合参数时,要将集合参数包装到一个Vo中才可以

VO: value Object 或 view Object 封装来自浏览器携带的数据

package com.ahcfl.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.List;
import java.util.Map;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Vo {
    private List<String> names;
    private List<UserVo> userList;
    private Map<String,String> maps;
}
 /**
     * 将请求携带的参数封装到对象的集合中
     * @param vo
     * @return
     */
    @RequestMapping("test05")
    public String test05(Vo vo){
        System.out.println(vo);
        return "success";
    }
<form action="/params/test05" method="get">
        用户名:
        <input type="text" name="names[0]" value="tom"><br>
        <input type="text" name="names[1]" value="rose"><br>
        <input type="text" name="names[2]" value="jack"><br>
        <hr>
        用户:
        <input type="text" name="userList[0].username" value="张三">
        <input type="text" name="userList[0].age" value="28"><br>
        <input type="text" name="userList[1].username" value="李四">
        <input type="text" name="userList[1].age" value="30"><br>
        <hr>
        <input type="text" name="maps['name']" value="景甜"> <br>
        <input type="text" name="maps['age']" value="18"> <br>
        <input type="submit" value="请求参数封装到数组中">
    </form>

5、特殊的情况

【1】日期处理

如果请求携带的参数为日期类型,SpringMVC没有提供相关的转换器,哪该如何处理呢?

我们可以使用SpringMVC提供的注解进行日期格式化操作
@DateTimeFormat(pattern = "yyyy-MM-dd")
    
说明:此时springmvc.xml中必须要开启注解驱动: <mvc:annotation-driven/>    
    
    /**
     * 测试获取日期类型的数据
     * @param birthday
     * @return
     */
    @RequestMapping("/testDate")
    public String getDate(@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday){
        System.out.println(birthday);
        return "success2";
    }

    /**
     * url:http://localhost:8080/testDate2?birthday=2021-05-25
     * @param birthday
     * @return
     */
    @RequestMapping("/testDate2")
    public String getDate2(Date birthday){
        System.out.println(birthday);
        return "success2";
    }

【2】编码过滤器

如果请求携带了中文有乱码该怎么办呢?
在web阶段自己编写过编码过滤器,在SpringMVC中已经提供好了编码过滤器,我们直接使用即可

<!-- 在web.xml中配置springMVC编码过滤器 -->  
	<filter>  
		<filter-name>CharacterEncodingFilter</filter-name>  
		<filter-class>
			org.springframework.web.filter.CharacterEncodingFilter
		</filter-class>  
		<!-- 设置过滤器中的属性值 -->  
		<init-param>  
			<param-name>encoding</param-name>  
		    <param-value>UTF-8</param-value>  
		</init-param>
	</filter>  
	<!-- 过滤所有请求 -->  
	<filter-mapping>  
		<filter-name>CharacterEncodingFilter</filter-name>  
		<url-pattern>/*</url-pattern>  
	</filter-mapping>

【3】请求参数名称不一致

@RequestParam : 主要用于在SpringMVC后台控制层获取参数时,前端传入的参数和方法形参不一致时。

它支持三个属性: 
	value:默认属性,用于指定前端传入的参数名称 
	required:用于指定此参数是否必传 
	defaultValue:当参数为非必传参数且前端没有传入参数时,指定一个默认值。
<a href="/params/demo8?username=张三">请求参数-基本类型</a> <br>
------------------------------
@RequestMapping("demo8")
public String demo1(@RequestParam(defaultValue = "tom",required = false,value = "name") String username){
    System.out.println(username);
    return "success";
}

   /**
     * 请求url:http://localhost:8080/testDiffName?name=ahcfl&age=18
     * 说明:
     * 通过@RequestParam指定请求参数赋值给指定的形参;
     * 属性:
     *      value/name:指定请求参数名称,注解打在那个形参上,就给那个形参赋值;
     *      required
     *          true:请求必须携带指定参数,否则报错
     *          false:非必须,如果没有,也不会报错
     *      defaultValue
     *          指定默认值,一般配合required=fase一块使用,如果入参为null,那么就使用默认值
     *
     * @param userName
     * @param userAge
     * @return
     */
    @RequestMapping("/testDiffName")
public String testDiffName(@RequestParam(value = "name",required = false,defaultValue = "景甜") String userName,@RequestParam("age") String userAge){
        System.out.println("userName:"+userName+",userAge:"+userAge);
        return "success2";
    }

【4】获取请求头信息

@RequestHeader

作用: 主要用于从请求头中获取参数。它支持的属性跟@RequestParam一样。

public String demo2(@RequestHeader("cookie") String cookie){}
@RequestMapping("demo2")
public String demo2(@RequestHeader("cookie") String cookie, HttpServletResponse response){
    System.out.println(cookie);
    return "success";
}

【5】获取cookie信息

@CookieValue作用: 用于从cookie中取值。

注意: cookie的key值区分大小写

@RequestMapping("demo3")
public String demo3(@CookieValue("JSESSIONID") String jsessionid){
    System.out.println(jsessionid);
    return "success";
}

小结

package com.ahcfl.controller;

@Controller
@RequestMapping("/params")
public class Params01Controller {
    /**
     * 获取基本类和String类型的数据信息
     *      非String类型最好使用对应的包装类.
     *      如果非String类的参数,没有携带值时
     *             基本类报错,包装类为null
     * @return
     */
    @RequestMapping("/test01")
    public String handler01(String username,Integer age){
        System.out.println(username+" : "+age);
        return "success";
    }

    /**
     * 获取请求携带的参数自动封装到pojo对象中:
     *      请求参数的名称必须要和pojo中属性名称一致
     * @param user
     * @return
     */
    @RequestMapping("/test02")
    public String handler02(User user){
        System.out.println(user);
        return "success";
    }

    /**
     * 获取同名参数的多个值
     * @param names
     * @return
     */
    @RequestMapping("/test03")
    public String handler03(String []names){
        System.out.println(Arrays.toString(names));
        return "success";
    }

    /**
     * 获取请求参数封装到list和map集合中
     * @param pvo
     * @return
     */
    @RequestMapping("/test04")
    public String handler04(ParamsVo pvo){
        List<User> list = pvo.getUsers();
        for (User user : list) {
            System.out.println(user);
        }
        Map<String, String> maps = pvo.getMaps();
        System.out.println(maps);
        return "success";
    }

    /**
     * SpringMVC提供了类型转换器,将String转换为对应的类型
     *      DateTimeFormat: 完成String转日期
     * @param name
     * @param birthday
     * @return
     */
    @RequestMapping("/test05")
    public String test05(@RequestParam(value = "username",required = true,defaultValue = "tom") String name, @DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday){
        System.out.println(name+" : "+birthday);
        return "success";
    }

    /**
     * 获取请求携带的头
     * @param cookie
     * @return
     */
    @RequestMapping("/test06")
    public String test06(@RequestHeader("cookie") String cookie){
        System.out.println(cookie);
        return "success";
    }

    /**
     * 获取cookie头的值
     * @param cookieValue
     * @return
     */
    @RequestMapping("/test07")
    public String test07(@CookieValue("JSESSIONID") String cookieValue){
        System.out.println(cookieValue);
        return "success";
    }
}

参数常用注解

1、@RequestMapping

@RequsetMapping 的映射规则,进一步说下此注解在限定传递参数中的作用

value, method

​ value: 指定请求的实际地址;

​ method: 指定请求的method类型, GET、POST、PUT、DELETE等;

consumes,produces(不建议指定)

​ consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

​ produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

params,headers

​ params: 指定request中必须包含某些参数值是,才让该方法处理。

​ headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。

【演示】

修改CustomerController中的findCustomerById方法

    /**
     * @Description 查看用户
     * params:指定request中必须包含某些参数值,才让该方法处理
     */
    @RequestMapping(value = "findCustomerById",params = "customerId")
    public ModelAndView findCustomerById(String customerId){
        System.out.println("============传递的用户ID:"+customerId);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/views/customer-findone.jsp");
        return modelAndView;
    }

访问
http://localhost:8080/platform/custo/findCustomerById
不传递customerId参数机会报错在这里插入图片描述

2、@PathVariable

@PathVariable绑定URL中的参数值

【演示】

在CustomerController中新增findCustomerById1方法

     /**
     * @Description 查看用户
     */
    @RequestMapping(value = "findCustomerById1/{id}")
    public ModelAndView findCustomerById1(@PathVariable("id") String customerId){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("content",customerId);
        modelAndView.setViewName("/WEB-INF/views/succeed.jsp");
        return modelAndView;
    }

访问 http://localhost:8080/platform/customer/findCustomerById1/1

在这里插入图片描述

3、@RequestParam

@RequestParam绑定单个请求数据,既可以是URL中的参数,也可以是表单提交的参数

它有三个属性:

value:用于设置参数名(别名)

defaultValue:用于对参数设置默认值

required:用于设置是否必需值,默认为true。为true时,如果参数为空,会报错

【演示】

修改BasicTypeController的doBasicType()方法

    /**
     * @Description 接受表单
     */
    @RequestMapping(value = "do-basic-type")
    public ModelAndView doBasicType(@RequestParam(value = "id",required = false,defaultValue = "1") Integer id){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("id", id);
        modelAndView.setViewName("/WEB-INF/views/basic-type.jsp");
        return modelAndView;
    }

访问 http://localhost:8080/platform/basic-type/do-basic-type 发现默认传递一个id=1
在这里插入图片描述

4、@RequestBody
【演示】

此注解用于接收json类型数据

修改PojoTypeController中doPojoType方法

/**
     * @Description 操作pojo-type页面
     */
    @RequestMapping("do-pojo-type")
    public ModelAndView doPojoType(@RequestBody Customer customer){
        ModelAndView modelAndView = new ModelAndView();
        System.out.println("传递过来的参数:"+customer.toString());
        modelAndView.addObject("customer",customer);
        modelAndView.setViewName("/WEB-INF/views/pojo-type.jsp");
        return modelAndView;
    }

pom.xml中添加json支持

<!--jackson版本-->
<jackson.version>2.9.0</jackson.version>
<!--jackson依赖包-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>${jackson.version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson.version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>${jackson.version}</version>
</dependency>

使用postman测试

{
"custId":1,
"custName":"张三",
"createrTime":"2020-04-01 08:00:00"}

测试访问:
http://localhost:8080/platform/pojo-type/do-pojo-type在这里插入图片描述
在这里插入图片描述

@RequestBody的时间转换

需要注意的是,在接收json数据时,我们之前定义的@InitBinder处理是无效的,这个时候我们就需要使用新的方式在Customer类的createrTime字段上添加
在这里插入图片描述

​创建时间,入参DateTimeFormat,出参:JsonFormat

@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",timezone = "GMT+8")
package com.ahcfl.pojo;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
 * @Description:用户实体类
 */
public class Customer {

    //客户编号(主键)
    private Integer custId;

    //客户名称(公司名称)
    private String custName;

    //客户信息来源
    private String custSource;

    //客户所属行业
    private String custIndustry;

    //客户级别
    private String custLevel;

    //客户联系地址
    private String custAddress;

    //客户联系电话
    private String custPhone;

    //创建时间,入参DateTimeFormat,出参:JsonFormat
    @DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    @JsonFormat(pattern ="yyyy-MM-dd hh:mm:ss",timezone = "GMT+8")
    private Date createrTime;

    //履历
    private CustomerInfo customerInfo;

    public Integer getCustId() {
        return custId;
    }

    public void setCustId(Integer custId) {
        this.custId = custId;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public String getCustSource() {
        return custSource;
    }

    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    public String getCustIndustry() {
        return custIndustry;
    }

    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    public String getCustLevel() {
        return custLevel;
    }

    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    public String getCustAddress() {
        return custAddress;
    }

    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    public String getCustPhone() {
        return custPhone;
    }

    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    public Date getCreaterTime() {
        return createrTime;
    }

    public void setCreaterTime(Date createrTime) {
        this.createrTime = createrTime;
    }

    public CustomerInfo getCustomerInfo() {
        return customerInfo;
    }

    public void setCustomerInfo(CustomerInfo customerInfo) {
        this.customerInfo = customerInfo;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "custId=" + custId +
                ", custName='" + custName + '\'' +
                ", custSource='" + custSource + '\'' +
                ", custIndustry='" + custIndustry + '\'' +
                ", custLevel='" + custLevel + '\'' +
                ", custAddress='" + custAddress + '\'' +
                ", custPhone='" + custPhone + '\'' +
                ", createrTime=" + createrTime +
                ", customerInfo=" + customerInfo +
                '}';
    }
}

在这里插入图片描述

六、自定义类型转换器(了解)

类型转换器,顾名思义就是做类型转换的,因为SpringMVC接收到的请求参数都是【字符串】,

而在参数封装的时候什么类型都有,所以需要类型转换。

SpringMVC已经内置了常用的类型转换器,比如String转int的类型转换器。但是对于一些格式不明确的

字符串就不好实现,比如时间类型,这就需要我们自定义类型转换器。

以时间为例,自定义类型转换器的步骤:

1.自定义一个转换器类实现Converter< 源类型, 目标类型>接口,

**并实现它的T convert(S s)方法,实现转换功能。 **

import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateConverter implements Converter<String,Date> {
    public Date convert(String s) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            return  format.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

**2.在配置文件中将自定义的的转换器交给ConversionServiceFactoryBean来管理 **

<bean id="conversionId" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.ahcfl.converter.DateConverter"></bean>
        </set>
    </property>
</bean>

3.将ConversionServiceFactoryBean托管给注解启动annotation-driven

<mvc:annotation-driven conversion-service="conversionId"/>

总结

SpringMVC概述:
		Spring提供的mvc模式的实现,对web层进行的封装.
SpringMVC入门案例:
	1.创建maven的web项目,并导入jar包,设置打包方式war
      spring-webmvc
    2.编写web.xml文件
      配置SpringMVC的总控制器: DispatcherServlet
      配置SpringMVC配置文件的位置: springmvc.xml
      配置总控制器的初始化时机: 服务器启动时,立即创建DispatcherServlet对象
    3.编写SpringMVC的配置文件
      组件扫描:包扫描
      视图解析器: InternalResourceViewResolver
        	配置响应页面的前缀与后缀
    4.编写web层的代码: 处理器
      HelloController.java
      @RequestMapping("/hello")
      public String hello(){ 
      	// 当我们给一个方法添加了@RequestMapping注解后,该方法就可以被SpringMVC调用了
      	return " success";
    	}

服务器启动时加载流程:
  1.服务器启动时只会加载web.xml文件
  2.实例化DispatcherServlet对象
  3.初始化DispatcherServlet对象,调用init方法执行
  4.首先解析springmvc.xml文件,创建应用上下文对象
  5.初始化三大组件:
	  处理器映射器: 
		  建立请求路径与方法的对应关系
          /hello : com.itheima.web.HelloController.hello()
      处理器适配器:
		  HttpRequestHandlerAdapter
          SimpleControllerHandlerAdapter
          RequestMappingHandlerAdapter ★
      视图解析器
          存放视图的前后缀
  web层处理器实现的多种方式:
			直接给方法添加注解: @RequestMapping ★
			编写一个类实现Controller接口,重写handleRequest方法
			编写一个类实现HttpRequestHandler接口,重写handleRequest方法

                
浏览器访问时的执行流程:
	1.浏览器发起请求 /hello
  2.DispatcherServlet拦截请求
  	a.解析请求路径 /hello
   	b.调用处理器映射器获取方法的全限定名 com.itheima.web.HelloController.hello()
    c.调用处理器适配器 传递com.itheima.web.HelloController.hello()
    		判断处理器的实现方式  @RequestMapping
    		RequestMappingHandlerAdapter:
						反射让方法执行
            method.invoke();
				返回逻辑视图: success
		d.调用视图解析器: success
      	根据逻辑视图生成对应的物理视图
      	/pages/success.jsp
   3.请求转发到对应的物理视图上		

原文链接:https://blog.csdn.net/mmmmmCJP/article/details/117304415



所属网站分类: 技术文章 > 博客

作者:听说你没有见过我

链接:http://www.javaheidong.com/blog/article/207428/04ed5e9919f1752f2441/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

4 0
收藏该文
已收藏

评论内容:(最多支持255个字符)