news 2026/6/21 11:40:12

SpringBoot 接口传参:RequestParam、RequestBody、PathVariable 怎么选

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot 接口传参:RequestParam、RequestBody、PathVariable 怎么选

SpringBoot 接口传参:RequestParam、RequestBody、PathVariable 怎么选

目录

  • 一、@RequestParam:从 URL 查询参数中取值
  • 二、@PathVariable:从 URL 路径中取值
  • 三、@RequestBody:从请求体中取值
  • 三种注解对比
  • 什么时候用哪个:按 HTTP 语义来选
  • 使用时注意事项
  • 小结

我们在学习后端开发的时候,都在相应教学内容上看到过这三个注解。教程里直接给使用方式,但却没有详细说什么时候该用哪个。等到真正写项目接口的时候,就会开始纠结:分页参数用@RequestParam,那查详情的 ID 放在路径里用@PathVariable还是也用@RequestParam?提交表单十几个字段,是全用@RequestParam一个个接,还是塞进一个对象用@RequestBody

三种注解都能拿到前端传来的数据,但它们的数据来源、适用场景、HTTP 语义完全不同。搞混了代码能跑,但接口设计会很别扭。我们一个一个来看一下使用场景。

一、@RequestParam:从 URL 查询参数中取值

@RequestParam对应的是 URL 中?后面的查询参数(Query String)。

@GetMapping("/users")publicList<User>listUsers(@RequestParam(defaultValue="1")intpage,@RequestParam(defaultValue="10")intsize){returnuserService.listUsers(page,size);}

前端请求:GET /users?page=1&size=10

Spring 看到@RequestParam,就知道去 URL 的查询参数里找pagesize这两个 key,取出来转成int,注入到方法参数里。defaultValue是个保底:如果前端没传这个参数,就用默认值,不会报错。

适用场景

筛选、排序、分页这种可选的查询条件。@RequestParam最合适。参数是 URL 的一部分,浏览器地址栏能直接看到,方便调试和分享链接。

@GetMapping("/products")publicList<Product>search(@RequestParam(required=false)Stringkeyword,@RequestParam(required=false)Stringcategory,@RequestParam(defaultValue="price")StringsortBy){returnproductService.search(keyword,category,sortBy);}

请求:GET /products?keyword=手机&category=electronics&sortBy=price

注意required = false:这个参数是可选的,不传也不会报 400。如果你确定某个参数必须传(比如分页的页码),可以用required = true(默认值),前端不传就直接返回 400 错误。

多个值的情况

一个参数还能接收多个值,前端用同一个 key 传多次:

@GetMapping("/users/batch")publicList<User>getByIds(@RequestParamList<Long>ids){returnuserService.getByIds(ids);}

请求:GET /users/batch?ids=1,2,3GET /users/batch?ids=1&ids=2&ids=3

Spring 会自动把多个值收集到List里。

二、@PathVariable:从 URL 路径中取值

@PathVariable对应的是 URL 路径中用{xxx}占位的部分。

@GetMapping("/users/{id}")publicUsergetUser(@PathVariableLongid){returnuserService.getUserById(id);}

前端请求:GET /users/42

{id}是一个路径变量,@PathVariable告诉 Spring:去 URL 路径里把{id}位置的值取出来,转成Long,赋给id参数。

适用场景

标识具体资源的场景。RESTful 风格的 API 设计中,用路径来表达"操作的是哪个资源"。

GET /users/42 → 查看用户 42 PUT /users/42 → 更新用户 42 DELETE /users/42 → 删除用户 42 GET /orders/1001/items → 查看订单 1001 的商品列表

路径中的421001就是资源标识,用@PathVariable接收。这种设计比GET /users?id=42更符合 REST 语义,URL 也更简洁直观。

多个路径变量

一个 URL 里可以有多个占位符:

@GetMapping("/departments/{deptId}/employees/{empId}")publicEmployeegetEmployee(@PathVariableLongdeptId,@PathVariableLongempId){returnemployeeService.get(deptId,empId);}

请求:GET /departments/5/employees/128

两个占位符对应两个@PathVariable,Spring 会按名称匹配。

三、@RequestBody:从请求体中取值

@RequestBody对应的是 HTTP 请求的 Body 部分。当前端发送 JSON 格式的数据时,Spring 会用HttpMessageConverter(默认是 Jackson)把 JSON 反序列化成 Java 对象。

@PostMapping("/users")publicUsercreateUser(@RequestBodyUserCreateRequestrequest){returnuserService.createUser(request);}
// 请求体对应的 DTOpublicclassUserCreateRequest{privateStringname;privateStringemail;privateIntegerage;// getter/setter}

前端请求:

POST /users Content-Type: application/json { "name": "张三", "email": "zhangsan@example.com", "age": 25 }

Spring 看到@RequestBody,就知道把整个请求体读出来,用 Jackson 解析成UserCreateRequest对象。字段名要和 JSON 的 key 对应,类型要能转换,否则直接报 400。

适用场景

提交复杂表单数据、创建或更新资源。当参数多、结构复杂、或者包含嵌套对象时,@RequestBody是最佳选择。

// 嵌套对象的场景publicclassOrderCreateRequest{privateLonguserId;privateList<OrderItem>items;privateAddressshippingAddress;privateStringpaymentMethod;}publicclassOrderItem{privateLongproductId;privateIntegerquantity;}publicclassAddress{privateStringprovince;privateStringcity;privateStringdetail;}

这种嵌套结构,用@RequestParam一个个接几乎不可能,用@RequestBody一行搞定。

三种注解对比

对比维度@RequestParam@PathVariable@RequestBody
数据来源URL 查询参数?key=valueURL 路径/users/{id}HTTP 请求体 Body
Content-Type无要求无要求通常application/json
参数数量适合少量可选参数适合 1-2 个资源标识适合复杂/大量参数
HTTP 方法任意任意通常 POST/PUT
典型场景分页、筛选、排序资源标识、RESTful 路径创建、更新、复杂提交
浏览器可见性地址栏可见地址栏可见不可见(在请求体里)

一句话总结:@RequestParam管查询条件,@PathVariable管资源标识,@RequestBody管请求体。

什么时候用哪个:按 HTTP 语义来选

与其记住注解的语法,不如理解 HTTP 本身的语义。每个 HTTP 方法有它自己的含义,参数怎么传跟着语义走就行了。

GET 请求:筛选和查询

GET 用来获取资源。参数通常是可选的筛选条件,放在 URL 查询参数里:

@GetMapping("/articles")publicList<Article>search(@RequestParam(required=false)Stringkeyword,@RequestParam(defaultValue="1")intpage,@RequestParam(defaultValue="20")intsize){returnarticleService.search(keyword,page,size);}

如果要查某个具体资源,用路径标识:

@GetMapping("/articles/{id}")publicArticlegetDetail(@PathVariableLongid){returnarticleService.getById(id);}

GET 请求没有请求体,所以@RequestBody在 GET 中没有意义。虽然 HTTP 规范没有明确禁止 GET 带 Body,但大多数 HTTP 客户端和代理服务器会忽略 GET 的 Body,Spring 默认也不支持。如果你发现自己想在 GET 里用@RequestBody,大概率是接口设计有问题,应该改成 POST。

POST 请求:创建资源

POST 用来提交数据、创建资源。数据通常比较复杂,放在请求体里:

@PostMapping("/articles")publicArticlecreate(@RequestBody@ValidArticleCreateRequestrequest){returnarticleService.create(request);}

PUT 请求:更新资源

PUT 用来更新资源。被更新的资源用路径标识,更新的内容放请求体:

@PutMapping("/articles/{id}")publicArticleupdate(@PathVariableLongid,@RequestBodyArticleUpdateRequestrequest){returnarticleService.update(id,request);}

这里@PathVariable@RequestBody同时出现——一个管"更新谁",一个管"更新成什么",职责非常清晰。

DELETE 请求:删除资源

DELETE 用来删除资源,被删除的对象用路径标识:

@DeleteMapping("/articles/{id}")publicvoiddelete(@PathVariableLongid){articleService.delete(id);}

把上面的规律总结成一张表:

HTTP 方法资源标识请求数据典型注解组合
GET@PathVariable@RequestParam查询列表 / 查看详情
POST@RequestBody创建资源
PUT@PathVariable@RequestBody更新资源
DELETE@PathVariable删除资源

使用时注意事项

@RequestBody 不能和 @RequestParam 混用在同一参数上

有些新手会写出这种代码:

// 错误写法@PostMapping("/users")publicUsercreate(@RequestBody@RequestParamUserDTOdto){...}

