@RequestParam,@RequestBody,@PathVariable注解还分不清吗?

前言

在使用 SpringMVC 开发时,经常遇到前端传递的各种参数,比如 form 表单,JSON 数据,String[] 数组,再或者是最常见的 String 字符串等等,总之大部分场景都是在标题这三个注解来回切换,所以搞清楚这三个注解,日常开发就可以横着走了。

正文

@RequestParam 和 @RequestBody 都是从 HttpServletRequest request 中取参的,而 @PathVariable 是映射 URI 请求参数中的占位符到目标方法的参数中的,接下来一一举例说明。

希望大家能了解:前端在不明确指出 Content-Type 时,默认为 application/x-www-form-urlencoded 格式,@RequestParam 可以获取 application/x-www-form-urlencoded 以及 application/json 这两种类型的参数,但是 @RequestBody 是用来获取非 application/x-www-form-urlencoded 类型的数据,比如 application/jsonapplication/xml 等。

1、@RequestParam

请求链接举例(GET/POST):?param1=xxx&param2=yyy

http://javam4.com/m4detail?id=111&tag=java

后端接收举例:

@RequestMapping(value = "/m4detail", method = {RequestMethod.GET,RequestMethod.POST})
public void m4detail(@RequestParam(value="id", required=true) String isId, @RequestParam String tag) {System.out.println("isId="+isId);System.out.println("tag="+tag);}

首先这种方式无论是 GET 还是 POST 请求,都是可以获取到参数的,举例中特意使用了 @RequestParam 注解的一些参数,具体参数如下:

  • defaultValue 如果本次请求没有携带这个参数,或者参数为空,那么就会启用默认值
  • name 绑定本次参数的名称,要跟URL上面的一样
  • required 这个参数不是必须的,如果为 true,不传参数会报错
  • value 跟name一样的作用,是name属性的一个别名

2、@PathVariable

请求链接举例(GET/POST):/{id}

http://javam4.com/m4detail/111?tag=java

后端接收举例:

@RequestMapping(value = "/m4detail/{id}", method = {RequestMethod.GET,RequestMethod.POST})
public void m4detail(@PathVariable String id, @RequestParam String tag) {System.out.println("id="+id);System.out.println("tag="+tag);
}

然后有的小伙伴可能会问,你这就接收了一个 {id},那我能接受 2 个参数吗?能。

一个 {xx} 就能对应一个参数,那你的请求链接假如是这样:

http://javam4.com/m4detail/111/java

后端接收方式:

@RequestMapping(value = "/m4detail/{id}/{tag}", method = {RequestMethod.GET,RequestMethod.POST})
public void m4detail(@PathVariable String id, @PathVariable String tag) {System.out.println("id="+id);System.out.println("tag="+tag);
}

同样 @PathVariable 也有相应的参数:

  • name 绑定参数的名称,默认不传递时,绑定为同名的形参。 赋值但名称不一致时则报错
  • value 跟name一样的作用,是name属性的一个别名
  • required 这个参数不是必须的,如果为 true,不传参数会报错

总结,使用 @PathVariable 需要注意两点:

  • 参数接收类型使用基本类型
  • 如果@PathVariable标明参数名称,则参数名称必须和URL中参数名称一致

3、@ReuqestBody(不能用于GET请求)

通常后端与前端的交互大多情况下是 POST 请求,尤其是传递大量参数时,毕竟大量参数暴露在浏览的地址栏还是不怎么优雅的,而在 POST 请求中应用 JSON 串对于 Spring MVC 来说是比较友好的,后端使用 @RequestBody 注解就可以方便的实现 JSON 串到接收参数的数据映射。

说明一下 @RequestBody 为什么不能用用于 GET 请求,RequestBody 顾名思义,是将请求参数设置在请求 Body 中的,也就是请求体,而 GET 请求无请求体。

使用 @RequestBody 需要满足如下条件:

  • Content-Type 为 application/json,确保传递是 JSON 数据;
  • 参数转化的配置必须统一,否则无法接收数据,比如 json、request 混用等

传递参数举例:(JSON数据)

{"aaa": {"id": "759791ec-0175-ff808081","title": "我是标题","content": "我是内容"},"bbb": ["123456"],"ccc": 10
}

后端想要接收这个 JSON 数据有两种方式选择,一种是建立与 JSON 数据与之对应的实体,二是直接使用 Map<String,Object> 对象接收。

因为 SpringMVC 会帮我们把符合要求的参数封装进实体对象中,所以在参数比较多的情况下,直接使用对象方式会比较方便。

后端接收举例:(实体举例)

@PostMapping("/save")
public void save(@RequestBody QuestionVo vo) {System.out.println(vo.getAaa().getId());
}

QuestionVo.java 实体:

public class QuestionVo {private Question aaa;private List<String> bbb;private List<String> ccc;省略get\set方法...
}
public class Question {private String id;private String title;private String content;省略get\set方法...
}

