zoukankan      html  css  js  c++  java
  • @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;

        省略getset方法...
    }
    public class Question {

        private String id;

        private String title;

        private String content;

        省略getset方法...
    }

    在这给大家说一下 @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

  • 相关阅读:
    SPOJ GSS4 Can you answer these queries IV ——树状数组 并查集
    SPOJ GSS3 Can you answer these queries III ——线段树
    SPOJ GSS2 Can you answer these queries II ——线段树
    SPOJ GSS1 Can you answer these queries I ——线段树
    BZOJ 2178 圆的面积并 ——Simpson积分
    SPOJ CIRU The area of the union of circles ——Simpson积分
    HDU 1724 Ellipse ——Simpson积分
    HDU 1071 The area ——微积分
    HDU 4609 3-idiots ——FFT
    BZOJ 2194 快速傅立叶之二 ——FFT
  • 原文地址:https://www.cnblogs.com/niceyoo/p/13934626.html
Copyright © 2011-2022 走看看