学习视频:10001 Spring MVC概述_哔哩哔哩_bilibili~11005 请求映射方式_哔哩哔哩_bilibili
目录
1.概述
Java EE三层架构
Spring MVC在三层架构中的位置
编辑
Spring MVC在表现层的作用
Spring MVC的特点
2.Spring MVC入门程序
代码实现
Spring MVC工作原理
Spring MVC三大组件—处理器映射器
Spring MVC三大组件—处理器适配器
Spring MVC三大组件—视图解析器
Spring MVC执行流程
Spring MVC执行流程详细介绍
3.Spring MVC的核心类和注解
DispatcherServlet
@Controller注解
@RequestMapping注解
方式—标注在方法上
方式二标注在类上
@RequestMapping注解的属性
编辑
value属性的两种映射路径标注
method属性限定处理器映射
4.请求映射方式
a. 基于请求方式的URL路径映射
b. 基于Ant风格的URL路径映射
ant1
ant2
ant3
ant4
ant5
c.基于RESTful风格的URL路径映射
RESTful风格的基本请求操作
RESTful风格四种请求的约定方式
编辑
使用RESTful风格的优势
代码演示
1.概述
在JSP Model2架构模型采用JSP + Servlet + JavaBean技术实现了页面显示、流程控制和业务逻辑的分离。但是,JSP Model2架构模型将流程控制等通用逻辑以硬编码的方式实现,每次进行新的Web应用程序开发时,都需要重新编写Servlet控制器的URL分析代码,以及流程控制等Web层通用逻辑代码。为了解决JSP Model2架构模型在实践中存在的问题,一些基于JSP Model2架构基础发展起来的Web MVC应用框架应运而生。其中Spring MVC框架就是目前最主流的Web MVC应用框架之一
Java EE三层架构
在Java EE开发中,系统经典的三层架构包括表现层、业务层和持久层。三层架构中,每一层各司其职,表现层(Web层)负责接收客户端请求,并向客户端响应结果;业务层(Service层)负责业务逻辑处理,和项目需求息息相关;持久层(Dao层)负责和数据库交互,对数据库表进行增删改查。
Spring MVC在三层架构中的位置
Spring MVC在表现层的作用
Spring MVC作用于三层架构中的表现层,用于接收客户端的请求并进行响应。Spring MVC中包含了控制器和视图,控制器接收到客户端的请求后对请求数据进行解析和封装,接着将请求交给业务层处理。业务层会对请求进行处理,最后将处理结果返回给表现层。表现层接收到业务层的处理结果后,再由视图对处理结果进行渲染,渲染完成后响应给客户端。
Spring MVC的特点
- Spring MVC是Spring框架的后续产品,可以方便地使用Spring框架所提供的其他功能。
- Spring MVC使用简单,很容易设计出干净简洁的Web层。
- Spring MVC支持各种请求资源的映射策略。
- Spring MVC具有非常灵活的数据验证、格式化和数据绑定机制,能使用任何对象进行数据绑定,不必实现特定框架的API。
- Spring MVC支持国际化,可以根据用户区域显示多国语言。
- Spring MVC支持多种视图技术。它支持JSP、Velocity和FreeMarker等视图技术。
- Spring MVC灵活性强,易扩展。
2.Spring MVC入门程序
代码实现
<?xml version="1.0" encoding="utf8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.it</groupId><artifactId>Days10</artifactId><version>1.0-SNAPSHOT</version><!-- 声明当前是一个maven的web工程--><packaging>war</packaging><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--spring的ioc相关--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.0</version><!--依赖范围--><scope>provided</scope></dependency><!-- spring jdbc相关--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.6.RELEASE</version></dependency><!-- 事务相关--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.2.6.RELEASE</version></dependency><!--spring事务aop相关--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.6.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version><scope>runtime</scope> </dependency><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version> </dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.3</version></dependency><!--单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version><scope>runtime</scope></dependency><!-- <dependency>--><!-- <groupId>org.slf4j</groupId>--><!-- <artifactId>slf4j-log4j12</artifactId>--><!-- <version>1.6.1</version>--><!-- </dependency>--><!-- <dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>--></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.2</version><configuration><source>1.8</source><source>1.8</source></configuration></plugin><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></plugins><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><directory>src/main/resources</directory></resource></resources></build></project>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 前端控制器--><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*:/spring-mvc.xml</param-value></init-param><!-- 启动时加载--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 注解扫描--><context:component-scan base-package="com.it.controller"></context:component-scan><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="suffix" value=".jsp"></property><!--视图解析器的后缀--><property name="prefix" value="/WEB-INF/pages/"></property><!--视图解析器的前缀--></bean></beans>
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class FirstController {@RequestMapping("/firstController")public String sayHello(){System.out.println("访问第一个controller");//string返回值,默认是视图的名字(视图解析器的前缀+此处的字符串+视图解析器的后缀)return "success";}}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><h1>hello springMVC!!!</h1></body>
</html>
Spring MVC工作原理
Spring MVC三大组件—处理器映射器
处理器映射器可以理解为一个Map<URL,Hanlder>,HandlerMapping负责根据用户请求的URL找到Handler(处理器),Spring MVC提供了不同的映射器来实现不同的映射方式。
圈1是URL,圈2是Hanlder
Spring MVC三大组件—处理器适配器
处理器适配器作用是根据处理器映射器找到的处理器 Handler 信息,去执行相关的 Handler。不同的处理器映射器映射出来的Handler对象是不一样的,不同的映射由不同的适配器来负责解析。
Spring MVC三大组件—视图解析器
视图解析器进行视图解析,首先将逻辑视图名解析成物理视图名,即具体的页面地址,再生成View视图对象返回。
Spring MVC执行流程
Spring MVC执行流程详细介绍
1.用户通过浏览器向服务器发送请求,请求会被Spring MVC的前端控制器DispatcherServlet拦截。
2.DispatcherServlet拦截到请求后,会调用HandlerMapping(处理器映射器)。
3.处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4.DispatcherServlet会通过返回信息选择合适的HandlerAdapter(处理器适配器)。
5.HandlerAdapter会调用并执行Handler(处理器),这里的处理器指的就是程序中编写的Controller类,也被称之为后端控制器。
6.Controller执行完成后,会返回一个ModelAndView对象,该对象中会包含视图名或包含模型和视图名。
7.HandlerAdapter将ModelAndView对象返回给DispatcherServlet。
8.前端控制器请求视图解析器根据逻辑视图名解析真正的视图。
在Spring MVC4.0以前,配置文件内必须要配置处理器映射器、处理器适配器和视图解析器,但在Spring MVC4.0以后,如果不配置处理器映射器、处理器适配器和视图解析器,框架会加载内部默认的配置完成相应的工作。如果想显式并快捷地配置处理器映射器和处理器适配器,也可以在配置文件中使用 <mvc:annotation-driven/> 元素来实现,该元素会自动注册处理器映射器和处理器适配器。
3.Spring MVC的核心类和注解
DispatcherServlet
DispatcherServlet是Spring MVC的核心类,也是Spring MVC的流程控制中心,也称为Spring MVC的前端控制器,它可以拦截客户端的请求。拦截客户端请求之后,DispatcherServlet会根据具体规则将请求交给其他组件处理。所有请求都要经过DispatcherServlet进行转发处理,这样就降低了Spring MVC组件之间的耦合性。
<!-- 前端控制器--><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*:/spring-mvc.xml</param-value></init-param><!-- 启动时加载如果不配置:当第一次访问当前servlet,tomcat才会加载这个servlet.配置了正整数,意味着tomcat启动,就自动加载这个servlet--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><!--代表缺省(默认)的servlet,当一个请求找不到与之对应的servlet的时候,就照这个缺省的servlet.最终结果,拦截所有游览器发出的请求--><url-pattern>/</url-pattern></servlet-mapping>
如果web.xml没有通过<init-param>元素指定DispatcherServlet初始化时要加载的文件,则应用程序会去WEB-INF文件夹下寻找并加载默认配置文件,默认配置文件的名称规则如下所示。
[servlet-name]-servlet.xml
其中,[servlet-name]指的是web.xml文件中<servlet-name>元素的值;“-servlet.xml”是配置文件名的固定拼接。
<load-on-startup>元素取值
<load-on-startup>元素取值分为三种情况:
(1)如果<load-on-startup>元素的值为正整数或者0,表示在项目启动时就加载并初始化这个Servlet,值越小,Servlet的优先级越高,就越先被加载;
(2)如果<load-on-startup>元素的值为负数或者没有设置,则Servlet会在被请求时加载和初始化;
(3)如果<load-on-startup>元素的值为1,表明DispatcherServlet会在项目启动时加载并初始化。
@Controller注解
在Spring MVC框架中,传统的处理器类需要直接或间接地实现Controller接口,这种方式需要在Spring MVC配置文件中定义请求和Controller 的映射关系。当后台需要处理的请求较多时,使用传统的处理器类会比较繁琐,且灵活性低,对此,Spring MVC框架提供了@Controller注解。使用@Controller注解,只需要将@Controller注解标注在普通Java类上,然后通过Spring的扫描机制找到标注了该注解的Java类,该Java类就成为了Spring MVC的处理器类。
基于@Controller注解的处理器类示例代码
import org.springframework.stereotype.Controller;
...
@Controller //标注@Controller注解
public class FirstController{...
}
Spring MVC配置文件的类包扫描配置信息
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置要扫描的类包 --><context:component-scan base-package="com.itheima.controller"/>......
</beans>
Spring扫描配置文件范围
Spring MVC的配置文件被加载时,Spring会自动扫描com.itheima.controller类包及其子包下的Java类。如果被扫描的Java类中带有@Controller、@Service等注解,则把这些类注册为Bean并存放在Spring中。
与传统的处理器类实现方式相比,使用@Controller注解的方式显然更加简单和灵活。因此,在实际开发中通常使用@Controller注解来定义处理器类。
@RequestMapping注解
@RequestMapping注解用于建立请求URL和Handler(处理器)之间的映射关系,该注解可以标注在方法上和类上。下面分别对@RequestMapping注解的这两种使用方式进行介绍。
方式—标注在方法上
当@RequestMapping注解标注在方法上时,该方法就成了一个可以处理客户端请求的Handler(处理器),它会在Spring MVC接收到对应的URL请求时被执行。Handler在浏览器中对应的访问地址,由项目访问路径+处理方法的映射路径共同组成。
@RequestMapping("/login")public String login(){System.out.println("处理登录成功");return "success";}
方式二标注在类上
当@RequestMapping注解标注在类上时,@RequestMapping的value属性值相当于本处理器类的命名空间,即访问该处理器类下的任意处理器都需要带上这个命名空间。@RequestMapping标注在类上时,其value属性值作为请求URL的第一级访问目录。当处理器类和处理器都使用@RequestMapping注解指定了对应的映射路径,处理器在浏览器中的访问地址,由项目访问路径+处理器类的映射路径+处理器的映射路径共同组成。
@Controller
@RequestMapping("/springMVC")
public class FirstController {
这个一般用来做路径的分模块管理的
@RequestMapping注解的属性
value属性的两种映射路径标注
value属性是@RequestMapping注解的默认属性。当value属性是@RequestMapping注解显式使用的唯一属性时,可以省略value的属性名。例如,下面两种映射路径标注的含义相同。
@RequestMapping(value="/firstController")
@RequestMapping("/firstController")
@Controller
public class AuthController {@RequestMapping(value = {"/addUser","/deleteUser"})public String checkAuth(){System.out.println("增删改体验");return "success";}
}
method属性限定处理器映射
method属性可以对处理器映射的URL请求方式进行限定。当请求的URL和处理器映射成功,但请求方式和method属性指定的属性值不匹配,处理器也不能正常处理请求。
@Controller
@RequestMapping("/method")
public class MethodController {@RequestMapping(method = RequestMethod.GET)public String get(){System.out.println("RequestMethod.GET");return "success";}@RequestMapping(method = RequestMethod.POST)public String post(){System.out.println("RequestMethod.post");return "success";}@RequestMapping(method = RequestMethod.PUT)public String put(){System.out.println("RequestMethod.put");return "success";}@RequestMapping(method = RequestMethod.DELETE)public String delete(){System.out.println("RequestMethod.delete");return "success";}}
启动后我们用postman工具测试
method属性中有多个HTTP请求类型
如果需要同时支持多个请求方式,则需要将请求方式列表存放在英文大括号中,以数组的形式给method属性赋值,并且多个请求方式之间用英文逗号分隔,示例代码如下所示。
@RequestMapping(value = "/method",
method = {RequestMethod.GET,RequestMethod.POST})
public void getAndPost() {System.out.println("RequestMethod.GET+RequestMethod.POST");
}
params属性值的定义方式
params属性中定义的值可以将请求映射的定位范围缩小。当客户端进行请求时,如果请求参数的值等于params属性定义的值,可以正常执行所映射到的方法,否则映射到的方法不执行。
@Controller
public class ParamsController {@RequestMapping(value = "/params",params = "id=1")public void findById(String id) {System.out.println("id="+id); }}
4.请求映射方式
请求映射方式的分类
基于注解风格的Spring MVC,通过@RequestMapping注解指定请求映射的URL路径。URL路径映射常用的方式有基于请求方式的URL路径映射、基于Ant风格的URL路径映射和基于REST风格的URL路径映射。接下来分别对这三种请求映射方式进行详细讲解。
a. 基于请求方式的URL路径映射
除了可以使用@RequestMapping注解来限定客户端的请求方式之外,从Spring 4.3版本开始,还可以使用组合注解完成客户端请求方式的限定。组合注解简化了常用的HTTP请求方式的映射,并且更好的表达了被注解方法的语义。
Spring MVC组合注解
@GetMapping:匹配GET方式的请求。
@PostMapping:匹配POST方式的请求。
@PutMapping:匹配PUT方式的请求。
@DeleteMapping:匹配DELETE方式的请求。
@PatchMapping:匹配PATCH方式的请求。
@GetMapping用法示例
接下来以@GetMapping为例讲解组合注解的用法,@GetMapping是@RequestMapping(method = RequestMethod.GET)的缩写,使用组合注解替代@RequestMapping注解,可以省略method属性,从而简化代码。@GetMapping用法示例代码如下所示。
// @RequestMapping(value = "/firstController",method = RequestMethod.GET)@GetMapping("/firstController")public String sayHello(){System.out.println("访问第一个controller");//string返回值,默认是视图的名字(视图解析器的前缀+此处的字符串+视图解析器的后缀)return "success";}
这个GetMapping和上面注释处理是相同的 结果
b. 基于Ant风格的URL路径映射
Spring MVC支持Ant风格的URL路径映射, 所谓Ant风格其实就是一种通配符风格,可以在处理器映射路径中使用通配符对访问的URL路径进行关联。Ant风格的通配符有以下3种,分别是:?匹配任何单字符;*匹配0或者任意数量的字符;**匹配0或者多级目录。
Ant风格通配符的路径匹配
ant1
@RequestMapping("/ant1?")public String ant1(){System.out.println("ant1方法");return "success";}
这个1后面只能跟1个字符,多了不行
ant2
@RequestMapping("/ant2/*.do")public String ant2(){System.out.println("ant2方法");return "success";}
这个.do前面跟几个字符都可以
ant3
@RequestMapping("/*/ant3")public String ant3(){System.out.println("ant3方法");return "success";}
这个/ant3前也是多个字符可以
ant4
@RequestMapping("/**/ant4")public String ant4(){System.out.println("ant4方法");return "success";}
这个/ant4前可以跟一级或2级目录
ant5
@RequestMapping("/ant5/**")public String ant5(){System.out.println("ant5方法");return "success";}
这个后面跟0或任意多的
映射路径使用多个通配符情况
当映射路径中同时使用多个通配符时,会有通配符冲突的情况。当多个通配符冲突时,路径会遵守最长匹配原则(has more characters)去匹配通配符,如果一个请求路径同时满足两个或多个Ant风格的映射路径匹配规则,那么请求路径最终会匹配满足规则字符最多的路径。例如,/ant/a/path同时满足 /**/path和/ant/*/path匹配规则,但/ant/path最终会匹配“/ant/*/path”路径。
c.基于RESTful风格的URL路径映射
RESTful是按照REST风格访问网络资源,简单说RESTful就是把请求参数变成请求路径的一种风格。 而REST(Representational State Transfer)是一种网络资源的访问风格,规范对了网络资源的访问方式。REST所访问的网络资源可以是一段文本、一首歌曲、一种服务,总之是一个具体的存在。每个网络资源都有一个URI指向它, 要获取这个资源,访问它的 URI 就可以,因此URI 即为每一个资源的独一无二的标识符。
传统风格访问的URL格式如下所示。
http://.../findUserById?id=1
而采用RESTful风格后,其访问的URL格式如下所示。
http://.../user/id/1
需要注意的是,RESTful风格中的URL不使用动词形式的路径,例如,findUserById表示查询用户,是一个动词,而user表示用户,为名词。
RESTful风格的基本请求操作
RESTful风格在HTTP请求中,通过GET 、POST 、PUT和DELETE 4个动词对应四种基本请求操作,具体如下所示。
- GET用于获取资源
- POST用于新建资源
- PUT用于更新资源
- DELETE用于删除资源
RESTful风格四种请求的约定方式
地址一样请求的方式不一样,所代表的含义不一样
使用RESTful风格的优势
约定不是规范,约定是可以打破,所以称为RESTful风格,而不是RESTful规范。使用RESTful风格的优势在于路径的书写比较简便,并且通过地址无法得知做的是何种操作,可以隐藏资源的访问行为。
代码演示
@Controller
@RequestMapping("/user")
public class UserController {@GetMapping("/{id}")public String findById(@PathVariable("id") String id){System.out.println("根据id查询:"+id);return "success";}@DeleteMapping("/{id}")public String deleteById(@PathVariable("id") String id){System.out.println("根据id删除:"+id);return "success";}@PutMapping("/{id}")public String updateById(@PathVariable("id") String id){System.out.println("根据id更新:"+id);return "success";}@PostMapping("/{id}")public String add(){System.out.println("新增");return "success";}}