在这给大家说一下 @RequestBody 在一个请求中只能用一次,如下是报错的:

@PostMapping("/save")
public void save(@RequestBody QuestionVo vo, @RequestBody String niceyoo) {System.out.println(vo.getAaa().getId());
}

报错信息:

I/O error while reading input message; nested exception is java.io.IOException: Stream closed

但是 @RequestParam 是支持多个使用的。

总结(一定要看)

1、在 GET 请求中可以使用 @RequestParam,不能使用 @RequestBody,@RequestBody 是用来获取请求体中的参数,因为 GET 请求没有请求体,所以不能使用。

2、在 POST 请求中,可以使用 @RequestBody 和 @RequestParam ,其中 @RequestParam 是用来获取 application/x-www-form-urlencodedform-data 格式数据的,@RequestBody 用来获取非 application/x-www-form-urlencoded 数据的,比如 application/jsonapplication/xml 等。

3、一个方法中,可以同时使用多个 @RequestParam ,但是只能使用一个 @RequestBody,否则会报错。

4、@PathVariable 起到的作用就是 URI 请求参数中的占位符到目标方法参数的映射。

5、前端请求的 Content-Type ,默认值为 application/x-www-form-urlencoded 格式,在这种格式下,后端直接使用 @RequestParam 就可以直接获取指定的参数,但是一旦前端传递的是 JSON 数据,也就是 Content-Type 的值为 application/json,那么使用 @RequestParam 是取不到值的,不但取不到值还报错。

JSON 数据如下:

{"name": "哈哈哈哈"
}

后端接收错误演示:

@PostMapping("/save")
public void save(@RequestParam String name) {System.out.println(name);
}

报错内容:

Required String parameter 'name' is not present

然后小伙伴就会问,那么使用 @RequestBody 可以直接映射 name 值 ‘哈哈哈哈’ 吗?

答案也是否定的,举例如下:

@PostMapping("/save")
public void save(@RequestBody String name) {System.out.println(name);
}

打印内容如下:

{"name": "哈哈哈哈"
}

这样其实是将 String name 当做一个对象,Spirng MVC 直接将值映射到 name 上,所以拿到的值是整个 JSON 数据的全部,而创建实体或者是使用 Map 接收就不会出问题,但显然就这 name 一个字段,创建一个实体对象实属浪费,直接用 Map<String,Object> / Map<String,String> 接收就可以了:

@PostMapping("/save")
public void save(@RequestBody Map<String,String> map) {System.out.println(map.get("name"));
}

希望这篇文章对你有所帮助。博客园持续更新,欢迎关注。

博客园:https://www.cnblogs.com/niceyoo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/413895.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android | Sqlite3

Android 数据库创建及使用: 创建: package he3.sd.dao;import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log;/*** Created by asd25 on 2018/6/11 0011.*/public clas…

[js] flash如何与js交互?

[js] flash如何与js交互&#xff1f; 当Flash置于HTML容器中时&#xff0c;经常会遇到AS与JS的通信问题&#xff0c;例如&#xff1a;JS能否调用AS中的变量、方法&#xff0c;AS能否调用JS中的变量、方法等等。答案是肯定的。随着技术的不断发展&#xff0c;解决方案也是多种多…

PHP文件下载

步骤 //流的方式发送给浏览器 header("Content-Type: application/octet-stream"); //按照字节的返回给浏览器 header("Accept-Ranges: bytes"); //告诉浏览器文件的大小 header("Accept-Length: ".filesize(文件地址)); //以附件的形式发送给浏…

面试官:了解二叉树吗,平衡二叉树,红黑树?

前言 面试过程中&#xff0c;多多少少会问一点数据结构&#xff08;二叉树&#xff09;的问题&#xff0c;今天我们来复习一下二叉树的相关问题&#xff0c;文末总结。 1. 二叉树的由来 在 jdk1.8 之前&#xff0c;HashMap 的数据结构由「数组链表」组成&#xff0c;数组是 …

[js] 说说你对js对象生命周期的理解

[js] 说说你对js对象生命周期的理解 一切皆对象 咱们经常听到JS中“一切皆对象”&#xff1f;有没有问想过这是什么意思&#xff1f;其它语言也有“一切皆对象”之说&#xff0c;如Python。但是Python中的对象不仅仅是像JS对象这样的存放值和值的容器。Python中的对象是一个类…

(理论)数据库建模三步骤:概念模型-逻辑模型-物理模型

概念模型就是在了解了用户的需求&#xff0c;用户的业务领域工作情况以后&#xff0c;经过分析和总结&#xff0c;提炼出来的用以描述用户业务需求的一些概念的东西。如销售业务中的“客户”和“定单”&#xff0c;还有就是“商品”&#xff0c;“业务员”。 用USE CASE来描述…

java.util.UnknownFormatConversionException: Conversion = ‘j‘ || Conversion = ‘D‘ || Conversion = ‘Y‘

