news 2026/6/21 18:30:27

【Spring Boot + MyBatis|第2篇】@RequestParam、@PathVariable、@RequestBody 区别详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Spring Boot + MyBatis|第2篇】@RequestParam、@PathVariable、@RequestBody 区别详解

前言

上一篇我们学习了 Spring Boot + MyBatis 项目中的三层架构,也就是 Controller、Service、Mapper 分别负责什么。

在实际写 Controller 接口的时候,还有一个很常见的问题:

前端传过来的参数,后端到底应该怎么接收?

比如有时候我们这样写:

@GetMapping("/{id}")publicResultgetById(@PathVariableIntegerid){returnResult.success();}

有时候又这样写:

@GetMappingpublicResultlist(@RequestParamStringname){returnResult.success();}

新增数据时又经常这样写:

@PostMappingpublicResultsave(@RequestBodyEmpemp){returnResult.success();}

这里就涉及到三个非常常见的注解:

  • @RequestParam
  • @PathVariable
  • @RequestBody

这一篇我们就来单独梳理一下它们的区别,以及在项目中分别适合用在哪些场景。

一、三个注解分别用来接收什么?

可以先用一句话简单区分:

@RequestParam接收请求参数,@PathVariable接收路径参数,@RequestBody接收请求体 JSON 数据。

注解主要接收位置常见请求方式典型场景
@RequestParamURL 问号后面的参数GET条件查询、分页查询
@PathVariableURL 路径中的参数GET、DELETE根据 id 查询、删除
@RequestBody请求体中的 JSONPOST、PUT新增、修改复杂对象

下面我们分别来看。

二、@PathVariable:接收路径参数

1. 功能需求

比如我们要根据员工 id 查询员工信息。

前端请求路径是:

GET /emps/1

这里的1不是普通参数,而是路径的一部分。

这种情况下就适合使用@PathVariable

2. Controller 层实现

@RestController@RequestMapping("/emps")publicclassEmpController{@AutowiredprivateEmpServiceempService;@GetMapping("/{id}")publicResultgetById(@PathVariableIntegerid){Empemp=empService.getById(id);returnResult.success(emp);}}

3. Service 层实现

publicinterfaceEmpService{EmpgetById(Integerid);}
@ServicepublicclassEmpServiceImplimplementsEmpService{@AutowiredprivateEmpMapperempMapper;@OverridepublicEmpgetById(Integerid){returnempMapper.getById(id);}}

4. Mapper 层实现

@MapperpublicinterfaceEmpMapper{@Select("select id, username, name, gender, phone from emp where id = #{id}")EmpgetById(Integerid);}

5. 文字说明

这个接口的完整访问路径是:

/emps/{id}

当请求路径是:

/emps/1

Spring 会把路径中的1取出来,赋值给 Controller 方法中的id参数。

所以:

@PathVariableIntegerid

表示从路径中获取参数。

这种写法一般用于“资源定位”,比如:

GET /emps/1 根据 id 查询员工 DELETE /emps/1 根据 id 删除员工 GET /depts/3 根据 id 查询部门

6. 涉及知识点

1. 路径变量名称一致时可以省略名称

如果路径中写的是:

@GetMapping("/{id}")

方法参数也叫id

@PathVariableIntegerid

那么可以直接这样写。

2. 路径变量名称不一致时要指定名称

如果路径中写的是:

@GetMapping("/{empId}")

但是方法参数叫id,就需要这样写:

@GetMapping("/{empId}")publicResultgetById(@PathVariable("empId")Integerid){returnResult.success(empService.getById(id));}

否则 Spring 可能不知道应该把哪个路径变量赋值给哪个参数。

三、@RequestParam:接收普通请求参数

1. 功能需求

比如我们要做员工条件查询,前端可能会这样传参:

GET /emps?name=张三&gender=1&page=1&pageSize=10

这里的参数都在 URL 的问号后面,这种参数就适合使用@RequestParam

2. Controller 层实现

