上一期呢我们说到SpringMVC的第一大核心知识:建立连接,上一期我们说学习Spring MVC主要是学习三个东西:建立连接、请求和响应。那么建立连接,我们在上一期介绍完后,本期我们来介绍请求。
请求处理:参数传递与接收
我们使用Postman发送请求和使用客户端发送请求对于后端而言是一样的,
就像外卖和堂食对于我们厨师来说是一样的。
请求处理的核心是"前端传递参数,后端接收参数",Spring MVC支持多种参数传递方式,后端可灵活接收。
1 传递单个参数
后端直接在方法中定义与前端参数名一致的形参,即可接收参数:
那么我先看前端的请求:

我们看后端的代码:
java
package com.zhongge.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName RequestController
* @Description TODO 请求控制器
* @Author 笨忠
* @Date 2026-02-06 15:26
* @Version 1.0
*/
@RestController//加上这个注解代表将我们的对象交给Spring管理 带有Rest代表的是所有的方法返回的是JSON格式
@RequestMapping("/request")//类路径
public class RequestController {
//由于我们还没有说响应所以我们的方法都先返回字符串
@RequestMapping("/r1")//方法路径
public String r1(String name){
//注意的是我们的name参数一定是从我们的方法形参列表中获取的
return "一个参数:" + name;
//后续我们还可以将name存入到我们的数据库中去进行一个对比
}
}
请求的结果:

注意事项:
1.参数名必须与前端一致,否则无法获取参数。【这个在后面解释】
2.基本类型(除boolean外)接收参数时,参数必须传递,否则报500错误;类型不匹配时,报400错误。
比如现在我使用的是基本类型
java
@RequestMapping("/r2")
public String r2(int num){
return "一个参数得到的是值:" + num;
}
1)如果正确传递

2)如果不传递,后台报错

3)传递类型不匹配的话,你们就是前端报错

3,经过上述因此我们建议使用包装类型(如Integer、String)接收参数,参数未传递时会赋值为null,避免报错。原因就是我们SpringMVC接受到的参数都是String类型,他回去给你去转,所以对于包装类型,如果转不了的话,那么就是默认为null
java
此时就算你的参数没有给,那么都不会报错

2 传递多个参数
与单个参数接收方式一致,定义多个形参,前端按参数名传递即可,参数顺序不影响接收结果:
后端代码:
java
//传递多个参数,用户名和密码
@RequestMapping("/r4")
public String r4(String username, String password){
return "用户名是:" + username + " 密码是:" + password;
}
使用GET方式请求:

使用表单形式+POST方式请求

3 传递对象
当参数较多时,可将参数封装为Java对象,Spring MVC会根据参数名自动绑定到对象的属性上:
- 定义实体类(如User),包含对应属性、getter/setter方法和toString方法。
- 后端方法直接接收该对象作为参数:
实体类
java
package com.zhongge.demo;
/**
* @ClassName User
* @Description TODO 实体类 User
* @Author 笨忠
* @Date 2026-02-08 16:14
* @Version 1.0
*/
public class User {
//用户名
private String username;
//年龄
private Integer age;//注意 我们建议使用包装类
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//重写toString方法
@Override
public String toString() {
return "User{" +
"用户名='" + username + '\'' +
", 年龄=" + age +
'}';
}
}
处理器方法
java
// URL:http://127.0.0.1:8080/param/m3?id=5&name=zhangsan&password=123456
@RequestMapping("/m3")
public Object method3(Userp){
return p.toString();
}

说明:未传递的属性,引用类型赋值为null,基本类型赋值为默认值(如int为0)。
注意事项:
实体类要有get和set方法,否则将就会读取不到数据导致数据为null,因为底层是反射机制。
java
package com.zhongge.demo;
/**
* @ClassName User
* @Description TODO 实体类 User
* @Author 笨忠
* @Date 2026-02-08 16:14
* @Version 1.0
*/
public class User {
//用户名
private String username;
//年龄
private Integer age;//注意 我们建议使用包装类
/* public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
*/
//重写toString方法
@Override
public String toString() {
return "User{" +
"用户名='" + username + '\'' +
", 年龄=" + age +
'}';
}
}
如果没有实体类,那么此时就是

4 后端参数重命名(@RequestParam)
解释:为什么前端的参数和后端形参需要一致?
如图所示:我们前端传递的参数是username,password。

那么此时我后端的处理器方法代码如下:
java
@RequestMapping("/r4")
public String r4(String username, String password){
//接受的参数是和前端的一致的username和password
return "用户名是:" + username + " 密码是:" + password;
}
那么他具体的处理逻辑是什么呢?我们看下图:

首先我的前端传递的是username和password,那么此时我们就会使用一个map集合将他存起来,然后的话,我们的后端就根据形参列表中参数名字去map集合中进行比对,如果找到了,那么就取到对应的值了。
如果前端的参数和我们后端的形参名字不同的话,那么此时我们就无法取到值,于是我们username和password的值都是空的null,首先看现象
java
//参数不一致的情况
@RequestMapping("/r6")
public String r6(String name, String psd){
return "用户名是:" + name + " 密码是:" + psd;
}
现象
原理如图所示:

由于我后端使用的是name和psd去map集合里面去寻找,所以我们最终没有找到对应的值,所以才会读到null。

那么我们怎么解决这样的问题呢?
我们使用@RequestParam【请求参数】
当前端传递的参数名与后端接收的参数名不一致时,使用@RequestParam注解重命名:
java
//使用RequestParam注解
@RequestMapping("/r6")
public String r6(@RequestParam("username") String name,@RequestParam("password") String psd){
return "用户名是:" + name + " 密码是:" + psd;
}
现象:此时就可以正确的取到数据了

原理如图所示:

就是说使用@RequestParam("username") String name代表的是将username拿去集合中找到key为username的值,如果找到了就将这个值赋值给name变量。
@RequestParam注解的详解
java
@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";
}
1.第一个属性value和name
-
value 和 name 是别名关系,功能完全相同
-
如果不指定,默认使用方法参数名作为请求参数名
2.required 属性 - 参数必要性控制
-
默认值为 true,意味着默认所有参数都是必需的
-
当 required=true 且参数未传递时,Spring会抛出异常
3.defaultValue 属性 - 默认值设置
- defaultValue 的值永远是字符串
- Spring会自动进行类型转换(String → 目标类型)
- 设置了 defaultValue 时,required 属性自动视为 false
- 默认值对空字符串也生效
关键说明:
- @RequestParam修饰的参数默认是必传的,未传递会报400错误。
- 非必传参数设置:添加required=false(如@RequestParam(value = "time", required = false))。
也就是说你使用这个注解,那么默认这个参数你就必须传递
如果不传递就会报错
此时如果你将required属性设置为false,那么就代表这个参数不是必须传递的,此时就不会报错了

现象:
那么注意的是:比如我们搞一个登录功能,那么用户名和密码是必须传递的,那么此时就可以使用@RequestParam来限制你这个参数必须传递。
5 传递数组
后端定义数组类型形参,前端传递多个同名参数即可,Spring MVC会自动封装为数组:
后端代码:
java
//传递数组
@RequestMapping("/r7")
public String r7(String[] arr) {
return "数组中的值是:" + Arrays.toString(arr);
}
1)第一种请求方式:单独的输入多个arr的值

2)只输入一个arr,然后使用逗号隔开

补充:前端也可通过"arrayParam=zhangsan,lisi,wangwu"的方式传递,后端同样能接收。
6 传递集合
集合参数需配合@RequestParam注解使用,Spring MVC会将多个同名参数封装为集合:
java
@RequestMapping("/r8")
public String r8( List<String> list) {
return "集合中的值是:" + list;
}
那么此时我们如果想使用数组一样的方式处理的话,那么后端就会报错


后端报错信息:

那么原因是什么?
上述的参数传递方式会默认当做数组来处理,所以如果你需要将他变为集合的话,那么此时得注意加上一个参数绑定注解@RequestPrame
java
@RequestMapping("/r8")
public String r8(@RequestParam List<String> list) {
return "集合中的值是:" + list;
}
结果:此时就不会报错了

注意:@RequestParam List<String> list @RequestParam 不写属性value,那么value的值默认就是参数名字list
7 传递JSON数据(@RequestBody)
JSON就是JavaScript的对象表示法。
JSON是前后端数据交互的常用格式,本质是字符串,支持对象、数组等复杂结构,Spring MVC通过@RequestBody注解接收JSON对象。
JSON核心基础
- 语法:数据以键值对形式存在,用{}表示对象,[]表示数组,键值(key/value)对用逗号分隔,属性和值之间使用冒号分开,键key使用引号,值value中如果是字符串就是用引号。
- 优点:简单易用、跨平台、轻量级、易于扩展、安全性高。
- JSON与Java对象互转:Spring MVC集成jackson-databind工具,所以说我们如果写的是Spring项目的话, 那么你就不用手动去将Java和JSON进行转换了,因为SpringMVC已经为我们做好了,通过ObjectMapper的writeValueAsString(对象转JSON)和readValue(JSON转对象)方法实现。
jackson的使用:
对象变为JSON
对象
java
package com.zhongge.demo;
/**
* @ClassName User
* @Description TODO 实体类 User
* @Author 笨忠
* @Date 2026-02-08 16:14
* @Version 1.0
*/
public class User {
//用户名
private String username;
//年龄
private Integer age;//注意 我们建议使用包装类
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//重写toString方法
@Override
public String toString() {
return "User{" +
"用户名='" + username + '\'' +
", 年龄=" + age +
'}';
}
}
补充单元测试

