查看原文
其他

说说几种Spring MVC支持的客户端传参方式

尤慕 背井 2020-01-13

本文通过review一段代码来讲述2个问题:

  • http请求格式(针对1.1版本)

  • Spring处理客户端传参的几种方式




在review项目代码时,看到了如下一个 controller 方法:



我们通常不建议controller层依赖servlet包下的类,以便于编写测试。暂忽略此点,先看看 getNotifyMsg 方法做了什么。



代码猛一看挺复杂,实际目的很简单:读取 request body 内容。


我们先不管该方法的具体实现(因为实现本身存在可调整的地方,比如可以直接使用 httpServletRequest.getReader() 来获取 Reader对象,不需要自己再一步一步构造了),先抛出一个问题:我们是否能完全避免 getNotifyMsg 这个方法,利用Spring内置的特性,自动读取request body?




首先,我们复习一下 http 请求的格式。


对于如下curl请求:



服务端实际上接收的请求信息是这样的:



它由三部分组成,分别是起始行(start-line)请求头(headers)、和请求体(body)


对于上图而言:

  • 第1行是起始行,起始行本身又分为三部分:请求方法(method, 这里是POST);路径(path,这里是 /hello/world?from=youmoo);以及协议版本(protocol version,这里是 HTTP/1.1)。

  • 第2~6行是头部。头部允许有多行,每一行是一个header键值对。

  • 第8行是请求体(request body ,也叫payload)。头部和请求体总是由一个空行隔开。


在http请求中,请求体是可选的(可以没有)。


有了以上了解,我们再谈谈另一个问题:Spring MVC 支持哪些传参方式?




理解http请求格式后,我们看看Spring支持的参数解析方式。


一、通过 query string


http请求路径中问号(?)后的字符串,叫作 query string (也叫search、search string、search params等)。


在Spring中,我们可以使用 @RequestParam 获取 query string 中对应的参数值:



在这种情况下,可以直接忽略 @RequestParam 注解,即,上图中方法1方法2的效果一样。


二、通过请求路径(path)


假如有一个controller方法,它既支持 /hello/tom 路径也支持 /hello/jerry 路径,即,支持 /hello/* 路径。Spring允许我们通过 @PathVariable 捕获该子路径。



三、通过请求头(header)


比如当我们需要获取客户端的 user agent 时:



实际开发中我们会传递一些自定义header来实现某些功能(比如用户token、上下游链路标识等)。


四、通过请求体(body)


现在流行restful api开发,在restful格式中,请求参数常以json的形式在请求体中发送。问题是,请求体可以传输任何数据,我们怎么知道收到的是什么格式的数据呢?


答案是,通过设定 content-type 请求头。


在Spring中,对请求体的解析也依赖于 content-type 头。


如果content-type属于json一族,我们通常使用 @RequestBody 进行参数接收:



通过form表单传递参数也很常用,它的 content-typeapplication/x-www-form-urlencoded

在Spring中form表单的解析方式和 query string 类似,也是用 @RequestParam 来接收。


如果一个参数既出现在了query string中,又出现在了form表单中,Spring会用逗号将2者拼接起来(query string在前,form表单在后)作为参数的值。


五、通过cookie


cookie 也在请求头当中,但 cookie 下允许存在多个键值对,每个键值对又能单独解析以供使用。


在Spring中,我们使用 @CookieValue 注解来接收单个cookie:



依托Spring强大的参数类型自动转换机制,我们既可以使用原生 Cookie 对象接收cookie 值,也可以用 String/int(取决于cookie值的类型)


六、如果你需要知道请求方法...


有些controller方法支持多种请求(如GET/POST)等,如果你的业务逻辑依赖于请求方法,可以像下面这样接收请求方法:





有了以上对http请求格式以及spring如何处理客户端参数的认识,我们再回到第一个问题:我们是否能完全避免 getNotifyMsg 这个方法,利用Spring内置的特性,自动读取request body?


答案是。。。OF COURSE!


我们只需要将第一张图中的 payWechat 方法像下面这样写即可:



是不是很省心?这也是Spring的强大之处,数据解析交给它,开发者只需要关注解析结果




实际上controller方法也支持 InputStream / Reader / @RequestBody byte[] 作为入参类型,具体的用途请读者自己探索。


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存