2022尚硅谷SSM框架跟学 六Spring MVC基础一
- 三、SpringMVC
- 1.SpringMVC简介
- 1.1什么是MVC
- 1.2什么是SpringMVC
- 1.3SpringMVC的特点
- 2入门案例
- 2.1开发环境
- 2.2创建maven工程
- (1)添加web模块
- (2)打包方式:war
- (3)引入依赖
- 2.3配置web.xml
- (1)默认配置方式
- (2)扩展配置方式
- 2.4创建请求控制器
- 2.5创建SpringMVC的配置文件
- 2.6测试HelloWorld
- (1)实现对首页的访问
- (2)通过超链接跳转到指定页面
- 2.7总结
- 3.@RequestMapping注解
- 3.1@RequestMapping注解的功能
- 3.2@RequestMapping注解的位置
- 3.3@RequestMapping注解的value属性
- 3.4@RequestMapping注解的method属性
- 3.5@RequestMapping注解的params属性(了解)
- 3.6@RequestMapping注解的headers属性(了解)
- 3.7SpringMVC支持ant风格的路径
- 3.8SpringMVC支持路径中的占位符(重点)
三、SpringMVC
1.SpringMVC简介
1.1什么是MVC
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
- 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
- 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据。
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器。
MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器。
1.2什么是SpringMVC
SpringMVC是Spring的一个后续产品,是Spring的一个子项目
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层(持久层),表述层表示前台页面和后台servlet
1.3SpringMVC的特点
- Spring 家族原生产品,与 IOC 容器等基础设施无缝对接。
- 基于原生的Servlet,通过了功能强大的前端控制器。DispatcherServlet,对请求和响应进行统一处理。
*表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案 - 代码清新简洁,大幅度提升开发效率。
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可。
- 性能卓著,尤其适合现代大型、超大型互联网项目要求。
2入门案例
2.1开发环境
IDE:idea 2021.3
构建工具:maven 3.6.3
服务器:tomcat8.5
Spring版本:5.3.1
2.2创建maven工程
Name:spring-mvc-helloworld
GroupId:com.atguigu
(1)添加web模块
(2)打包方式:war
在pom.xml中设置打包方式
<packaging>war</packaging>
设置完打包方式后,查看项目结构,已经变成web项目了
点击+号,找到web.xml
注意当前路径是错误的
当前路径:
F:\javawebwork\SSM\spring-mvc-helloworld\WEB-INF\web.xml
应该修改为正确路径
F:\javawebwork\SSM\spring-mvc-helloworld\src\main\webapp\WEB-INF\web.xml
路径修改完后,点击ok和Apply,然后发现目录结构就已经变化了
(3)引入依赖
在pom.xml中引入依赖
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
查看依赖的关系如下
注:由于 Maven 的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。
2.3配置web.xml
注册SpringMVC的前端控制器DispatcherServlet
(1)默认配置方式
配置web.xml
<!--
SpringMVC的配置文件默认的位置和名称
位置:WEB-INF下
名称为< servlet-name >-servlet.xml。
例如当前为springMVC-servlet.xml
-->
<!-- 配置SpringMVC的前端控制器DispatcherServlet,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 路径模型 -->
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求。
可以写成/* 可以匹配任意请求包含jsp
可以写成/
也可以写/hello
可以写*.do
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
这里注意servlet-mapping中的servlet-name要设置和上面servlet标签中servelt-name一样的名字,不要选成default了。
注:
< url-pattern >标签中使用/和/*的区别:
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求,因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面。
/*则能够匹配所有请求,包括jsp,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用/*的写法。
那不禁会问,为啥这里不用能够匹配所有请求的/*,而采用/呢?
答:jsp的本质是Servlet,而Tomcat中已经配置了jsp相关的Servlet,叫JspServlet,所以这些以.jsp结尾的请求应该交给Tomcat来处理,我们就不要再处理了。
打开tomcat的web.xml
此配置作用下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为< servlet-name >-servlet.xml。
例如,以下配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为SpringMVC-servlet.xml,而SpringMVC-servlet.xml的配置见:2.5创建SpringMVC的配置文件
(2)扩展配置方式
如果不想把配置文件,放到webapp/WEB-INF/目录下,那我们需要用到扩展配置的方式。
可通过< init-param>标签设置SpringMVC配置文件的位置和名称。
在(1)的基础上,增加< init-param>标签
代码如下:
<!-- 设置springmvc配置文件的位置和名称 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- classpath:必须加上,否则还是指的WEB-INF下的地址 -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
增加完后,需要清理一下依赖,点击clean,之后点击package即可。
重新运行Tomcat,发现首页也可以加载出来。
通过load-on-startup标签设置SpringMVC前端控制器DispatcherServlet的初始化时间。
<!-- 服务器启动的时候去初始化DispatcherServlet,这样可以减少第一次访问的时间 -->
<load-on-startup>1</load-on-startup>
减少第一次初始化的时间
2.4创建请求控制器
由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器
请求控制器中每一个处理请求的方法成为控制器方法。
因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IOC容器管理,此时SpringMVC才能够识别控制器的存在。
创建com.atguigu.controller.HelloContorller
package com.atguigu.controller;
import org.springframework.stereotype.Controller;
@Controller
public class HelloContorller {
}
2.5创建SpringMVC的配置文件
创建配置文件springMVC-servlet.xml
<!-- 扫描控制层组件(自己配置package) -->
<context:component-scan base-package="com.atguigu.controller"></context:component-scan>
<!-- 配置Thymeleaf视图解析器(直接拷贝即可) -->
<bean id="viewResolver"
class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!--
比如当前index的实际位置在/WEB-INF/templates/index.html(物理视图)
去掉视图前缀变为 index.html
去掉视图后缀变为 index(逻辑视图)
-->
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
创建一个html页面,用来显示。index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>index.html</h1>
</body>
</html>
配置文件如下:
解析:
比如当前index的实际位置在
/WEB-INF/templates/index.html(物理视图)
去掉视图前缀变为index.html
去掉视图后缀变为 index(逻辑视图)
2.6测试HelloWorld
首先需要配置一下Tomcat
点击右上角的下拉框,Edit Configurations
新建Tomcat本地项目
引入Artifacts
选择结尾是exploded的
配置上下文名称
配置更新和失焦后的处理方式
配置好了之后我们直接启动Tomcat看一下,发现报错500
自查了一下问题,发现springMVC-servlet.xml配置文件中,s写成了小写,这里我们改成大写,一定要保证以下几个地方一致。尤其是大小写
再次运行Tomcat,这次显示404是正确的
那之后我们怎样才能访问首页呢?
(1)实现对首页的访问
在请求控制器HelloContorller.java中创建处理请求的方法
通过@RequestMapping注解
package com.atguigu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @ClassName: HelloContorller
* @Description:
* @Author: wty
* @Date: 2023/1/16
*/
@Controller
public class HelloContorller {
/**
* @param
* @return java.lang.String
* @description //首页,门户
* @date 2023/1/16 19:03
* @author wty
**/
@RequestMapping("/")
public String portal() {
// 将逻辑视图返回
return "index";
}
}
注意return后面返回的是逻辑视图,上面有说过。
我们再次运行Tomcat看一下,跳转结果
(2)通过超链接跳转到指定页面
在主页index.html引入Thymeleaf
这里讲一下配置HTML的模板文件,快速配置Thymeleaf
在主页index.html中设置超链接
其中th:href写了2种方式,第一种是Thymeleaf通过@来跳转的,第二种是直接通过/来跳转的,我们要来看下哪种是正确的方式
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>index.html</h1>
<a th:href="@{/hello}">测试SpringMVC</a>
<a href="/hello">测试绝对路径</a>
</body>
</html>
在请求控制器HelloContorller.java中创建处理请求的方法
创建方法hello,用来处理超链接的跳转,其中@RequestMapping注解后面的value值要和跳转的超链接后面的值一致
HelloContorller.java代码如下
package com.atguigu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @ClassName: HelloContorller
* @Description:
* @Author: wty
* @Date: 2023/1/16
*/
@Controller
public class HelloContorller {
/**
* @param
* @return java.lang.String
* @description //首页,门户
* @date 2023/1/16 19:03
* @author wty
**/
@RequestMapping("/")
public String portal() {
// 将逻辑视图返回
return "index";
}
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
新建跳转界面success.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>成功</title>
</head>
<body>
<h1>成功</h1>
</body>
</html>
我们再运行Tomcat看一下
鼠标悬停看一下跳转地址
这里显然是可以跳转成功的
鼠标悬停看一下另一个跳转地址
跳转失败
比对一下跳转地址,看到了前者是有上下文,后者是没有的,得出结论Thymeleaf标签是可以自动补充缺失的地址的。
2.7总结
浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面。
3.@RequestMapping注解
重新创建新的Module
Name:spring-mvc-demo
GroupId:com.atguigu
在pom.xml中增加打包方式的依赖
<packaging>war</packaging>
拷贝之前的依赖
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
配置web.xml信息
路径更改为
F:\javawebwork\SSM\spring-mvc-demo\src\main\webapp\WEB-INF\web.xml
点击ok即可
配置完目录如下
配置web.xml
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
创建类com.atguigu.controller.TestRequestMappingController
@Controller
public class TestRequestMappingController {
}
创建springmvc.xml
<!-- 扫描控制层组件(自己配置package) -->
<context:component-scan base-package="com.atguigu.controller"></context:component-scan>
<!-- 配置Thymeleaf视图解析器(直接拷贝即可) -->
<bean id="viewResolver"
class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!--
比如当前index的实际位置在/WEB-INF/templates/index.html(物理视图)
去掉视图前缀变为 index.html
去掉视图后缀变为 index(逻辑视图)
-->
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
创建一个首页的控制器PortalController.java
com.atguigu.controller.PortalController
@Controller
public class PortalController {
@RequestMapping("/")
public String portal() {
return "index";
}
}
新建文件夹,创建index.html
创建首页index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>index.html</h1>
</body>
</html>
修改Tomcat配置
配置启动和更新配置
启动Tomcat看一下效果,得到的首页如下。
3.1@RequestMapping注解的功能
从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
3.2@RequestMapping注解的位置
@RequestMapping标识一个类:设置映射请求的请求路径的初始信息。
@RequestMapping标识一个方法:设置映射请求请求路径的具体信息。
看一下源码,看到@RequestMapping注解的位置如下。
我们先新建测试类com.atguigu.controller.TestRequestMappingController
先在方法上定义注解
@Controller
public class TestRequestMappingController {
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
新建跳转成功的页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>跳转成功</title>
</head>
<body>
<h1>success.html</h1>
</body>
</html>
下面我们尝试在类上TestRequestMappingController.java增加注解@RequestMapping
TestRequestMappingController.java代码如下:
@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
在首页上增加成功的跳转相关代码
index.html如下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>index.html</h1>
<a th:href="@{/hello}">测试@RequestMapping注解所标识的位置</a>
</body>
</html>
运行Tomcat看一下运行后的结果
那是因为在类上的@RequestMapping注解,设置映射请求的请求路径的初始信息。那么就应该是/test/hello,于是我们更改一下地址,重新访问一下。
我们发现这次更改地址后,跳转成功
为了更好的理解,在类上的@RequestMapping注解,我们做如下测试。
修改TestRequestMappingController.java
把类上的@RequestMapping注解注释掉
@Controller
//@RequestMapping("/test")
public class TestRequestMappingController {
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
拷贝TestRequestMappingController类中的hello方法到PortalController.java中
@RequestMapping("/hello")
public String hello() {
return "success";
}
操作如下:
之后我们再运行Tomcat看一下会出现什么?
很明显有了抛出异常信息。
IllegalStateException: Ambiguous mapping. Cannot map ‘testRequestMappingController’ method
这种是我们常间分模块开发会遇到的问题,那就是在多个不同类的方法中标记的@RequestMapping注解的value属性值相同,那么我们需要用:
类上的@RequestMapping注解的value属性值+方法上的@RequestMapping注解的value属性值
来访问相关页面
举例如下:有2个模块,类名上的@RequestMapping注解value不同,方法上的@RequestMapping注解value不同。
模块一想要访问
模块二想要访问
3.3@RequestMapping注解的value属性
value和path属性是一样的
看一下value是数组,那么说明可以同时增加多个value的属性值,如下:
@Controller
public class TestRequestMappingController {
@RequestMapping({"/hello", "/abc"})
public String hello() {
return "success";
}
}
同样,如果要匹配多个servlet也是可以的
修改index.html,增加abc的跳转
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>index.html</h1>
<a th:href="@{/hello}">测试@RequestMapping注解所标识的位置</a>
<br/>
<a th:href="@{/abc}">测试@RequestMapping注解的value属性</a>
</body>
</html>
把PortalController.java中多余的@RequestMappin注解注释掉
@Controller
//@RequestMapping("/student")
public class PortalController {
@RequestMapping("/")
public String portal() {
return "index";
}
//@RequestMapping("/hello")
public String hello() {
return "success";
}
}
运行Tomcat看一下结果,验证@RequestMapping的value是否可以是多个值。
点击/hello的跳转
跳转成功
点击/abc的跳转
跳转成功
因为我们说path和value一样的,那我们把value更改成path
修改TestRequestMappingController.java
@Controller
public class TestRequestMappingController {
@RequestMapping(path = {"/hello", "/abc"})
public String hello() {
return "success";
}
}
一样可以跳转成功
总结:
@RequestMapping注解的value属性通过请求的请求地址匹配请求映射。
@RequestMapping注解的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求。
@RequestMapping注解的value属性必须设置,至少通过请求地址匹配请求映射。
3.4@RequestMapping注解的method属性
先来看下method属性的源码
看一下RequestMethod的源码,是枚举类型的。
枚举类型比较多,我们学过的其实只有get和post,那么我们用get试一下。
修改TestRequestMappingController.java
@Controller
public class TestRequestMappingController {
@RequestMapping(
value = {"/hello", "/abc"}, method = RequestMethod.GET
)
public String hello() {
return "success";
}
}
我们再来运行一下Tomcat看一下2种跳转
点击第一种
点击第二种
这个时候,如果我们想测试一下post请求呢
直接修改TestRequestMappingController.java,更改为POST请求
代码如下:
@Controller
public class TestRequestMappingController {
@RequestMapping(
value = {"/hello", "/abc"}, method = RequestMethod.POST
)
public String hello() {
return "success";
}
}
重新运行Tomcat,看一下,显然用GET是不合适的。
报错:HTTP Status 405 - Request method ‘GET’ not supported
那么我们必须改造一下前端页面,变成post请求的形式,这种方式往往是form表单的提交。
修改index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>index.html</h1>
<a th:href="@{/hello}">测试@RequestMapping注解所标识的位置</a>
<br/>
<a th:href="@{/abc}">测试@RequestMapping注解的value属性</a>
<form th:action="@{/hello}" method="post">
<input type="submit" value="测试@RequestMapping注解的method属性">
</form>
</body>
</html>
再运行Tomcat看一下,点击提交表单
跳转成功
那么问题来了,如果我们想二者兼得,即有GET,又有POST该怎么办呢,我们从源码中想到了,RequestMethod类型的method属性是个数组。
修改TestRequestMappingController.java
package com.atguigu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @ClassName: TestRequestMappingController
* @Description:
* @Author: wty
* @Date: 2023/1/17
*/
@Controller
public class TestRequestMappingController {
@RequestMapping(
value = {"/hello", "/abc"}, method = {RequestMethod.POST, RequestMethod.GET}
)
public String hello() {
return "success";
}
}
有了上面的修改之后,再次运行Tomcat从以下三个任意选择标签跳转
都可以跳转成功
总结:
@RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射。
@RequestMapping注解的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求。
若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错。
405:Request method ‘POST’ not supported
只有表单提交、Ajax提交的时候,设置的method是post请求,采用post请求,剩下基本都是get请求。
注:
1、对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解。
处理get请求的映射–>@GetMapping
处理post请求的映射–>@PostMapping
处理put请求的映射–>@PutMapping
处理delete请求的映射–>@DeleteMapping
2、常用的请求方式有get,post,put,delete
但是目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理。
若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter,在RESTful部分会讲到。
3.5@RequestMapping注解的params属性(了解)
先看一下源码:
对于params属性来说,它也是数组类型,但是它和value以及method不同的是,value和method是数组中只要任意一个满足即可,而params是控制器所匹配的请求全都要满足params中的属性。
例如:
修改TestRequestMappingController.java
package com.atguigu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class TestRequestMappingController {
@RequestMapping(
value = {"/hello", "/abc"},
method = {RequestMethod.POST, RequestMethod.GET},
params = {"username"}
)
public String hello() {
return "success";
}
}
直接运行Tomcat,发现报错了
HTTP Status 400 - Parameter conditions “username” not met for actual request parameters:
针对这个报错我们改进一下前台页面index.html
代码如下:
<a th:href="@{/hello?username=admin}">测试@RequestMapping注解的params属性</a>
运行Tomcat,点击新增的超链接
发现成功跳转
相同的方式还有
代码如下:
<a th:href="@{/hello(username='admin')}">测试@RequestMapping注解的params属性</a>
点击最后一个超链接跳转
跳转结果,发现也是可以跳转成功的。
因为params是个数组类型,那么我们尝试一下再增加一个参数。
"!password"也就是不要含有password的意思。
修改TestRequestMappingController.java
@Controller
public class TestRequestMappingController {
@RequestMapping(
value = {"/hello", "/abc"},
method = {RequestMethod.POST, RequestMethod.GET},
params = {"username", "!password"}
)
public String hello() {
return "success";
}
}
重新部署一下Tomcat
这里的跳转肯定也是没有问题的。
那如果后缀加上password的话,那我们再跳转一下
发现直接报错,说明!password就是不能携带password
HTTP Status 400 - Parameter conditions “username, !password” not met for actual request parameters: username={admin}, password={}
我们继续修改TestRequestMappingController.java
增加参数age=20
@Controller
public class TestRequestMappingController {
@RequestMapping(
value = {"/hello", "/abc"},
method = {RequestMethod.POST, RequestMethod.GET},
params = {"username", "!password", "age=20"}
)
public String hello() {
return "success";
}
}
再跳转一下,发现报错。
那我们加上参数age=20再看一下。
http://localhost:8080/SpringMVC/hello?username=admin&age=20
跳转成功
我们继续增加参数
!gender=女
params = {"username", "!password", "age=20", "gender!=女"}
重新刷新Tomcat,登录网址
http://localhost:8080/SpringMVC/hello?username=admin&age=20
看一下结果,是跳转成功的。
我们更改地址
http://localhost:8080/SpringMVC/hello?username=admin&age=20&gender=女
更改地址如下:跳转报错
发现报错
HTTP Status 400 - Parameter conditions “username, !password, age=20, gender!=女” not met for actual request parameters: username={admin}, age={20}, gender={女}
更改成
http://localhost:8080/SpringMVC/hello?username=admin&age=20&gender=男
发现跳转结果
总结:
@RequestMapping注解的params属性通过请求的请求参数匹配请求映射。
@RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系。
“param”:要求请求映射所匹配的请求必须携带param请求参数。
“!param”:要求请求映射所匹配的请求必须不能携带param请求参数。
“param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value。
“param!=value”:要求请求映射所匹配的请求可以不携带param,若携带的话,请求参数param!=value。
若浏览器所发送的请求的请求路径和@RequestMapping注释value属性匹配,但是请求参数不匹配,此时页面报错:400
3.6@RequestMapping注解的headers属性(了解)
在测试控制器中增加代码
代码如下
headers = {"referer"}
按F12之后,查看来源。注意来源是跳转之后才会有,首页是不会有的。
跳转后,查看F12
那我们如果直接去访问跳转后的网址,可以成功吗,我们尝试一下。
发现抛出错误
HTTP Status 404 -
@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射。
@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系。
“header”:要求请求映射所匹配的请求必须携带header请求头信息。
“!header”:要求请求映射所匹配的请求必须不能携带header请求头信息。
“header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value。
“header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value。
若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面显示404错误,即资源未找到。
3.7SpringMVC支持ant风格的路径
?:表示任意的单个字符
*:表示任意的0个或多个字符,不包括?和/
** :表示任意层数的任意目录
注意:在使用 ** 时,只能使用/**/xxx的方式, **的前后不能有其它字符。
测试一下,我们修改TestRequestMappingController.java
@RequestMapping("/a?a/test/ant")
public String testAnt() {
return "success";
}
修改页面index.html
<a th:href="@{/aaa/test/ant}">测试@RequestMapping注解支持ant风格的属性</a>
访问首页
http://localhost:8080/SpringMVC/
查看一下新加进去的超链接
跳转的新地址是
地址如下
http://localhost:8080/SpringMVC/aaa/test/ant
那么如果我们更改一下地址,还能成功吗
更改如下
http://localhost:8080/SpringMVC/a+a/test/ant
发现访问成功
更改如下
http://localhost:8080/SpringMVC/ava/test/ant
发现访问成功
更改如下
http://localhost:8080/SpringMVC/a?a/test/ant
发现报错
HTTP Status 404 -
因为对于?来说,系统会认为是路径和参数的分隔符。
那如果是两个字符呢,我们继续修改地址
http://localhost:8080/SpringMVC/aaaa/test/ant
我们发现依然报错
HTTP Status 404 -
说明?只能表示任意的单个字符。
现在我们来看下*是如何占位的。
修改TestRequestMappingController.java
@RequestMapping("/a*a/test/ant")
public String testAnt() {
return "success";
}
可以发现跳转成功
http://localhost:8080/SpringMVC/aaa/test/ant
跳转成功
更改地址为
http://localhost:8080/SpringMVC/a+a/test/ant
更改地址
http://localhost:8080/SpringMVC/aaaa/test/ant
发现上述地址都可以跳转成功,但是如果更改为
http://localhost:8080/SpringMVC/a?a/test/ant
发现就会报错
HTTP Status 404 -
那如果更改为/会报错吗
http://localhost:8080/SpringMVC/a/a/test/ant
发现依然会报错,因为/是地址的分隔符。
最后看一下**
更改TestRequestMappingController.java
@RequestMapping("/**/test/ant")
public String testAnt() {
return "success";
}
我们再重新部署一下Tomcat
发现跳转成功
修改地址为
http://localhost:8080/SpringMVC/a/aa/a/a/a/test/ant
发现依然跳转成功
3.8SpringMVC支持路径中的占位符(重点)
原始方式:/deleteUser?id=1
rest方式:/user/delete/1
SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参。
在index.html增加
<a th:href="@{/test/rest/1}">测试@RequestMapping注解的value属性的占位符</a>
在TestRequestMappingController.java中增加方法
@RequestMapping("/test/rest/{id}")
public String testRest(@PathVariable("id") Integer id) {
System.out.println("id:" + id);
return "success";
}
重新部署Tomcat查看结果
单击新增加的超链接
最后查看控制台输出的结果
说明数字是可以输出成功的,那么如果是字符串呢,我们来尝试一下。
修改index.html
<a th:href="@{/test/rest/admin/1}">测试@RequestMapping注解的value属性的占位符</a>
修改TestRequestMappingController.java
@RequestMapping("/test/rest/{username}/{id}")
public String testRest(@PathVariable("username") String username, @PathVariable("id") Integer id) {
System.out.println("username:" + username);
System.out.println("id:" + id);
return "success";
}
重新部署Tomcat查看结果
看一下控制台的跳转