@RestController@RequestMapping("/emps")publicclassEmpController{@AutowiredprivateEmpServiceempService;@GetMappingpublicResultpage(@RequestParam(defaultValue="1")Integerpage,@RequestParam(defaultValue="10")IntegerpageSize,Stringname,Integergender){PageBeanpageBean=empService.page(page,pageSize,name,gender);returnResult.success(pageBean);}}

3. Service 层实现

publicinterfaceEmpService{PageBeanpage(Integerpage,IntegerpageSize,Stringname,Integergender);}
@ServicepublicclassEmpServiceImplimplementsEmpService{@AutowiredprivateEmpMapperempMapper;@OverridepublicPageBeanpage(Integerpage,IntegerpageSize,Stringname,Integergender){PageHelper.startPage(page,pageSize);List<Emp>empList=empMapper.list(name,gender);Page<Emp>p=(Page<Emp>)empList;returnnewPageBean(p.getTotal(),p.getResult());}}

4. Mapper 层实现

@MapperpublicinterfaceEmpMapper{List<Emp>list(Stringname,Integergender);}

如果使用 XML 写动态 SQL,可以这样写:

<selectid="list"resultType="com.example.pojo.Emp">select id, username, name, gender, phone from emp<where><iftest="name != null and name != ''">name like concat('%', #{name}, '%')</if><iftest="gender != null">and gender = #{gender}</if></where>order by update_time desc</select>

5. 文字说明

@RequestParam主要用来接收普通请求参数。

比如请求地址是:

/emps?page=1&pageSize=10&name=张三&gender=1

那么后端可以接收到:

page=1pageSize=10name="张三"gender=1

这里有一个细节:

@RequestParam(defaultValue="1")Integerpage

表示如果前端没有传page,默认值就是1

@RequestParam(defaultValue="10")IntegerpageSize

表示如果前端没有传pageSize,默认每页查询 10 条。

6. 涉及知识点

1. @RequestParam 默认 required 为 true

如果这样写:

@RequestParamStringname

默认表示name参数必须传。

如果前端没有传,可能会报错。

如果这个参数不是必须的,可以这样写:

@RequestParam(required=false)Stringname

或者直接省略注解:

Stringname

在 Spring Boot 中,简单参数很多时候可以不写@RequestParam,也能正常接收。

2. defaultValue 可以设置默认值

分页查询中经常这样写:

@RequestParam(defaultValue="1")Integerpage,@RequestParam(defaultValue="10")IntegerpageSize

这样前端即使不传分页参数,后端也能有默认值,不容易出现空指针问题。

3. 适合接收简单参数

@RequestParam适合接收:

  • String
  • Integer
  • Long
  • Double
  • Boolean
  • 简单日期参数

比如:

/emps?name=张三 /emps?page=1&pageSize=10 /emps?gender=1

这些都比较适合使用@RequestParam

四、@RequestBody:接收 JSON 请求体

1. 功能需求

如果我们要新增一个员工,前端一般不会把所有字段都拼到 URL 后面,而是通过 JSON 传给后端。

请求方式一般是:

POST /emps

请求体内容类似:

{"username":"zhangsan","name":"张三","gender":1,"phone":"13800000000"}

这种情况下就适合使用@RequestBody

2. Controller 层实现

@RestController@RequestMapping("/emps")publicclassEmpController{@AutowiredprivateEmpServiceempService;@PostMappingpublicResultsave(@RequestBodyEmpemp){empService.save(emp);returnResult.success();}}

3. Service 层实现

publicinterfaceEmpService{voidsave(Empemp);}
@ServicepublicclassEmpServiceImplimplementsEmpService{@AutowiredprivateEmpMapperempMapper;@Overridepublicvoidsave(Empemp){emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());empMapper.insert(emp);}}

4. Mapper 层实现

@MapperpublicinterfaceEmpMapper{@Insert("insert into emp(username, name, gender, phone, create_time, update_time) "+"values(#{username}, #{name}, #{gender}, #{phone}, #{createTime}, #{updateTime})")voidinsert(Empemp);}

5. 文字说明

@RequestBody表示从请求体中获取 JSON 数据,并把 JSON 转换成 Java 对象。

前端传来的 JSON 是:

{"username":"zhangsan","name":"张三","gender":1,"phone":"13800000000"}

后端接收时写:

@RequestBodyEmpemp

Spring Boot 会自动把 JSON 中的字段封装到Emp对象中。

也就是说:

JSON 字段 username -> Emp 对象的 username 属性 JSON 字段 name -> Emp 对象的 name 属性 JSON 字段 gender -> Emp 对象的 gender 属性 JSON 字段 phone -> Emp 对象的 phone 属性

这种方式非常适合新增和修改操作。

6. 涉及知识点

1. 前端需要设置 Content-Type

使用@RequestBody接收 JSON 时,前端请求头一般要设置:

Content-Type: application/json

如果前端传的是表单格式,而后端使用@RequestBody,就可能接收不到数据。

2. JSON 字段名要和 Java 属性名对应

比如 Java 类中属性叫:

privateStringusername;

那么 JSON 中最好也写:

{"username":"zhangsan"}

如果字段名对不上,就可能出现属性为null的情况。

3. @RequestBody 适合复杂对象

比如新增员工、修改员工、提交订单、保存表单等场景,一般都会使用@RequestBody

因为这些数据字段较多,用 JSON 表达更清楚。

五、三个注解的使用场景对比

1. 根据 id 查询

请求路径:

GET /emps/1

后端写法:

@GetMapping("/{id}")publicResultgetById(@PathVariableIntegerid){returnResult.success(empService.getById(id));}

适合使用:

@PathVariable

2. 条件分页查询

请求路径:

GET /emps?page=1&pageSize=10&name=张三&gender=1

后端写法:

@GetMappingpublicResultpage(@RequestParam(defaultValue="1")Integerpage,@RequestParam(defaultValue="10")IntegerpageSize,Stringname,Integergender){returnResult.success(empService.page(page,pageSize,name,gender));}

适合使用:

@RequestParam

3. 新增员工

请求路径:

POST /emps

请求体:

{"username":"zhangsan","name":"张三","gender":1,"phone":"13800000000"}

后端写法:

@PostMappingpublicResultsave(@RequestBodyEmpemp){empService.save(emp);returnResult.success();}

适合使用:

@RequestBody

六、最容易混淆的地方

1. @RequestParam 和 @PathVariable 的区别

看参数在什么位置。

如果参数在问号后面:

/emps?id=1

一般使用:

@RequestParamIntegerid

如果参数在路径中:

/emps/1

一般使用:

@PathVariableIntegerid

2. @RequestParam 和 @RequestBody 的区别

看前端传的是普通参数还是 JSON。

如果是这样:

/emps?name=张三&gender=1

使用:

@RequestParam

如果是这样:

{"name":"张三","gender":1}

使用:

@RequestBody

3. GET 请求一般不使用 @RequestBody

虽然有些情况下 GET 请求也能带请求体,但是在实际项目中不推荐这样做。

一般约定是:

GET 查询数据 POST 新增数据 PUT 修改数据 DELETE 删除数据

所以查询参数通常放在 URL 中,新增和修改数据通常放在请求体中。

七、常见报错和解决方式

1. Required request parameter is not present

这个错误通常是因为使用了:

@RequestParamStringname

但是前端没有传name参数。

解决方式:

@RequestParam(required=false)Stringname

或者设置默认值:

@RequestParam(defaultValue="")Stringname

2. JSON 数据接收后属性都是 null

常见原因有两个。

第一个原因是前端没有设置:

Content-Type: application/json

第二个原因是 JSON 字段名和 Java 对象属性名不一致。

比如 Java 属性是:

privateStringusername;

但是前端传的是:

{"user_name":"zhangsan"}

这样就可能无法自动封装。

3. PathVariable 接收不到参数