执行内容&#xff1a; String a "select * from j_question j where j.status %s and j.title like %java%"; String format String.format(a, 1); System.out.println(format);拼接SQL时&#xff0c;最后需要 format 替换字符串中的 %s 占位符。 预期效果&…

[js] 在DOM上同时绑定两个点击事件(一个用捕获,一个用冒泡),事件总共会执行几次,先执行哪个事件?

[js] 在DOM上同时绑定两个点击事件&#xff08;一个用捕获&#xff0c;一个用冒泡&#xff09;&#xff0c;事件总共会执行几次&#xff0c;先执行哪个事件&#xff1f; 两次 先捕获&#xff0c;后冒泡个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易…

Jenkins: QQ/Wechat机器人群消息通知Job构建结果

简介 Jenkins是持续化集成的一个核心部件&#xff0c;它上游从仓库&#xff08;gitlab&#xff09;等拉取代码&#xff0c;经编译构建&#xff0c;将应用发布至下游目标环境&#xff1b;构建结果通知的方式有很多&#xff0c;现成的插件有邮件和钉钉方式&#xff0c;但是就方便…

[js] json和对象有什么区别?

[js] json和对象有什么区别&#xff1f; JSON 是对象&#xff0c;但对象不一定是 JSON。对象是由属性和属性值组成&#xff0c;也就是 KEY->VALUE 对。 对象中的 value 可以是任意的数据类型&#xff0c;包括函数。而 JSON 中的 value 不能为函数。个人简介 我是歌谣&…

Java中的Set对象去重

前言部分 Set<T> 去重相信大家一定不陌生&#xff0c;尤其是在 Set<String>、Set<Integer> 等等&#xff0c;但是在使用 Set<实体> &#xff0c;在不重写 equals()、hashCode() 方法情况下&#xff0c;直接使用貌似并不能生效。 所以想要 Set<实体…

openfalcon架构及相关服务配置详解

一&#xff1a;openfalcon组件 1.falcon-agent 数据采集组件 agent内置了一个http接口&#xff0c;会自动采集预先定义的各种采集项&#xff0c;每隔60秒&#xff0c;push到transfer。 2.transfer agent与transfer建立长连接&#xff0c;将数据汇报给tarnsfer transfer默认监听…

DBeaver连接达梦|虚谷|人大金仓等国产数据库

前言 工作中有些项目可能会接触到「达梦、虚谷、人大金仓」等国产数据库&#xff0c;但通常这些数据库自带的连接工具使用并不方便&#xff0c;所以这篇文章记录一下 DBeaver 连接国产数据库的通用模版&#xff0c;下文以达梦为例&#xff08;其他国产数据库连接操作方式一样&…

[js] script所在的位置会影响首屏显示时间吗

[js] script所在的位置会影响首屏显示时间吗 会&#xff0c;如果script放在头部&#xff0c;js的执行会阻塞dom树的构建个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面…

luogu4462 异或序列

题目大意 给出n,m,k&#xff0c;有n个数的序列&#xff0c;m次询问一段区间&#xff0c;问异或和等于K的子区间的个数。 题解 本题一看就是莫队。但要解决该题需要以下性质&#xff1a; 定理&#xff1a; $$a\oplus bc\Leftrightarrow a\oplus cb\Leftrightarrow b\oplus ca$$ …

Map<String,Object>接收参数,Long类型降级为Integer,报类型转换异常

前言 今天看群里小伙伴问了一个非常有意思的问题&#xff1a; 使用 Map<String,Object> 对象接收前端传递的参数&#xff0c;在后端取参时&#xff0c;因为接口文档中明确该字段类型为 Long &#xff0c;所以对接收的参数进行了强转&#xff0c;即 (Long)参数 &#xf…

adb无法连接安卓手机

确保已安装好手机驱动&#xff08;在设备管理器中能找到安卓的设备&#xff09;查看设备的VID信息找到你的模拟器存放的目录&#xff0c;<例如&#xff1a;C:\Users\Administrator\.android 下找到或新建一个adb_usb.ini文件。文档内容写入VID即可 在cmd上输入adb kill-serv…

那些对你说学历不重要,技术重要的人,他们大部分都是有学历的。

随便唠叨几句 最近有挺多小伙伴在微信上私信我&#xff0c;咨询提升学历问题的&#xff0c;希望我能给点意见&#xff0c;当然&#xff0c;这里面大部分是涉及到专升本&#xff0c;因为自己是过来人&#xff0c;所以感触比较深&#xff0c;耐心的给予了回复&#xff0c;整理后…

前端学习(2856):简单秒杀系统学习之定时器循环显示

<html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title>javascrip</title></head><body ><script>function show() {console.log(每过1秒展示);}function show2(str) {…

SpringBoot中的Tomcat是如何启动的

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency>添加如上 Web 的依赖&#xff0c;Spring Boot 就帮我们内置了 Servlet 容器&#xff0c;默认使用的是 Tomcat&a…