该注解有什么作用呢?
我们可以查看一下该注解的源码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
通过Target注解标记的是当前注解可以使用的位置
需求:我们分别在类和方法上都使用注解并指定路径和侧面测试一下
编写我们的 success.html 页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>"来到了我们的success页面,匹配成功!"</p>
</body>
</html>
在我们 index.html 中添加一条超链接
<a th:href="@{/parentPath/target}">测试我们RequestMapping注解的位置</a>
为了不影响我们首页文件的匹配,我们另外写一个控制器Test2测试
package com.atguigu.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Bonbons
* @version 1.0
*/
@Controller
@RequestMapping("/parentPath")
public class Test2 {
@RequestMapping("/target")
public String testLocation(){
return "success";
}
}
控制器Test我们只需要让它去匹配首页页面
package com.atguigu.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Bonbons
* @version 1.0
*/
@Controller
public class Test {
@RequestMapping("/")
public String index() {
//设置视图名称
return "index";
}
}
通过 tomcat 运行测试

点击链接可以正常跳转

@RequestMapping(value = "路径")在首页编写我们的条用于测试的超链接
<a th:href="@{/test}">value属性对应多个路径的请求</a>
在我们的控制器 Test2 中编写控制器方法
package com.atguigu.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Bonbons
* @version 1.0
*/
@Controller
public class Test2 {
@RequestMapping(
value = {"/parentPath/target", "/test"}
)
public String testLocation(){
return "success";
}
}
运行tomcat服务器查看测试结果 >> 点击都可以跳转到我们指定的页面


在首页编写我们的表单代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>爷青结!!!</h1>
<a th:href="@{/parentPath/target}">测试我们RequestMapping注解的位置</a><br>
<!--以post方式请求的表单-->
<form th:action="@{/test}" method="post">
<input type="submit">
</form>
</body>
</html>
修改我们的控制器
package com.atguigu.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author Bonbons
* @version 1.0
*/
@Controller
public class Test2 {
@RequestMapping(
value = {"/parentPath/target", "/test"},
// 此处我们就将请求方式设置为post,预计超链接的请求找不到对应的映射
method = {RequestMethod.POST}
)
public String testLocation(){
return "success";
}
}
运行我们的 tomcat 进行测试
点击以get方式请求的超链接

点击以post方式请求表单的提交按钮

通过运行结果我们可以得知
SpringMVC 为我们提供了@RequestMapping派生注解,用于处理我们指定请求方式的控制器方法
我们常用的请求方式有 get、post、put、delete
该参数是通过请求参数匹配映射的,如果传递过来的请求不符合我们请求参数的规定,那么就不会被处理
该参数的类型是一个字符串类型的数组,我们一般有四种表达式:
需求:我们编写两条超链接,一个满足参数要求,一个不满足参数要求进行测试
编写我们的控制器方法
package com.atguigu.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author Bonbons
* @version 1.0
*/
@Controller
public class Test2 {
@RequestMapping(
value = {"/parentPath/target", "/test"},
// 此处我们就将请求方式设置为post,预计超链接的请求找不到对应的映射
method = {RequestMethod.POST},
params = {"username=root"}
)
public String testLocation(){
return "success";
}
}
对我们的首页进行配置,添加一条不符合参数要求的请求
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>爷青结!!!</h1>
<a th:href="@{/parentPath/target(username=root)}">测试我们RequestMapping注解的位置</a><br>
<a th:href="@{/test(username=admin)}">用户名不满足我们参数要求的请求</a>
</body>
</html>
运行我们tomcat服务器进行测试


该属性通过请求的请求头信息匹配请求映射
与params属性类似,无论有多少属性值,都要同时满足才能匹配成功,也有四种表达式
通过浏览器的检查功能我们可以查看请求头信息

SpringMVC 支持 ant 风格的路径,也就是支持使用通配符
* 代表任意个字符/**/SpringMVC 也支持路径中的占位符,也就是有些参数值我们可以采用位置对应的方式进行传递
// 原始方式
/deleteUser?id=1
// rest方式
/deleteUser/1
我们在请求处传递参数值,在控制器的方法形参处获得参数值【使用了@PathVariable注解类似于Spring的@Parameter注解】