这两个注解的数据来源是矛盾的:@RequestBody从请求体取,@RequestParam从查询参数取。一个参数不可能同时从两个地方取值。Spring 会直接报错。

正确的做法是分清楚:哪些参数从查询参数来,哪些从请求体来:

@PostMapping("/users")publicUsercreate(@RequestParam(defaultValue="false")Booleannotify,// 查询参数@RequestBodyUserDTOdto){// 请求体returnuserService.create(dto,notify);}

@PathVariable 的变量名要和路径占位符一致

// 如果占位符叫 {userId},参数名也得叫 userId@GetMapping("/users/{userId}")publicUsergetUser(@PathVariableLonguserId){...}

@RequestBody 的校验

@RequestBody接收的对象通常需要校验。配合@Valid注解和 JSR-303 校验注解一起用:

publicclassUserCreateRequest{@NotBlank(message="用户名不能为空")privateStringname;@Email(message="邮箱格式不正确")privateStringemail;@Min(value=0,message="年龄不能为负数")privateIntegerage;}@PostMapping("/users")publicUsercreate(@RequestBody@ValidUserCreateRequestrequest){returnuserService.create(request);}

不加@Valid,校验注解不会生效,前端传什么数据都能进来。

接收数组或列表

@RequestBody可以直接接收 JSON 数组:

@PostMapping("/users/batch")publicList<User>batchCreate(@RequestBodyList<UserCreateRequest>requests){returnuserService.batchCreate(requests);}

前端传一个 JSON 数组就行:

[{"name":"张三","email":"zhangsan@example.com"},{"name":"李四","email":"lisi@example.com"}]

小结

三种注解的本质区别在于数据来源不同@RequestParam从 URL 查询参数取,@PathVariable从 URL 路径取,@RequestBody从请求体取。不用死记语法,只需要跟着 HTTP 语义走:GET 查询用@RequestParam,资源标识用@PathVariable,复杂数据提交用@RequestBody

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

DSP56800到DSP56800E代码迁移:兼容性解析与性能优化实战

1. 项目概述&#xff1a;从DSP56800到DSP56800E的代码迁移实战 在嵌入式DSP开发领域&#xff0c;处理器的迭代升级是家常便饭&#xff0c;但随之而来的代码移植工作却往往让工程师们头疼不已。最近&#xff0c;我接手了一个将现有代码库从经典的DSP56800平台迁移到其增强版DSP5…

作者头像 李华
网站建设 2026/6/21 11:27:47

终极B站会员购抢票指南:3步轻松搞定限量商品

终极B站会员购抢票指南&#xff1a;3步轻松搞定限量商品 【免费下载链接】biliTickerBuy b站会员购购票辅助工具 项目地址: https://gitcode.com/GitHub_Trending/bi/biliTickerBuy 你是否曾在B站会员购抢购热门演唱会门票、限量手办或漫展通行证时&#xff0c;因为手速…

作者头像 李华
网站建设 2026/6/21 11:24:23

LaTeX2Word-Equation:3分钟掌握学术写作公式转换的终极指南

LaTeX2Word-Equation&#xff1a;3分钟掌握学术写作公式转换的终极指南 【免费下载链接】LaTeX2Word-Equation Copy LaTeX Equations as Word Equations, a Chrome Extension 项目地址: https://gitcode.com/gh_mirrors/la/LaTeX2Word-Equation 你是否曾经为了将网页上的…

作者头像 李华
网站建设 2026/6/21 11:19:54

终极NBT编辑器NBTExplorer:5步掌握我的世界数据编辑全流程

终极NBT编辑器NBTExplorer&#xff1a;5步掌握我的世界数据编辑全流程 【免费下载链接】NBTExplorer A graphical NBT editor for all Minecraft NBT data sources 项目地址: https://gitcode.com/gh_mirrors/nb/NBTExplorer NBTExplorer是一款专为《我的世界》玩家设计…

作者头像 李华
网站建设 2026/6/21 11:19:43

OpenCode + Ollama:本地化AI编程协作者实战指南

1. OpenCode 是什么&#xff1f;它和 Ollama 的关系到底有多紧密OpenCode 这个名字最近在开发者圈子里突然火了&#xff0c;但很多人点开 GitHub 仓库、翻完文档、甚至装完软件后&#xff0c;第一反应是&#xff1a;“这玩意儿怎么连个模型都没有&#xff1f;”——不是它没模型…

作者头像 李华