发布于2021-05-29 21:15 阅读(1438) 评论(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
表现层:负责数据展示
业务层:负责业务处理
数据层:负责数据操作
Servlet:
运行在服务器上的java小程序.
本质上就是java代码,这个java代码可以被web服务器调用
【1】生命周期:
实例化,创建一个对象放内存
默认第一次请求Servlet时,会创建Servlet对象,并调用init方法进行初始化操作
load-on-startup: 设置servlet的初始化时机
取值: 正整数,值越小优先级越高
初始化,创建完对象后,调用对象的方法进行初始化
init(): 初始化方法
当对象实例化完毕后,立即调用init方法完成初始化工作, 1次
service(): 提供服务
每次请求来的时候,tomcat都会调用service方法提供服务, 请求一次执行一次
destory(): 销毁方法
当对象从内存中移除前调用destory方法进行销毁工作, 1次
【2】Servletconfig
作用:为每个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");
}
【3】ServletContext
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");
MVC(Model View Controller) 是一种软件设计典范。
主要作用是将视图展示和业务控制代码分离开来。
- Model(模型)数据模型,用于封装数据
- View(视图)页面视图,用于展示数据 jsp ,html,json,xml等
- Controller(控制器)处理用户交互的调度器,用于根据用户需求处理程序逻辑Servlet 、SpringMVC等
# 思考:MVC架构跟三层架构是什么关系
可以这样理解:
1.MVC把三层架构中的web层再度进行了分化,分成了控制器、视图、模型。
2.三层架构的目的是【解耦】,mvc的目的是实现web层系统的【职责划分】。
MVC架构在三层架构中的位置图示
SpringMVC是Spring对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) 非常容易与其他视图技术集成,如:Velocity、FreeMarker等等
6) 因为模型数据不存放在特定的API里,而是放在一个Model里(Map数据结构实现,因此很容易被其他框架使用)
7) 非常灵活的数据验证、格式化和数据绑定机制、能使用任何对象进行数据绑定,不必实现特定框架的API
8) 更加简单、强大的异常处理
9) 对静态资源的支持
10) 支持灵活的本地化、主题等解析
需求: 通过浏览器访问SpringMVC框架返回一个jsp页面
1、创建web项目,编写pom.xml(指定工程war打包方式),引入坐标
2、 配置核心Servlet编写web.xml文件,在web.xml文件中【配置核心控制器】
3 、编写SpringMVC配置文件 spring-mvc.xml约束【处理器适配器,处理器映射器,视图解析器】
**4、编写业务处理器**
**5、编写响应页面**
**6、Tomcat插件的使用**
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命令运行
资源准备阶段:
(1)打包好war包,部署到Tomcat中==》mavne的自动发布插件完成
(2)Tomcat启动,加载web.xml文件
(3)初始化【前端控制器】dispatcherServlet的配置
(4)根据<param-name>的容器配置contextConfigLocation加载springmvc.xml配置
(5)根据spring-mvc.xml配置 完成spring IOC容器的初始化;
时序图:
(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进行页面跳转
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、前端控制器: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.生成响应
在SpringMVC的运行流程中我们可以发现DispatcherServlet负责整体调度工作,而实际工作的是三大组件
作用: 根据请求路径找到对应的方法(处理器)
在服务器启动,SpringMVC的配置文件加载时,会扫描指定的包,
当扫描到@RequestMapping注解时,会建立请求路径与当前方法(处理器)的对应关系
处理器: Handler
指的就是我们自己编写的java代码(web层的Controller)
作用: 反射调用方法执行
根据请求路径找到对应的【类或方法】时,判断(适配)当前处理器的实现方式,
并调用指定的处理器适配器类执行,处理器适配器类执行,就可以让方法执行了.
处理器的实现方式有多种
(把一个普通类变成处理器的方式,一旦一个类变成了处理器,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/>
作用: 根据逻辑视图匹配到物理的视图,并将物理视图返回给总控制器(核心控制)
(根据返回的视图名称,找到具体的视图位置)
根据视图的名称将其解析为 View 类型的视图,如通过 ModelAndView 中的视图名称将其解析成 View,
View 是用来渲染页面的,也就是将 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
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) {
......
}
}
客户端发送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()) {
...................................
}
}
getHandler(processedRequest)方法实际上 --》 是从HandlerMapping中 --》找到url和Controller的对应关系 ,
具体实现是在抽象类AbstractHandlerMapping中。
而RequestMappingHandlerMapping是使用注解方式时所使用的处理器映射器。
**doDispatch方法中带着 --》从getHandler(processedRequest)**获得mappedHandler
调用 --》getHandlerAdapter(mappedHandler.getHandler())
方法,
获得在ApplicationObjectSupport
中初始化的List handlerAdapters
–》 其对应HandlerAdapter
返回视图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);
}
}
...............省略....................
}
=======================调用View的render()方法去渲染=======================
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);
}
}
浏览器访问服务器时的执行流程
追踪一下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
解决跨域问题
绑定路径:
完全匹配: /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页面
}
}
@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值即为默认请求路径
掌握@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
都是可以访问得的,且结果是一样的。
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的请求方式
前面我们使用@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;
}
}
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、【使用场景】
提供第三方接口时使用,需要配合参数绑定使用
@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
但是请求方式不同,执行的方法也不同
# 什么是参数绑定?
例如:
登陆一个网站的时候,填写账号和密码,然后传给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会自动帮我们接收,并传递给方法进行使用,
【方法上的形参名称必须要和请求参数名称保持一致】
只需要保证前端传递的参数名称跟方法的形参名称一致就好。
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>
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>
只需要保证前端传递的参数名称跟方法中的数组形参名称一致就好。
<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";
}
获取集合参数时,要将集合参数包装到一个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>
如果请求携带的参数为日期类型,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";
}
如果请求携带了中文有乱码该怎么办呢?
在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>
@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";
}
@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";
}
@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";
}
}
@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参数机会报错
@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
@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
此注解用于接收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
需要注意的是,在接收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黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!