我们编写一个param_test.html 页面,后续测试的请求也都写在这个页面里
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>请求参数专题</title>
</head>
<body>
<h1>练习使用获取请求参数</h1>
<a th:href="@{/testServletAPI(username = 'root', password = 123456)}">测试通过ServletAPI获取我们的参数</a>
</body>
</html>
/ 为localhost:8080,所以此处自动会为我们补全绝对路径编写我们的 ParamController 控制类,后续的控制器方法也都写在这个源文件中
package com.atguigu.mvc.controller;
import com.atguigu.mvc.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**
* @author Bonbons
* @version 1.0
*/
@Controller
public class ParamController {
// 使用Servlet的API获取参数 >> 不推荐使用,如果我们传递参数的时候没用属性名就没法用
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
// 当我们使用HttpServletRequest作为形参时,Dispatcher控制器会将数据封装到我们的形参之中
// request >> 代表我们当前的这个请求
String username = request.getParameter("username");
String password = request.getParameter("password");
// 输出我们获取到的形参数据
System.out.println("username = " + username + ", password = " + password);
return "success";
}
}
运行我们 tomcat 服务器进行测试

点击超链接后,成功跳转我们指定也页面,并且控制台打印出了我们获取到的参数


我们添加一条请求语句 ,用于测试控制器方法获取参数【在前端页面里添加一条超链接】
<a th:href="@{/testParam(username = 'root', password = 123456)}">测试通过springMVC的构造器方法获取我们的参数</a><br>
然后在我们控制器类中编写对应的方法
// 使用SpringMVC的控制器方法来获取参数 -- 只需要方法的形参和传递参数的名一致就可以
@RequestMapping("/testParam")
public String testParam(String username,String password){
// 输出信息
System.out.println("username = " + username + ", password = " + password + ");
// 返回要跳转的页面
return "success";
}
运行测试


如果存在多个同名的请求参数,我们可以使用字符串来接收或字符串数组来接收
我们思考一个问题,既然能用对应属性名相同的形参接收,那么我们是不是可以把这些形参封装下一呢?
我们通过表单来获取数据,先编写我们的请求页面的代码
<!--为了演示通过pojo类来封装表单数据,我们需要写一个表单-->
<form th:action="@{/testPOJO}" method="post">
用户名 <input type="text" name="username"><br>
密码 <input type="text" name="password"><br>
性别 <input type="radio" name="sex">男<input type="radio" name="sex">女<br>
年龄 <input type="text" name="age"><br>
邮箱 <input type="text" name="email"><br>
<input type="submit" value="用实体类接收请求参数">
</form>
编写我们的POJO类User,有点类似于Spring中POJO类封装数据对象
package com.atguigu.mvc.bean;
/**
* @author Bonbons
* @version 1.0
*/
public class User {
private String username;
private String password;
private Integer age;
private String sex;
private String email;
// 因为我们使用反射机制创建对象,所以如果存在有参构造方法就一定要有无参构造方法
public User() {
}
public User(String username, String password, Integer age, String sex, String email) {
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
'}';
}
}
编写我们的控制器方法
// 测试我们利用实体类接收参数
@RequestMapping("/testPOJO")
public String testPOJO(User user){
// 因为我们提供了toString方法,所以此处直接输出
System.out.println(user);
return "success";
}
运行服务器进行测试

跳转页面成功,并在控制台成功打印获取到的参数值


在SpringMVC中为我们提供了 @Request 注解,可以将请求参数和控制器方法的形参创建映射关系
该注解具有四个属性值:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
编写控制器方法演示一下正确用法,此处就不挨个测试错误的用法了
// 使用SpringMVC的控制器方法来获取参数 -- 只需要方法的形参和传递参数的名一致就可以
@RequestMapping("/testParam")
public String testParam(@RequestParam(value = "user_name", required = false, defaultValue = "default") String username, String password)
{
// 如果使用了@RequestParam()注解,就自动装配机制默认必须为其传递参数名
// 输出信息
System.out.println("username = " + username + ", password = " + password);
return "success";
}
编写我们用于请求的超链接
<a th:href="@{/testParam(user_name, password = 123)}">测试使用@RequestParam注解获取参数</a>

点击超链接后成功跳转我们预设的页面

控制台打印出我们预期的信息,我们通过 required 字段指定 user_name 是请求必须传递的参数,通过 value 字段指定将我们user_name 参数名用username代替,然后在请求的超链接种我特意不给user_name赋值,然后通过defaultValue字段使用我们预设的默认属性值

一种为 get 请求出现的乱码,我们需要修改 tomcat 服务器的配置

另一种为 post 请求出现的乱码,我们需要通过手动配置过滤器去解决【在web.xml中注册】
<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>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*