如果路径中变量名和方法参数名不一致,需要手动指定:

@GetMapping("/{empId}")publicResultgetById(@PathVariable("empId")Integerid){returnResult.success(empService.getById(id));}

八、实际开发中的使用建议

在项目中可以按照下面的习惯来选择:

场景推荐写法
根据 id 查询@PathVariable
根据 id 删除@PathVariable
条件查询@RequestParam
分页查询@RequestParam
新增对象@RequestBody
修改对象@RequestBody
批量删除 id 数组@RequestParam@RequestBody,看前端传参方式

简单记忆:

路径中的参数用@PathVariable,问号后面的参数用@RequestParam,JSON 请求体用@RequestBody

九、总结

这一篇主要学习了 Spring Boot 中 Controller 接收参数的三种常见方式。

@PathVariable主要用来接收路径参数,适合根据 id 查询、根据 id 删除这类接口。

@RequestParam主要用来接收 URL 问号后面的普通参数,适合条件查询、分页查询。

@RequestBody主要用来接收请求体中的 JSON 数据,适合新增和修改复杂对象。

这三个注解在项目开发中非常常见,尤其是写增删改查接口时基本都会用到。只要能判断清楚“参数在哪里”,基本就能选对注解。

下一篇我们可以继续学习项目中很常见的统一返回结果类,也就是Result类应该怎么设计,以及为什么不建议接口直接返回普通字符串或实体对象。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/21 18:25:15

从原理图到数据:手把手教你用STM32同时读取多个DS18B20的温度

STM32多节点温度监测系统实战&#xff1a;基于DS18B20的分布式架构设计在工业控制、农业温室、机房监控等场景中&#xff0c;多点温度监测是基础却关键的需求。传统方案往往需要为每个测温点单独布线&#xff0c;不仅增加硬件复杂度&#xff0c;也提高了系统维护成本。而采用单…

作者头像 李华
网站建设 2026/6/9 3:36:49

Hadoop YARN Web UI保姆级解读:从8088页面看懂你的集群在忙啥

Hadoop YARN Web UI深度解析&#xff1a;从8088页面洞悉集群运行状态 引言&#xff1a;为什么你需要读懂YARN Web UI&#xff1f; 当你第一次打开Hadoop YARN的Web UI界面&#xff08;默认端口8088&#xff09;&#xff0c;可能会被各种指标和数据搞得眼花缭乱。这就像走进飞机…

作者头像 李华
网站建设 2026/6/9 3:35:35

保姆级教程:在GD32F405RGT6上实现SPI双机互传(主从一体代码详解)

GD32F405RGT6 SPI双机通信实战&#xff1a;主从一体设计与冲突规避指南两块开发板通过SPI总线互相传递温度传感器数据和电机控制指令&#xff0c;这种场景在工业控制领域随处可见。但当你真正动手实现时&#xff0c;会发现从机如何主动发起通信、主从切换时的总线竞争等问题远比…

作者头像 李华
网站建设 2026/6/11 15:18:51

别再只会用PMOS了!聊聊NMOS做高边开关的几种‘野路子’与‘正经方案’

NMOS高边开关设计&#xff1a;从电荷泵到工业级解决方案的全面指南在功率电子设计领域&#xff0c;NMOS管作为高边开关的应用一直是个充满挑战又极具实用价值的话题。传统教科书告诉我们PMOS适合上管驱动而NMOS适合下管驱动&#xff0c;但现实工程中往往面临元器件库存、成本控…

作者头像 李华
网站建设 2026/6/9 3:30:27

图片去水印用什么工具?2026免费图片去水印工具推荐

日常刷小红书、抖音、B站&#xff0c;看到心动的图片想存下来当壁纸或灵感素材&#xff0c;结果角落一个大大的水印&#xff0c;瞬间兴趣全无。自己用修图软件一点点抹掉&#xff0c;又费时又费力&#xff0c;还容易留下明显的涂抹痕迹。 这篇文章完全从个人收藏与学习的角度出…

作者头像 李华