美文网首页
@RequestBody修饰对象几种情景测试

@RequestBody修饰对象几种情景测试

作者: mecury | 来源:发表于2019-05-10 20:11 被阅读0次

[TOC]

@RequestBody测试.png

问题起因:

关于 @RequestBody 注解使用的几点疑问:

事情的起因是这样的,入职新公司之后,查看代码,见到了一种写法,感到十分奇怪:

@PostMapping("/xxx/yyy")
public Result<Boolean> createXXX(PaymentServiceDTO serviceDTO, PaymentAccountDTO accountDTO) {

}
  • 按照 Restful Http请求来说,POST 请求的参数一般是放到 Body 中的,这种写法我理解是不允许的。
  • 其次,POST 请求中放入了两个请求对象,记得之前有同事告诉我 @RequestBody 用于 POST请求,作用是将请求中的 Body json 数据解析为对象类型,方便操作,但是 @RequestBody 只能在一个 Mapping 中使用一次。
  • 后来还看到类似下面的代码,更增加了我的疑惑
@PostMapping("/xxx/yyy")
public Result<Boolean> createXXX(@RequestBody PaymentServiceDTO serviceDTO, PaymentAccountDTO accountDTO) {

}

  1. 该项目 POST 请求为什么会有上面的写法?
  2. @RequestBody 能否修饰多个对象?
  3. @RequestBody 修饰一个对象,但是像上面没有修饰的对象会怎么处理?
  4. 如果像上面一样,两个对象都不用 @RequestBody 修饰,那么参数应该放在哪里?又是怎么解析为对象的?

上面已经十分明白,我还是挺佩服的,这里说下后三个问题的答案:

Answer:

  1. @RequestBody 不能修饰多个对象,在一个方法中同时使用该注解,编译能通过,运行时会抛出异常
  2. 即使是 POST 请求,默认的参数类型也是 application/x-www-form-urlencoded,即参数作为 query param,放到 url 的后面。因此这种就好解释了
  • @RequestBody 修饰的对象,会填充 Body 中的参数
  • 没有修饰的对象,会由 query param 中的参数进行填充
  1. 如果都不用,就都会由 query param 中进行解析,填充入各个对象中,唯一的问题就是对象属性名不能相同,相同的属性名会被填充相同的值。

问题测试:

下面是测试的示例:

1. 使用 @RequestBody 修饰正常的情况

后端代码:

    @PostMapping("/normal")
    public void printInfo1(@RequestBody User user) {
        log.info("user   -->" + user);
    }

调用:

curl -X POST --header "Content-Type: application/json" --header "Accept: */*" -d "{
\"firstName\": \"firstname\",
\"lastName\": \"lastname\"
}" "http://localhost:8080/normal"
2019-05-10 19:20:22.920  INFO 2129 --- [io-8080-exec-10] com.example.demo.TestController          : user   -->User(id=0, firstName=firstname, lastName=lastname)

2. 不使用 @RequestBody 修饰

后端代码:

@PostMapping("/with_no_annotation")
    public void printInfo2(User user) {
        log.info("user   -->" + user);
    }

调用:

  • 参数放到 Body 中
curl -v -X POST --header "Content-Type: application/json" --header "Accept: */*" -d "{
\"firstName\": \"firstname\",
\"lastName\": \"lastname\"
}" "http://localhost:8080/with_no_annotation"
2019-05-10 19:36:36.742  INFO 2129 --- [nio-8080-exec-5] com.example.demo.TestController          : user   -->User(id=0, firstName=null, lastName=null)
  • 参数放到查询参数中
curl -v -X POST \
  http://localhost:8080/with_no_annotation \
  -d 'firstName=firstname&lastName=lastname'
2019-05-10 19:39:09.072  INFO 2129 --- [nio-8080-exec-1] com.example.demo.TestController          : user   -->User(id=0, firstName=firstname, lastName=lastname)

3. 传递两个对象,一个使用 @RequestBody 注解,一个不使用

后端代码:

    @PostMapping("/with_one_have")
    public void printInfo3(@RequestBody User user, ProductInfo productInfo) {
        log.info("user   -->" + user);
        log.info("product-->" + productInfo);
    }

调用:

  • 参数一个放在 Body 中,一个放入到 query param中
curl -X POST \
  'http://localhost:8080/with_one_have?productName=productName&productDesc=productDesc' \
  -H 'Content-Type: application/json' \
  -d '{
"firstName": "firstname",
"lastName": "lastname"
}'
2019-05-10 19:49:56.695  INFO 2129 --- [nio-8080-exec-2] com.example.demo.TestController          : user   -->User(id=0, firstName=firstname, lastName=lastname)
2019-05-10 19:49:56.695  INFO 2129 --- [nio-8080-exec-2] com.example.demo.TestController          : product-->ProductInfo(id=0, productName=productName, productDesc=productDesc)

4. 两个对象参数都使用 @RequestBody 修饰

后端代码:

    @PostMapping("/with_all_have_annotation")
    public void printInfo4(@RequestBody User user, @RequestBody ProductInfo productInfo) {
        log.info("user   -->" + user);
        log.info("product-->" + productInfo);
    }

调用:

  • 调用方法都没有办法写。。。。。。。
  • 下面是使用一个Json作为参数传递
curl -X POST --header "Content-Type: application/json" --header "Accept: */*" -d "{
    \"productName\":\"productName\",
    \"productDesc\":\"productDesc\"
}" "http://localhost:8080/with_all_have_annotation"
2019-05-10 19:54:50.903  WARN 2129 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: Stream closed]

5. 两个对象参数都不使用 @RequestBody修饰

后端代码:

    @PostMapping("/with_all_no_annotation")
    public void printInfo5(User user, ProductInfo productInfo) {
        log.info("user   -->" + user);
        log.info("product-->" + productInfo);
    }

调用:

出现问题当对象包含相同的字段时,会被覆盖为相同的值

 curl -X POST \
  'http://localhost:8080/with_all_no_annotation?id=1111&firstName=li&lastName=haifei&productName=productName&productDesc=productDesc'
2019-05-10 19:56:27.394  INFO 2129 --- [nio-8080-exec-7] com.example.demo.TestController          : user   -->User(id=1111, firstName=li, lastName=haifei)
2019-05-10 19:56:27.394  INFO 2129 --- [nio-8080-exec-7] com.example.demo.TestController          : product-->ProductInfo(id=1111, productName=productName, productDesc=productDesc)

6. 总结

看完上面,应该已经明白上面问题的答案了。其实这里如果看过源码,应该很好就解决了,奈何这里没看,只能使用比较笨的方法。还是源码大法好啊!

相关文章

网友评论

      本文标题:@RequestBody修饰对象几种情景测试

      本文链接:https://www.haomeiwen.com/subject/lmszoqtx.html