当前位置: 首页 > news >正文

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

http://www.jsqmd.com/news/1054587/

相关文章:

  • 教程指南|如何用 SendToMo 在电脑和手机之间传输大文件?
  • Java性能测试工具选型与实战:从JMeter到Gatling的深度解析
  • Claude本地化集成指南:API调用、安全配置与三大实用方案
  • DSP56852 AGC库构建与集成实战:从源码编译到嵌入式应用
  • AMD Ryzen调试工具完全指南:SMUDebugTool免费开源超频神器
  • 用 Hugging Face 解决机器翻译的正确姿势
  • 题解:AtCoder AT_awc0062_d Nearly Identical Signal Patterns
  • Mate Engine:打造你的专属免费虚拟桌面伙伴
  • 2026 年 6 月欧米茄官方售后门店资质实地查验报告 覆盖全国 60 + 正规服务点 - 欧米茄中国服务中心
  • Selenium自动化测试:彻底解决Chrome与Chromedriver环境配置难题
  • 2026合肥本土靠谱GEO优化服务商实测:合肥智拓GEO实力深度解析 - 行业深度观察C
  • 基于NXP MC56F83xxx DSC的PMSM无感FOC驱动开发实战
  • zteOnu深度解析:中兴光猫工厂模式认证与Telnet权限获取技术实现
  • 抖音批量下载工具:5分钟掌握免费批量下载技巧
  • Gemini 3.1 Pro延迟根因与DMXAPI全链路优化实战
  • LLM结构化经验表示Gene:从测试控制到自我进化的工程实践
  • WorkshopDL:跨平台Steam创意工坊模组下载完整指南
  • 考研英语阅读题源报刊|考研英语题源阅读|考研英语新题型题库
  • Claude代码路由机制:轻量Shell脚本实现本地安全调用
  • 2026年6月卡地亚官方腕表维修服务网络完成升级,多地标准化售后服务中心营业地址对外开放 - 卡地亚中国服务中心
  • 基于OWASP MASTG的移动应用安全测试报告撰写终极指南
  • 题解:AtCoder AT_awc0045_d Cell Division
  • 图神经网络在粒子加速器状态监测中的应用与优化
  • 3个核心优势:开源虚拟桌面伴侣Mate Engine的终极解决方案
  • [智能体-491]:第二增长曲线:贯穿企业、技术、个体、文明、物种的通用演化规律
  • 微信聊天记录永久保存终极指南:免费开源工具WeChatExporter详解
  • 2026合肥公办民办卫校实力排名、学费升学完整汇总一览! - 我叫小周
  • DSP56800E嵌入式开发:内联汇编与Intrinsic函数性能优化实战
  • TranslucentTB完整解决方案:Windows任务栏透明化终极指南
  • DSP56800到DSP56800E代码迁移:兼容性解析与性能优化实战