对应的代码
java
/**
* 对象转为JSON
*/
@Test//加这个注释代表的是单元测试
void TestObjectToJson() throws JsonProcessingException {
//首先做对象和JSON之间转换的人是:ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
//然后你是需要Java对象转为JSON的
//所以现在就需要先创建一个Java对象
User user = new User();
user.setUsername("李四");
user.setAge(10);
//那么现在就开始将Java对象转为JSON
//使用ObjectMapper中的writeValueAsString
//writeValueAsString从后向前翻译就是将值写为字符串,而我们的Java变为JSON就是将值作为字符串
String json = objectMapper.writeValueAsString(user);
//最后将JSON对象打印出
System.out.println(json);
}
对应的结果就是如下:

JSON变对象
对应的代码:
java
/**
* JSON变为Java对象
*/
@Test
void testJsonToObject() throws JsonProcessingException {
//首先做对象和JSON之间转换的人是:ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
//然后你得有一个JSON字符串
String json = "{\"username\":\"李四\",\"age\":10}";
//那么此时就调用我们的ObjectMapper中的readValue方法
//readValue代表的是将 某某JSON字符串变为 某某对象[使用的是类对象]
User user = objectMapper.readValue(json, User.class);
//将对象输出
System.out.println(user);
}
对应的结果:

JSON表示一个对象
json
{
"id": 1001,
"username": "张三",
"age": 25,
"isVip": true,
"email": null,
"address": {
"city": "北京",
"street": "海淀区中关村"
}
}
对应的Java对象
java
public class User {
private Integer id;
private String username;
private Integer age;
private Boolean isVip;
private String email; // 为 null
private Address address; // 嵌套对象
// getters and setters...
}
public class Address {
private String city;
private String street;
// getters and setters...
}
表示一个数组
json
["苹果", "香蕉", "橙子", "葡萄"]
对应Java中
java
// 可能是 List<String>
List<String> fruits = Arrays.asList("苹果", "香蕉", "橙子", "葡萄");
数组里包含多个对象
json
[
{
"id": 1001,
"username": "张三",
"age": 25
},
{
"id": 1002,
"username": "李四",
"age": 30
},
{
"id": 1003,
"username": "王五",
"age": 28
}
]
对应的Java中
java
// 通常是 List<User>
List<User> userList = new ArrayList<>();
// ... 向列表中添加 User 对象
对象里包含数组
json
{
"departmentName": "技术部",
"employeeCount": 3,
"employees": [
{
"name": "程序员A",
"title": "工程师"
},
{
"name": "程序员B",
"title": "高级工程师"
},
{
"name": "程序员C",
"title": "架构师"
}
]
}
对应的Java中
java
public class Department {
private String departmentName;
private Integer employeeCount;
private List<Employee> employees; // 对象内包含集合
// getters and setters...
}
public class Employee {
private String name;
private String title;
// getters and setters...
}
更复杂的嵌套(对象套数组,数组里对象再套数组...)
json
{
"articleId": 1,
"title": "JSON 入门指南",
"comments": [
{
"userId": "user123",
"content": "好文章!",
"replies": [ // 评论下还有回复(数组)
{
"userId": "user456",
"content": "同意!"
}
]
},
{
"userId": "user789",
"content": "例子很详细。",
"replies": [] // 该评论暂无回复,空数组
}
]
}
后端接收JSON代码示例
后端实体类
java
package com.zhongge.demo;
/**
* @ClassName User
* @Description TODO 实体类 User
* @Author 笨忠
* @Date 2026-02-08 16:14
* @Version 1.0
*/
public class User {
//用户名
private String username;
//年龄
private Integer age;//注意 我们建议使用包装类
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//重写toString方法
@Override
public String toString() {
return "User{" +
"用户名='" + username + '\'' +
", 年龄=" + age +
'}';
}
}
前端使用Postman来传递JSON格式的对象
点击body->raw->选择json

然后输入json对象

后端的处理:后端的控制器方法如果需要商品SpringMVC为我们接收json对象并且处理他,那么此时就使用@RequestBody注解来标记,代表我们需要SpringMVC为我们做这件事情
java
//接受json对象参数
@RequestMapping("/r9")
public String r9(@RequestBody User user) {
return "由SpringMVC将json变为对象的是:" + user.toString();
}
处理的结果:

注意:@RequestBody作用于请求正文【就是请求体body】,参数必须写在请求正文中,不能通过URL拼接;去掉@RequestBody则无法接收JSON参数。
注意事项:SpringMVC将json转对象使用的优先级情况如下
java
// 优先级排序(从高到低):
1. @JsonCreator 注解的构造器/工厂方法
2. 公有全参构造器(Jackson 2.7+ 可自动检测)
3. 无参构造器 + setter 方法 ← 最常见的默认方式
4. 无参构造器 + 字段直接赋值(需配置)
8 获取URL路径参数(@PathVariable)
PathVariable翻译为路径参数/路径变量,代表的是从URL路径中获取参数,也就是我SpringMVC从URL路径中将参数给拿到。这种参数称为路径参数,他通常用于唯一的ID。
那么主要的步骤就两个:
1.自定义URL
java
@RequestMapping("/r10/{userId}/{userName}")//定义URL:定义出两个参数
2.@PathVariable使用注解,从你定义的URL中获取参数的值
java
//注意的是:@PathVariable是参数注解有几个参数就得有几个注解
public String r10(@PathVariable Integer userId,//使用@PathVariable注解接收自定义url中的参数
@PathVariable String userName) {
return "";
}
完整的代码:
java
//使用@PathVariable注解从自定义的URL中获取参数
@RequestMapping("/r10/{userId}/{userName}")//定义URL:定义出两个参数
public String r10(@PathVariable String userName,//使用@PathVariable注解接收自定义url中的参数
@PathVariable Integer userId) {
return "从自定义URL中获取的参数是:" + "用户ID:" + userId + " 用户名:" + userName;
}
结果:

注意事项:
前端传递的参数和后端自定义路径中的参数必须一一对应
后端自定义参数和方法形参中的顺序可以不用对应

比如:你的前端参数和后端的URL定义不匹配就会报400

9 上传文件(@RequestPart和MultipartFile的使用)
那么我们在开发中上传文件也是一个很关键的事情,在我们的SpringMVC中上传文件的操作就相当的简单,因为他已经为我们封装好了,我们只需要去调用就行了,我们使用MultipartFile类操作文件说白了就是使用这个类来接受文件,将这个类放在参数部分,MultipartFile翻译为多部分文件,主要就是用来操作文件的,底层封装了IO操作。
举个例子:
前端使用Postman上传文件,我们使用的是body->form-data


后端使用MultipartFile类来接收文件
java
@RequestMapping("/r11")
public String r11(MultipartFile file) {
//输出文件名
System.out.println(file.getOriginalFilename());
return "后端成功接收到文件:" + file.getOriginalFilename();
}
结果:

后端控制台结果:

后端使用MultipartFile将文件收到之后,后端如何将文件存在服务器硬盘上呢?
使用的是MultipartFile中的transferTo(文件对象),底层封装了一系列的文件IO读写的相关操作,我们只需要掉用就可以完成文件的保存到服务器
transferTo翻译为移动到
代码:
java
//上传文件
@RequestMapping("/r11")
public String r11(MultipartFile file) throws IOException {
//输出文件名
System.out.println(file.getOriginalFilename());
//将文件保存到服务器中
file.transferTo(new File("D:/code/" + file.getOriginalFilename()));
return "后端成功接收到文件:" + file.getOriginalFilename();
}
结果:文件保存成功

注意:可以使用@RequestPart注解来重命名参数
比如我的前端参数不是file而是改为f,那么此时就会报错

此时我就在后端使用该注解将参数命名
java
/**
* 使用@RequestPart注解将参数重命名
*/
@RequestMapping("/r11")
public String r11( @RequestPart("f") MultipartFile file) throws IOException {
//输出文件名
System.out.println(file.getOriginalFilename());
//将文件保存到服务器中
file.transferTo(new File("D:/code/" + file.getOriginalFilename()));
return "后端成功接收到文件:" + file.getOriginalFilename();
}
此时结果就正确了

测试:使用Postman的form-data格式,key设为file(与注解中一致),选择文件上传即可。
总结:
HTTP 请求的参数可以放在什么地方?
- URL资源路径【URL上除去查询字符串】
- URL查询字符串【问号?后面的,该参数称为请求参数】
- header
- 请求正文body【该参数称为请求参数】
至此,请求处理的核心知识已基本讲介绍完毕。剩余还有两项关键内容:获取 Cookie 与 Session、获取请求头header,其中 Cookie 和 Session 为重点内容,具体细节将在下期详细介绍。最后欢迎点赞、关注、收藏,感谢各位老铁。