requestbody注解,@RequestParam、@PathVariable、@RequestBody和@Param
requestbody注解,@RequestParam、@PathVariable、@RequestBody和@Param详细介绍
本文目录一览: @RequestBody注解原理
从源码中可以看到,@RequestBody 用在方法参数上面,用来将请求参数绑定到request body中,通过 HttpMessageConverter 封装为具体的JavaBean。通俗点讲就是你在一个参数上加上该注解,spring就会将request body中的json/xml对象解析成该参数类型的Javabean对象。 作为RESTful开发中经常用到的注解,研究其原理有利于我们更好地理解并掌握它。 那么spring是如何做到这一点的呢?先来看DispatcherServlet。 作为springMVC处理请求的中央调度器,DispatcherServlet本身是一个servlet,所以我们看doService():
重点在doDispatch()方法,该方法先找到会找到合适的handler来处理当前请求:
HandlerAdapter是一个接口,具体处理方法在 RequestMappingHandlerAdapter 类中:
这里又调用了handleInternal()方法,RequestMappingHandlerAdapter重写了该方法: 进入该方法,
可以看到最终调用的都是invokeHandlerMethod()方法,此方法会处理@RequestMapping修饰的请求
进入该方法的 invocableMethod.invokeAndHandle(webRequest, mavContainer); ,来到ServletInvocableHandlerMethod,此类继承了InvocableHandlerMethod,可以处理请求的返回值。invokeAndHandle()方法:
重点在 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); ,通过请求调用并产生返回值。
getMethodArgumentValues() 方法的作用是获取方法参数,重点就在这里,
进入resolveArgument()方法,
@RequestBody修饰的参数会使用RequestResponseBodyMethodProcessor解析,
进入readWithMessageConverters()方法一路顺藤摸瓜,来到AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters(),
可以看到使用文章开头提到的HttpMessageConverter解析参数并返回,而此处的HttpMessageConverter是在RequestMappingHandlerAdapter中设置解析器的时候添加到每个解析器中的。而json格式的数据使用AbstractJackson2HttpMessageConverter进行解析,内部使用jackson进行json数据的解析。
请求由DispatcherServlet处理,找到相应的HandlerAdapter进行处理,RequestMappingHandlerAdapter会处理@RequestMapping注解的请求,设置一系列参数解析器进行解析,如果参数使用@RequestBody注解,则使用RequestResponseBodyMethodProcessor进行解析,此参数解析器用HttpMessageConverter将HttpMessage封装为具体的JavaBean对象,json格式的数据使用AbstractJackson2HttpMessageConverter进行解析,内部使用jackson进行json数据的解析。
使用Spring的@RequestBody注解,无法映射首字母大写属性的踩坑记录
使用@RequestBody注解,进行json反序列化映射的时候,若实体类属性为首字母大写,将无法映射成功。
Spring的@RequestBody注解,进行参数映射时使用的是set方法,若有两个参数,以java命名规范命名应为name与sex,但若命名为Name、Sex,虽然生成的set方法依然是setName()、setSex(),但Spring框架缺没办法区分属性是name还是Name,按照命名规则来会给name赋值,产生错误。
属性加上@JsonProperty("XXX")注解来指定映射的参数名
controller层如何接受集合
在controller层中,可以使用@RequestParam注解来接受集合参数。具体步骤如下:
1. 在controller方法的参数列表中,使用@RequestParam注解来声明集合参数,如下所示:
```
@RequestMapping("/users")
public String getUsers(@RequestParam List
userIds) {
// 方法体
}
```
2. 在客户端发起请求时,将集合参数以逗号分隔的形式拼接在URL上,如下所示:
```
http://localhost:8080/users?userIds=1,2,3
```
3. 在方法体中,即可使用集合参数进行业务处理。
需要注意的是,如果集合参数的元素类型为复杂类型,可以使用@RequestParam注解的value属性来指定参数名称,并使用JSON格式进行传输。具体示例如下:
```
@RequestMapping("/users")
public String getUsers(@RequestParam(value = "userIds", required = false) List
users) {
// 方法体
}
```
客户端请求示例:
```
http://localhost:8080/users?userIds=[{"id":1,"name":"John"},{"id":2,"name":"Tom"}]
```
在方法体中,即可使用users参数进行业务处理。
在controller层接受集合时,可以使用@RequestParam注解或@RequestBody注解来实现。其中@RequestParam注解用于接收表单数据或url中的参数,而@RequestBody注解则用于接收请求体中的数据。
@RequestParam注解接收的是以"&"符号分隔的key-value形式的参数,比如?id=1&name=test。而@RequestBody注解接收的是json格式的数据,也可以接收xml或其他格式的数据。在使用@RequestBody注解时,需要在请求头中指定Content-Type为application/json或其他对应的格式。
如果需要接收多个参数,可以将参数封装成一个对象,然后使用@RequestBody注解进行接收。同时,需要确保封装的对象与请求体中的数据格式一致。
需要注意的是,如果接收的集合中包含复杂对象,需要在复杂对象中添加无参构造函数,否则在反序列化时会出现异常。
在实际开发中,根据具体的需求和接口设计,可以灵活选择@RequestParam注解或@RequestBody注解来接收集合,并根据实际情况进行参数封装和数据格式的处理。
@RequestParam、@PathVariable、@RequestBody和@Param
顾名思义:获取参数,即获取传送过来的参数。例如获取下面链接的id参数值:
//链接(注意链接格式区别)
http://localhost:8080/hello?id=6
此时@RequestParam的作用就可以获取id下来并且作为形参传给方法体里面的id。
@RequestParam用于Controller层,是Spring的注解。 解决前台参数名称与后台接收参数变量名称不一致的问题,等价于request.getParam。具体参数:
1??value:参数名字,即入参的请求参数名字,如username表示请求的参数区中的name为username的参数的值将传入;
2??required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报 404 错误码;
3??defaultValue:默认值,表示如果请求中没有同名参数时的默认值,默认值可以是SPEL表达式,如“#{systemProperties['java.vm.version']}”。
顾名思义:路径变量,即获取链接路径上的变量。例如获取下面链接的id:
//链接(注意比较上面一条链接)
http://localhost:8090/hello/6
此时@PathVariable的作用是将路径上的id获取进来传递给方法体里面的形参id,但是变量名称必须一样。比如这里: value = "/getBook/{id}" 和 @PathVariable Integer id ;两个都必须是一样的,即都为 id ,否则报错;
@RequestBody注解一般主要是用来处理 content-type:"application/json charset=utf-8" 或者 content-type:"application/xml charset=utf-8" 两种请求数据,一般是异步请求用的比较多些,例如:
此时@RequestBody注解就可以获取到请求中的各个参数,然后赋值到相对应的方法形参上。另外,当有一个实体类User包含了id和name的元素的话,在方法里面直接可以写 @RequestBody User user 就会自动封装好供使用了,不用麻烦像这样 @RequestBody Integer id,@RequestBody String name 一个一个的封装。
用于dao层,是MyBatis中的注解。使得mapper.xml中的参数与后台的参数对应上,也增强了可读性。
如果两者参数名一致得话,spring会自动进行封装,不一致的时候就需要手动去使其对应上。即:用注解来简化xml配置的时候,@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中 。
在dao层,用来给参数命名,在MyBatis的mapper中加上该注解,传递的参数与Sql中的字段名一致:
handler method 参数绑定常用的注解,根据处理的Request的不同内容部分分为四类:(主要讲解常用类型)
@RequestBody接收Json参数 用自定义注解对Vo对象中Date类型日期格式校验
标题太长有木有?主要是为了把问题描述清楚,免得进错文章。
昨天测试的同事测试接口的时候,测试出来一个Date类型校验问题。 要求输入的日期格式是:yyyy-MM-dd HH:mm:ss,Vo中使用的注解如下:
测试同事输入下面两种参数都是保存成功,当输入为“202105”参数时,保存的数据变为“1970-01-01 08:03:22”,由此发现这个问题。
常用的三种日期格式化的注解解释如下:
由于 @RequestBody 注解先将json字符串转换成对应的Vo对象,Vo对象中的字段上添加的注解再生效, @DateTimeFormat 只是做格式化,无法做格式校验。
用自定义注解进行json字符串中的日期格式做校验。
解决思路 : 1.从request对象中获取原始json字符串入参 。由于自定义注解接口ConstraintValidator的实现获取到的参数值是@RequestBody注解将json字符串参数解析成Vo对象后的Date对象,不是原始json字符串值,所以需要从request中获取json原始参数值; 2.获取到json入参原始值使用正则表达式对日期进行格式进行校验 。
温馨提示 : 1.由于自定义注解中是无法直接获取到request对象,所以需要按照各自框架获取request对象的方式进行获取。 2.获取到的原始json字符串入参可能包含 空格 、 回车 、 换行符 、 制表符 这些特殊字符,所以需要进行特殊字符处理。 3.获取Vo对象中添加注解的属性名。 详细见: getFieldName(ConstraintValidatorContext context)即:【((ConstraintValidatorContextImpl) context).basePath.currentLeafNode.name】
SearchTaskVo.java
DateFormatValidation.java
DateFormatValidator.java
至此问题解决~ 文章中有何隐藏问题欢迎留言交流~ 有好的解决方案欢迎留言~
SpringBoot篇 - Controller中常用的注解简介
SpringBoot的Controller中经常会用到注解@Controller、@RestController、@RequestMapping、@RequestParam、@PathVariable、@RequestBody等,以下针对这些注解简单使用。
@Controller 定义了一个控制器类,它需要配合使用@RequestMapping 注解的方法才是真正处理请求的处理器。
使用此注解返回的不是Json数据,而是页面类数据。
例如:
先在pom.xml中添加依赖
然后在resources目录下新建templates目录,并且在templates目录下创建hello.html文件。
最后创建HelloController
启动服务,访问localhost:8080/test/hello,页面跳转到hello.html页面。
使用@RestController注解的方法表示一个控制器,返回json。原来返回一个json需要@Controller和@RequestBody配合使用。
例如:
启动服务,访问 http://localhost:8080/jdbc/select?memberNo=20211123146 ,返回:
@RequestMapping可以使用在类上,也可以使用在方法上。
而@GetMapping/@PostMapping 其实就是@RequestMapping和Get/Post的集合
@GetMapping(value = “hello”) 等价于@RequestMapping(value = “hello”, method = RequestMethod.GET)
@PostMapping(value = “hello”) 等价于@RequestMapping(value = “hello”, method = RequestMethod.POST )
@RequestParam用于获取查询参数。格式为:url?name=AAA
例如:
启动服务,访问 http://localhost:8080/jdbc/select?memberNo=20211123146 即可。
通过@PathVariable可以将URL中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。即获取路径参数。格式为:url/{id}
例如:
启动服务,访问 http://localhost:8080/jdbc/select/20211123146 即可。
@RequestBody传递的需要是对象
示例1:
启动服务,使用postman访问 http://localhost:8080/jdbc/memberPost1 即可。查看控制台输出:
Member(memberId=5, shopId=9730231, memberNo=20211123146, mobile=13800, openId=#zssyd4U4J3p+czzXkwg+ZQ==)
示例2:
启动服务,使用postman访问 http://localhost:8080/jdbc/memberPost2 即可
示例3:不使用注解
启动服务,使用postman访问 http://localhost:8080/jdbc/memberPost3 ,并在postman的form-data中分别传入key-value
总结:
如果要在Controller层返回一个页面,用注解@Controller;如果让其作为一个接口,用@RestController
在GET请求中(@GetMapping),不能使用@RequestBody。
在POST请求(@PostMapping),可以使用@RequestBody和@RequestParam
@RequestParam注解接受的参数来源于url中,格式为xxx?username=aa&password=456,而@RequestBody注解接收的参数则是来自于requestBody中,即请求体中。
requestbody注解可以直接用在单个属性上吗
@RequestParam A) 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( 由String到 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,...
JSON处理(一):HTTP请求响应的JSON化 @RequestBody 和 @ResponseBody
现Web开发中实行前后分离,数据交互为JSON形式,现对后端如何接收、返回JSON形式数据做介绍
将Http Request的请求体中的数据(json/xml)绑定到Controller方法的形参Bean对象上。而能否将body数据能否由@RequsetBody注解成功进行解析绑定,取决于请求头的Content-Type字段的值,应该为:application/json
该注解用于Controller的形参Bean前即可
将controller返回的对象,转换为JSON格式数据,并写入到Response的响应体中。
该注解用于Controller方法上;也可以直接用于类上,表示该类中的所有Controller方法均应用该注解
如下实例,向 http://localhost:8080/demo1 发送POST请求,请求体中为JSON数据:{"age": 37,"name": "Tom"}后
可以看到控制台输出如下,说明@RequestBody接收绑定请求体的数据成功
返回的响应体内容如下,说明@ResponseBody返回JSON数据成功
在POST请求下@RequestBody注解方式对比@RequestParam似乎前者可以取代后者...
ReuestBody的方式:
后端api:
postMan错误示例:
后端SQL打印语句,传入的参数明显错了,传了" "province":"广东省"? "这整个字符串,我要的只是"广东省"
postMan正确测试事例:
@RequestParam的注解方式,一个只能传一个 ,url上改?接参数名接参数值....
api方法参数:
在POSTMan测试写法要在Params那里传值而不是在body那里
都只传一个类型没问题,但是如果传对象的话,用RequestParam做不到,而RequestBody自然是可以的
一个Staff实体类作为参数,api的写法: