【SpringBoot接收接口入参的几种方式】

【SpringBoot接收接口入参的几种方式】在日常的 SpringBoot 开发中 针对不同的请求类型如 GET POST PUT DELETE 等 它们都分别都支持什么样的传参方式 对应的 controller 方法的定义又是什么样的 本文进行了全面的总结 方便后续查阅

大家好,欢迎来到IT知识分享网。

0.引言

1) 传参的几种方式

我们从调用方的视角去看待这个问题,对调用方来说,它在调用接口时有如下的几种传参方式:

  1. Query参数。表现形式是调用方在调用接口时,入参是拼接在接口的URI后面的,如/test_get/requestparam_1?name=wangwu&age=18。这种方式在入参个数比较少GET请求方式中比较常用。
  2. Path参数。这是REST风格的路径参数,入参直接拼接在接口的URI里面,如/test_pathvar/test1/zhangsan/1,其中的zhangsan1就是就是参数。这种方式在REST风格的接口中比较常用。
  3. Body参数。这种方式是把入参放在了请求体当中!它跟前两种入参方式的最大区别,就是:
    1)前两种入参方式它们的入参都是直接体现在了调用接口时候的URI
    2)而当前的这种Body参数方式,它的入参是放在了Body请求体
    而且,Body参数又可以细分成如下的几种方式:
    • application/json 前后端分离项目中常用的传参方式
    • x-www-form-urlencoded 上传表单数据
    • form-data 上传表单数据
    • xml
    • raw
    • binary




2) 关于请求方式与传参方式

无论是GETPOSTPUT还是DELETE请求方式,从技术上来说,它们几乎都支持上面提到的几种传参方式的——也就是说,即使是【GET发送body参数】,或者【POST发送Query参数】这样奇怪的使用方式,从技术上来说也是支持的!只不过在日常的开发中,我们可能更偏向于【GET发送Query参数】、【POST发送Body参数】这样的搭配使用方式。
关于GET请求能否发送body,可以看这篇文章,讲的非常好:HTTP GET 请求可以有 body 吗?
我这里直接将文章的结论贴出来:

HTTP 协议没有为 GET 请求的 body 赋予语义,也就是既不禁止也不要求 GET 请求带 body
大多数 HTTP 实现从技术上都支持 HTTP GET 请求带 body,少数实现会禁止(google-chrome 浏览器、node-fetch),少数实现会不建议(Fiddler)。

文章中作者的个人建议,也贴出来供参考:

软件工程中有一条原则:不要依赖未定义的行为。HTTP 协议未定义GET请求的 body 语义,如果想用GET请求发送 body,得先为其定义语义,并确保上下游都能很好的支持。作为服务接口的提供方,不应该假设所有的调用方都能发出GET请求 body;作为调用方,不应该假设服务方能完美解析GET请求 body,但如果服务方提供了支持GET请求 body 的接口,可以放心使用,不用纠结。
软件工程中还有另一条原则,不记得原文了,翻译成中国的老话就是:严于律己,宽已待人。我们在写库、写框架、写工具时应该支持GET请求带 body;在封装接口时,尽量不要强制调用方用GET body 提交数据,除非遇到用GET body 才符合逻辑的特殊情况;在使用别人提供的库、框架、工具,或者调用协作方提供的接口时不应该强求对方支持GET请求 body。

下面,将会依次对这几种参数方式进行讲解和代码示例。

3)代码的相关说明

3.1) 项目的pom依赖

 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Hutool是一个小而全的Java工具类库--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.6.3</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.6</version> </dependency> </dependencies> 

3.2) 代码说明

  1. 下面所有接口的定义,使用的都是@RequestMapping,且都没有指定具体的请求类型——如此故意为之就是为了使得接口从技术上支持各种请求方式(GET POST PUT DELETE等),好方便测试在不同的请求方式下,是否支持各种不同的传参方式。但是大家在平日的业务代码开发中,最好是在接口定义时指定特定的请求方式。
  2. 在下面所有的代码中,我都在方法定义的形参中加上了HttpServletRequest,是因为我要从HttpServletRequest中获取请求的方法类型(request.getMethod())和URI( request.getRequestURI()),从而在接口的返回结果在显现出来,以方便调试。
    大家在自己实际的业务代码中可以根据自身需求决定是否加上这个。不加也不影响入参的接收!
  3. 下面所以接口的定义中,方法返回类型都是string类型,如:
method: [DELETE], uri: [/test_query/requestparam_1], param type: [Query] ---> SUCCESS! requestParam1 name = wangwu-delete, age = 18 

但是看后面调用方调用接口的返回结果,却是如下所示的json串:

{ 
    "code": 0, "data": "method: [DELETE], uri: [/test_query/requestparam_1], param type: [Query] ---> SUCCESS! requestParam1 name = wangwu-delete, age = 18", "msg": "操作成功", "timestamp": 05 } 

可以看到方法返回的String内容则是在json串的data这个key当中。
这是因为在我的项目中,我结合@RestControllerAdviceResponseBodyAdvice,对接口返回结果进行了统一的处理。(核心的处理逻辑是:如果接口返回结果类型已经是指定的ResultVO,直接返回;否则将接口返回结果封装到ResultVO对象的data字段中,再返回。)
4. 本文旨在展示在各种请求方式下对不同传参方式的支持情况,因此下面代码中,都没有对接口入参进行任何的校验——即:校验不是本文的重点,关于接口入参的校验,可以去看我的另一篇博客。


1.Query参数

Query参数,表现形式是调用方在调用接口时,入参是拼接在接口的URI后面的,如/test_query/requestparam_1?name=wangwu&age=18

1.1接口定义方式1:在方法形参的位置,把每个参数都平铺开来

  • 定义方式: 在方法形参的位置,把每个参数都平铺开来
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:虽然这种传参方式,从技术上来说可用于GET POST PUT DELETE等请求方式,但是在日常开发中一般偏向于应用在入参个数少(一般少于5个)GET请求方式中
  • 优点:方便简单
  • 缺点:
      1. 调用时入参直接显示在uri中,不太安全
      1. 方法定义时参数个数如果过多,方法体结构会显得很臃肿
      1. 没有入参校验

代码

package com.su.demo.controller.param_type; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; @RestController @RequestMapping(value = "/param_type/query") public class TestQueryController { 
     / * <ul> * <li><b>入参类别</b>:Query参数 * <li><b>定义方式</b>: 在方法形参的位置,把每个参数都平铺开来</li> * <li><b>调用方式</b>: 入参拼接在接口的uri后面,如 /test_get/requestparam_1?name=wangwu&age=18</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:虽然这种传参方式,适用于GET POST PUT DELETE等请求方式,但是一般偏向于应用在 入参个数少(一般少于5个)的<b>GET</b>请求方式中</li> * <li><b>优点</b>:方便简单</li> * <li><b>缺点</b>:1) 入参直接显示在uri中,不太安全 2)参数个数如果过多,方法体结构会显得很臃肿; 3)没有入参校验</li> * </ul> * <p><b>注意</b>:根据自己的需求决定是否在形参中加上HttpServletRequest,我这里是为了从request中获取method,所以加上了</p> */ @RequestMapping(value = "/test1") public String test1(String name, Integer age, HttpServletRequest request) { 
     // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age; } } 

调用case

注意看上面这个/param_type/query/test1接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以GET 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。

1.2接口定义方式2:在方法形参的位置,结合@RequestParam把每个参数都平铺开来

  • 定义方式: 在方法形参的位置,结合@RequestParam把每个参数都平铺开来
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:虽然这种传参方式,从技术上来说可用于GET POST PUT DELETE等请求方式,但是在日常开发中一般偏向于应用在入参个数少(一般少于5个)GET请求方式中
  • 优点:方便简单,且结合@RequestParam,可实现入参的必填校验/重命名/默认值等简单的校验功能
  • 缺点:
      1. 调用时入参直接显示在uri中,不太安全
      1. 方法定义时如果参数个数如果过多,方法体结构会显得很臃肿
      1. @RequestParam能支持的校验相对来说还是比较简单

代码

package com.su.demo.controller.param_type; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; @RestController @RequestMapping(value = "/param_type/query") public class TestQueryController { 
     / * <ul> * <li><b>入参类别</b>:Query参数 * <li><b>定义方式</b>: 在方法形参的位置,把每个参数都平铺开来.并且相较于前一种定义方式,这种方式使用 {@link RequestParam}绑定请求参数到方法形参, 且需要注意该注解中的各个属性的作用!</li> * <li><b>调用方式</b>: 入参拼接在接口的uri后面,如 /test_get/requestparam_1?name=wangwu&age=18</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:虽然这种传参方式,适用于GET POST PUT DELETE等请求方式,但是一般偏向于应用在 入参个数少(一般少于5个)的<b>GET</b>请求方式中</li> * <li><b>优点</b>:方便简单;且结合{@link RequestParam},可实现入参的必填校验/重命名/默认值等简单的功能</li> * <li><b>缺点</b>:1) 入参直接显示在uri中,不太安全 * 2)参数个数如果过多,方法体结构会显得很臃肿(当前这个方法有4个入参,其实就已经有点臃肿了) * 3){@link RequestParam}能支持的校验相对来说还是比较简单</li> * </ul> */ @RequestMapping(value = "/test2_requestparam") public String test2(@RequestParam String name, @RequestParam(name = "newAge") Integer age, @RequestParam(name = "birth", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date birth, @RequestParam(defaultValue = "true") Boolean enable, HttpServletRequest request) { 
     // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age + ", birth = " + birth + ", enable = " + enable; } } 

调用case

注意看上面这个/param_type/query/test2_requestparam接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以GET 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述

可以看到,参数都获取到了。

1.3接口定义方式3:把入参封装到一个实体中

  • 定义方式: 把入参封装到一个实体中
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:虽然这种传参方式,从技术上来说可用于GET POST PUT DELETE等请求方式,但是在日常开发中一般偏向于应用在入参个数多(一般大于5个)GET请求方式中
  • 优点:因为参数都封装在实体对象当中了,所以对参数的个数就没有什么的限制了,接口定义的时候方便多了
  • 缺点:对于这种入参的定义方式来说,它是没有什么缺点的,硬要说缺点的话,其实是针对Query这种传参方式来说的,即:当参数个数一多的时候,参数都放在请求uri中了,一个是不太安全,另外也容易造成uri的长度过过长 (虽然http协议中未明确对url进行长度限制,但在真正实现中,url的长度还是受到限制的,一是服务器端的限制,二就是游览器端的限制)

注:再次申明,在下面代码中,我在方法定义的形参中加上了HttpServletRequest,是因为我要从HttpServletRequest中获取请求的方法类型(request.getMethod())和URI( request.getRequestURI()),从而在接口的返回结果在显现出来,以方便调试。
大家在自己实际的业务代码中可以根据自身需求决定是否加上这个。不加也不影响入参的接收!

代码

package com.su.demo.controller.param_type; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; @RestController @RequestMapping(value = "/param_type/query") public class TestQueryController { 
     / * <ul> * <li><b>入参类别</b>:Query参数 * <li><b>定义方式</b>: 把入参封装到一个实体中(入参个数多于5个时一般用这种方式) * <li><b>调用方式</b>: 入参拼接在接口的uri后面,如 /test_get/requestparam_1?name=wangwu&age=18</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:从技术上来说这种传参方式,同时适用于GET POST PUT DELETE等多种请求方式,但是一般我个从偏向于在入参个数大于5个的<b>GET</b>请求方式中使用</li> * <li><b>优点</b>:因为参数都封装在实体bean当中了,所以对参数的个数就没有什么的限制了,接口定义的时候方便多了 * <li><b>缺点</b>:对于这种入参的[定义方式]来说,它是没有什么缺点的.硬要说缺点的话,其实是针对Query这种传参方式来说的,即当参数个数一多的时候,参数都放在请求uri中容易造成uri的长度过过长 * (虽然http协议中未明确对url进行长度限制,但在真正实现中,url的长度还是受到限制的,一是服务器端的限制,二就是游览器端的限制)</li> * </ul> */ @RequestMapping(value = "/test3_entity") public String test3(UserDTO userDTO, HttpServletRequest request) { 
     // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! userDTO = " + userDTO; } } 

其中UserDTO 的代码如下:

package com.su.demo.bean.dto; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; @Data public class UserDTO { 
     / * 主键ID */ private Long id; / * 用户姓名 */ private String name; / * 用户状态 true:启用;false:禁用 */ private Boolean enable; / * 用户生日 */ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date birth; } 

调用case

注意看上面这个/param_type/query/test3_entity接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以POST 请求方式的调用结果为例,看是否可以在controller代码中获到调用方传过来的实参。
在这里插入图片描述
可以看到,参数都获取到了。

1.4接口定义方式4:用原生的HttpServletRequest接收参数

  • 定义方式: 在方式形参的位置,用原生的HttpServletRequest接收
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景现在很少用这种方式去接收入参了。
  • 优点:HttpServletRequest是整个请求,可以获取到所有的数据.且HttpServletRequestHttpServletResponse都是内置对象,可以使用
  • 缺点:代码中再去从request中拿到参数,比较麻烦

代码

package com.su.demo.controller.param_type; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; @RestController @RequestMapping(value = "/param_type/query") public class TestQueryController { 
     / * <ul> * <li><b>入参类别</b>:Query参数 * <li><b>定义方式</b>: 在方式形参的位置,用原生的{@link HttpServletRequest}接收 * <li><b>调用方式</b>: 入参拼接在接口的uri后面,如 /test_get/requestparam_1?name=wangwu&age=18</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,但是正常情况下比较少用这种方式来获取参数了</li> * <li><b>优点</b>:{@link HttpServletRequest}是整个请求,可以获取到所有的数据.且HttpServletRequest、HttpServletResponse都是内置对象,可以使用</li> * <li><b>缺点</b>:代码中再去从request中拿到参数,比较麻烦</li> * </ul> * <p> 注意,这种方式其实也可以获取body请求体里面的数据,参考https://blog.csdn.net/_/article/details/ */ @RequestMapping(value = "/test4_request") public String test4(HttpServletRequest request) throws IOException { 
     // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); String name = request.getParameter("name"); Integer age = Integer.parseInt(request.getParameter("age")); // 需要进行类型转换 return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age; } } 

调用case

注意看上面这个/param_type/query/test4_request接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以PUT 请求方式的调用结果为例,看是否可以在controller代码中获到调用方传过来的实参。
在这里插入图片描述
可以看到,参数都获取到了。

1.5接口定义方式5:用Map结合RequestParam接收参数

  • 定义方式: 在方式形参的位置,用Map结合RequestParam接收参数
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:适用于参数个数较多,但是自己又想偷懒不想专门定义一个实体来接收入参的场景。一般不推荐使用这种方式
  • 优点:简单方便,偷懒很开心
  • 缺点:1)需要在代码中通过指定特定的key的方式去获取入参,比较麻烦;2)利用map去get到入参之后,还需要手动的去做非空判断+数据类型转换等,很麻烦;3)而且这种接收入参的方式,没有办法结合org.springframework.validation.annotation.Validated来做入参校验!

代码

package com.su.demo.controller.param_type; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; @RestController @RequestMapping(value = "/param_type/query") public class TestQueryController { 
     / * <ul> * <li><b>入参类别</b>:Query参数 * <li><b>定义方式</b>: 在方式形参的位置,结合{@link RequestParam}用Map接收 * <li><b>调用方式</b>: 入参拼接在接口的uri后面,如 /test_get/requestparam_1?name=wangwu&age=18</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:适用于参数个数较多,但是自己又想偷懒不想专门定义一个实体来接收入参的场景。一般不推荐使用这种方式。</li> * <li><b>优点</b>:简单方便</li> * <li><b>缺点</b>:需要在代码中通过指定特定的key的方式去获取入参,比较麻烦;而且这种接收入参的方式,没有办法结合{@link org.springframework.validation.annotation.Validated}来做入参校验</li> * </ul> */ @RequestMapping(value = "/test5_map") public String test5(@RequestParam Map<String, String> paramMap, HttpServletRequest request) throws IOException { 
     // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); String name = paramMap.get("name"); // 判断:如果paramMap.get("age")为null,则age赋默认值0;否则进行入参类型的转换 Integer age = null == paramMap.get("age") ? 0: Integer.parseInt(paramMap.get("age")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age; } } 

调用case

注意看上面这个/param_type/query/test5_map接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以DELETE 请求方式的调用结果为例,看是否可以在controller代码中获到调用方传过来的实参。
在这里插入图片描述

可以看到,参数都获取到了。


2.Path参数

Path参数,表现形式是入参直接拼接在接口的URI里面,如/test_pathvar/test1/zhangsan/1,其中的zhangsan1就是就是参数。这种方式在REST风格的接口中比较常用。

REST(英文:Representational State Transfer,简称REST,意思:表述性状态转换,描述了一个架构样式的网络系统,比如web应用),一定要记住==它是一种软件架构风格!而不是标准!==它只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
REST指的是一组架构(约束条件)和原则。满足这些(约束条件)和(原则)的应用程序或设计就是 Restful

2.1接口定义方式:用占位符的方式把入参封装到请求路径中

  • 定义方式: 用占位符的方式把入参封装到请求路径中,然后再通过@PathVariable注解可以将URL中的占位符参数绑定到控制器(controller)处理方法的形参中
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等多种请求方式。 但是一般入参个数较少,且你开发的是REST风格的接口,那可以考虑用这种方式
  • 优点和缺点:优点和缺点,其实就是REST风格的接口的优点和缺点了,大家可以自行去查阅

代码

package com.su.demo.controller.param_type; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController @RequestMapping(value = "/param_type/path_variable") public class TestPathVarController { 
      / * <ul> * <li><b>入参类别</b>:PathVariable路径参数方式 * <li><b>定义方式</b>: 用占位符的方式把入参封装到请求路径中,然后再通过@PathVariable注解可以将URL中的占位符参数绑定到控制器(controller)处理方法的形参中. </li> * <li><b>调用方式</b>: REST风格路径参数,入参拼接在接口的URI里面,如/test_pathvar/test1/zhangsan/1 </li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等多种请求方式. * 但是一般入参个数小于5个,且你开发的是REST风格的接口,那可以考虑用这种方式 * </li> * </ul> * <p>REST(英文:Representational State Transfer,简称REST,意思:表述性状态转换,描述了一个架构样式的网络系统,比如web应用),是一种软件架构风格不是标准哦! * 只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。 * REST 指的是一组架构(约束条件)和原则。满足这些(约束条件)和(原则)的应用程序或设计就是 Restful。</p> */ @RequestMapping(value = "/test1/{name}/{age}") public String test1(@PathVariable("name") String name, @PathVariable("age") Integer myage, HttpServletRequest request) { 
      // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", myage = " + myage; } } 

调用case

注意看上面这个/param_type/path_variable/test1/{name}/{age}接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以GET 请求方式的调用结果为例,看是否可以在controller代码中获到调用方传过来的实参。
在这里插入图片描述

可以看到,参数都获取到了。


3.Body参数

Body参数,这种方式是把入参放在了请求体当中!它跟前两种入参方式的最大区别,就是:

  1. 前两种入参方式它们的入参都是直接体现在了调用接口时候的URI
  2. 而当前的这种Body参数方式,它的入参是放在了http请求的请求体
    而且,Body参数又可以细分成如下的几种方式:
    • application/json 前后端分离项目中常用的传参方式
    • form-data
    • x-www-form-urlencoded
    • raw
    • binary


下面分别进行说明

3.1 application/json

这种入参方式,入参是json格式的,且放在http请求的请求体当中,并且在发起http请求时Content-Type=application/json

3.1.1 接口定义方式1:在方式形参的位置,用原生的HttpServletRequest接收

  • 定义方式: 在方式形参的位置,用原生的HttpServletRequest接收
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,但是正常情况下比较少用这种方式来获取Content-Type=application/json的body参数了
  • 优点:HttpServletRequest是整个请求,可以获取到所有的数据。且HttpServletRequestHttpServletResponse都是内置对象,可以使用
  • 缺点:码中再去从request中拿到参数,老麻烦了,可以看下面的代码
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson.JSON; import com.su.demo.bean.dto.UserDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @RestController @RequestMapping(value = "/param_type/body_json") public class TestBodyController { 
       / * <ul> * <li><b>入参类别</b>:body参数方式 * <li><b>定义方式</b>: 在方式形参的位置,用原生的{@link HttpServletRequest}接收 * <li><b>调用方式</b>: 参数放在请求体 body 当中 * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,但是正常情况下比较少用这种方式来获取body参数了</li> * <li><b>优点</b>:{@link HttpServletRequest}是整个请求,可以获取到所有的数据.且HttpServletRequest、HttpServletResponse都是内置对象,可以使用</li> * <li><b>缺点</b>:代码中再去从request中拿到参数,老麻烦,可以看下面的代码</li> * </ul> * <p> 注意,这种方式其实也可以获取body请求体里面的数据,参考https://blog.csdn.net/_/article/details/ */ @RequestMapping(value = "/test1_request") public String test1(HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); ServletInputStream inputStream = request.getInputStream(); // 用hutool工具包的read方式,将inputStream读取成string String body = IoUtil.read(inputStream, "UTF-8"); System.out.println("body = " + body); // 用fastjson将json字符串转换成bean UserDTO userDTO = JSON.parseObject(body, UserDTO.class); return requestMetaInfo + " ---> SUCCESS! userDTO = " + userDTO; } } 

其中UserDTO的代码如下:

package com.su.demo.bean.dto; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; @Data public class UserDTO { 
       / * 主键ID */ private Long id; / * 用户姓名 */ private String name; / * 用户状态 true:启用;false:禁用 */ private Boolean enable; / * 用户生日 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date birth; } 
调用case

注意看上面这个/param_type/body_json/test1_request接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以POST 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述
可以看到,参数都获取到了。

3.1.2 接口定义方式2:在方式形参的位置,用RequestBody接收

  • 定义方式: 在在方式形参的位置,用RequestBody接收
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,但是正常情况下一般用在POSTPUT 请求中
  • 优点:
    • 方法形参的定义非常简洁;
    • 调用的时候参数放在body中,参数体可以很大,不像Query入参方式在当参数过多的时候容易触发服务器端Request header is too large的报错
  • 缺点:用String类型来接收参数,接收之后再转换成bean实体,还是稍微显得有点麻烦
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson.JSON; import com.su.demo.bean.dto.UserDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @RestController @RequestMapping(value = "/param_type/body_json") public class TestBodyController { 
       / * <ul> * <li><b>入参类别</b>:body参数方式 * <li><b>定义方式</b>: 在方式形参的位置,用{@link RequestBody}接收 * <li><b>调用方式</b>: 参数放在请求体 body 当中 * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,但是正常情况下一般用在POST或PUT请求中</li> * <li><b>优点</b>:1)方法形参的定义非常简洁; * 2)调用的时候参数放在body中,参数体可以很大,不像Query入参方式在当参数过多的时候容易触发服务器端"Request header is too large"的报错 * </li> * <li><b>缺点</b>:用String类型来接收参数,接收之后再转换成bean实体,还是稍微显得有点麻烦</li> * </ul> */ @RequestMapping(value = "/test2_requestbody_string") public String test2(@RequestBody String body, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); System.out.println("body = " + body); // 用fastjson将json字符串转换成bean UserDTO userDTO = JSON.parseObject(body, UserDTO.class); return requestMetaInfo + " ---> SUCCESS! userDTO = " + userDTO; } } 
调用case

注意看上面这个/param_type/body_json/test2_requestbody_string接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以PUT 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述
可以看到,参数都获取到了。

3.1.3 接口定义方式3:用一个实例来接收RequestBody入参

  • 定义方式: 在方式形参的位置,用RequestBody接收,而且是直接用一个实例类来接收了(spring自动调用相应的org.springframework.http.converter.HttpMessageConverter去做了入参的转换)
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,但是正常情况下一般用在POSTPUT 请求中
  • 优点:
    • 方法形参的定义非常简洁;
    • 调用的时候参数放在body中,参数体可以很大,不像Query入参方式在当参数过多的时候容易触发服务器端Request header is too large的报错
  • 缺点:好像没啥缺点

工作中前后端分离项目一般用这用方式比较多

代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson.JSON; import com.su.demo.bean.dto.UserDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @RestController @RequestMapping(value = "/param_type/body_json") public class TestBodyController { 
       / * <ul> * <li><b>入参类别</b>:body参数方式 * <li><b>定义方式</b>: 在方式形参的位置,用{@link RequestBody}接收, * 而且是直接用一个实例类来接收了(spring自动调用相应的{@link org.springframework.http.converter.HttpMessageConverter}去做转换) * </li> * <li><b>调用方式</b>: 参数放在请求体 body 当中 * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,但是正常情况下一般用在POST或PUT请求中</li> * <li><b>优点</b>:1)方法形参的定义非常简洁; * 2)调用的时候参数放在body中,参数体可以很大,不像Query入参方式在当参数过多的时候容易触发服务器端"Request header is too large"的报错 * </li> * <li><b>缺点</b>:好像没啥缺点</li> * </ul> */ @RequestMapping(value = "/test3_requestbody_entity") public String test3(@RequestBody UserDTO userDTO, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! userDTO = " + userDTO; } } 
调用case

注意看上面这个/param_type/body_json/test3_requestbody_entity接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以DELETE 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述

可以看到,参数都获取到了。

3.1.4 接口定义方式4:用Map来接收RequestBody入参

  • 定义方式: 在方式形参的位置,用RequestBody接收,而且是直接用一个Map的实例类来接收了
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:适用于参数个数较多,但是自己又想偷懒不想专门定义一个实体来接收入参的场景。一般不推荐使用这种方式
  • 优点:简单方便,偷懒很开心
  • 缺点:1)需要在代码中通过指定特定的key的方式去获取入参,比较麻烦;2)利用map去get到入参之后,还需要手动的去做非空判断+数据类型转换等,很麻烦;3)而且这种接收入参的方式,没有办法结合org.springframework.validation.annotation.Validated来做入参校验!

一般不推荐使用这种方式

代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson.JSON; import com.su.demo.bean.dto.UserDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @RestController @RequestMapping(value = "/param_type/body_json") public class TestBodyController { 
       / * <ul> * <li><b>入参类别</b>:body参数方式 * <li><b>定义方式</b>: 在方式形参的位置,用{@link RequestBody}接收, * 而且是直接用一个Map对象实例类来接收了(spring自动调用相应的{@link org.springframework.http.converter.HttpMessageConverter}去做转换) * </li> * <li><b>调用方式</b>: 参数放在请求体 body 当中 * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:从技术上来说,这种传参方式同时适用于GET POST PUT DELETE等请求方式,一般使用在偷懒不想专门定义一个实体来接收入参的场景。一不太推荐使用这种方式/li> * <li><b>优点</b>:1)方法形参的定义非常简洁; * 2)调用的时候参数放在body中,参数体可以很大,不像Query入参方式在当参数过多的时候容易触发服务器端"Request header is too large"的报错 * </li> * <li><b>缺点</b>:好像没啥缺点</li> * </ul> */ @RequestMapping(value = "/test4_requestbody_map") public String test4(@RequestBody Map<String, String> paramMap, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); String name = paramMap.get("name"); // 判断:如果paramMap.get("age")为null,则age赋默认值0;否则进行入参类型的转换 Integer age = null == paramMap.get("age") ? 0: Integer.parseInt(paramMap.get("age")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age; } } 
调用case

注意看上面这个/param_type/body_json/test4_requestbody_map接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证),为了节约文章篇幅,下面只以POST 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述

可以看到,参数都获取到了。

3.2 x-www-form-urlencoded

x-www-form-urlencodedform-data,两者都可以用来上传前端表单数据,下面简单将两者的不同列举出来,更详细的可自行上网查询或者看下面博客 form-data、x-www-form-urlencoded的区别或者form-data与x-www-form-urlencoded的区别以及知识延伸
1.支持的入参类型不同x-www-form-urlencoded只支持普通的文本内容,不支持上传File文件!而form-data则支持上传File文件(如图片、音频、视频)。
2. 编码不同x-www-form-urlencoded的编码方式就隐藏在名字里urlencoded,即使用js中encodeURI()函数;而form-data的格式,要比 x-www-form-urlencoded复杂的多,它会把内容分成多个部分,每个部分都支持不同的格式
3. x-www-form-urlencoded占用字节少,form-data占用字节多


x-www-form-urlencoded会将表单内的数据转换为键值对,比如name=lisi&age=23,并放在请求体body中进行传输

3.2.1 接口定义方式1:在方法形参的位置,把每个参数都平铺开来

  • 定义方式: 方法形参的位置,把每个参数都平铺开来,也可以使用@RequestParam注解
  • 兼容的请求方式POST PUT DELETE注意,不兼容GET请示方式
  • 适用场景:虽然这种传参方式,适用于POST PUT DELETE等请求方式,但是一般偏向于应用在 用POSTPUT方式去发送的表单数据,且参数个数少,且表单字段都是普通类型(即表单字段不是File文件)
  • 优点:方便简单
  • 缺点:1)参数个数如果过多,方法体结构会显得很臃肿
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form_urlencoded") public class TestFormUrlEncodeController { 
       / * <p>注意,如果使用GET请求方式,则后端获取不到入参!!!</p> * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=application/x-www-form-urlencoded * <li><b>定义方式</b>: 在方法形参的位置,把每个参数都平铺开来</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=application/x-www-form-urlencoded</li> * <li><b>兼容的请求方式</b>:POST PUT DELETE</li> * <li><b>适用场景</b>:虽然这种传参方式,适用于POST PUT DELETE等请求方式,但是一般偏向于应用在 用<b>POST</b>或b>PUT</b>方式去发送的表单数据,且参数个数少,且表单字段都是普通类型(即表单字段不是File文件),</li> * <li><b>优点</b>:方便简单</li> * <li><b>缺点</b>:1)参数个数如果过多,方法体结构会显得很臃肿</li> * </ul> */ @RequestMapping(value = "/test1_requestparam") public String test1(String name, @RequestParam(name = "age", required = false) Integer age, Boolean enable, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age + ", enable = " + enable; } } 
调用case

注意看上面这个/param_type/body_form_urlencoded/test1_requestparam接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)——经过实测发现,当请示方式为GET 的时候,后端代码获取不到入参!而当请求方式为POST PUT DELETE的时候,后端可以获取到入参。
下面是示例

GET,传参失败

在这里插入图片描述

可以看到,没有获取到入参!

POST PUT DELETE 传参成功

为了节约文章篇幅,下面只以POST 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述

可以看到,参数都获取到了。

3.2.2 接口定义方式2:用一个实例来接收入参

  • 定义方式: 把入参封装到一个实体中,且实体一定不能使用@RequestParam@RequestBody注解修饰
  • 兼容的请求方式POST PUT DELETE注意,不兼容GET请示方式
  • 适用场景:虽然这种传参方式,适用于POST PUT DELETE等请求方式,但是一般偏向于应用在 用POSTPUT方式去发送的表单数据,且表单字段都是普通类型(即表单字段不是File文件)
  • 优点:方便简单,不管表单字段个个数多或少,一般如果表单字段类型没有File文件类型的,都可以使用这种方式
  • 缺点:缺点的话就是针对Content-Type=application/x-www-form-urlencoded这种入参方式来说了:不能上传文件
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form_urlencoded") public class TestFormUrlEncodeController { 
       / * <p>注意,如果使用GET请求方式,则后端获取不到入参!!!只支持POST PUT DELETE</p> * <p>且形参定义那里,一定不能使用{@link RequestParam}修饰</p> * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=application/x-www-form-urlencoded * <li><b>定义方式</b>: 把入参封装到一个实体中(入参个数多于5个时一般用这种方式)</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=application/x-www-form-urlencoded</li> * <li><b>兼容的请求方式</b>:POST PUT DELETE</li> * <li><b>适用场景</b>:虽然这种传参方式,适用于POST PUT DELETE等请求方式,但是一般偏向于应用在 用<b>POST</b>或<b>PUT</b>方式去发送的表单数据,且表单字段都是普通类型(即表单字段不是File文件),</li> * <li><b>优点</b>:方便简单,不管表单字段个个数多或少,一般如果表单字段类型没有File文件类型的,都可以使用这种方式</li> * <li><b>缺点</b>:缺点的话就是针对Content-Type=application/x-www-form-urlencoded这种入参方式来说了:不能上传文件</li> * </ul> */ @RequestMapping(value = "/test2_entity") public String test2(TeacherDTO teacherDTO, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! teacherDTO = " + teacherDTO; } } 
调用case

注意看上面这个/param_type/body_form_urlencoded/test2_entity接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)——经过实测发现,当请示方式为GET 的时候,后端代码获取不到入参!而当请求方式为POST PUT DELETE的时候,后端可以获取到入参。
下面是示例

GET,传参失败

在这里插入图片描述
可以看到,没有获取到入参!

POST PUT DELETE 传参成功

为了节约文章篇幅,下面只以PUT 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述
可以看到,参数都获取到了。

3.2.3 接口定义方式3:用原生的HttpServletRequest接收参数

  • 定义方式: 用原生的HttpServletRequest接收参数
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:一般很少这种方式来接收Content-Type=application/x-www-form-urlencoded的请求
  • 优点:获取入参很麻烦,没啥优点
  • 缺点:获取入参很麻烦

注意:

  1. 如果是GET请求方式,则:通过request.getInputStream()方式是可以获取入参的,获取到的数据示例:name=wangwu&age=12 ,但是通过request.getParameter("xxx")方式,却获取不到入参!
  2. 如果是 POST PUT DELETE请求方式,则正好相反: 通过request.getInputStream()方式无法获取入参,通过request.getParameter("xxx")方式则可以获取入参

下面代码是以request.getParameter("xxx")方式去获取入参

代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form_urlencoded") public class TestFormUrlEncodeController { 
       / * <p>如果是GET请求方式,则:通过request.getInputStream()方式可以获取入参,获取到的数据示例:name=wangwu&age=12 但是通过request.getParameter("xxx")方式,却获取不到入参!</p> * <p>如果是POST PUT DELETE请求方式,则正好相反: 通过request.getInputStream()方式无法获取入参,通过request.getParameter("xxx")方式则可以获取入参</p> * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=application/x-www-form-urlencoded * <li><b>定义方式</b>: 在方法形参的位置,用{@link HttpServletRequest}来接收入参</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=application/x-www-form-urlencoded</li> * <li><b>兼容的请求方式</b>:POST PUT DELETE</li> * <li><b>适用场景</b>:一般很少这种方式来接收Content-Type=application/x-www-form-urlencoded的请求</li> * <li><b>缺点</b>:获取入参很麻烦</li> * </ul> */ @RequestMapping(value = "/test3_request") public String test3(HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); String name = request.getParameter("name"); Integer age = null == request.getParameter("age") ? 0 : Integer.parseInt(request.getParameter("age")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式——但是经过实测发现,当通过request.getParameter("xxx")方式去获取入参时,则只有请示方式是POST PUT DELETE的时候,后端代码才能获取到入参!而当请求方式为GET 的时候,后端获取入参失败。
下面是示例

GET,传参失败

在这里插入图片描述
获取不到入参!

POST PUT DELETE 传参成功

为了节约文章篇幅,下面只以POST 请求方式的调用结果为例,看是否可以在controller代码中获取到调用方传过来的实参。
在这里插入图片描述
可以看到,可以获取到参数!

3.2.4 接口定义方式4:用Map接收参数

  • 定义方式: 在方法形参的位置,用Map来接收入参,并且,map前面一定要加上RequestParam注解,否则map也拿不到入参!
  • 兼容的请求方式POST PUT DELETE注意,不兼容GET请示方式
  • 适用场景:由于当请求的Content-Type=application/x-www-form-urlencoded时,只支持POST PUT DELETE请求方式, 但是这种方式对于入参的获取校验处理也很麻烦,所以一般不用这种方式来接收Content-Type=application/x-www-form-urlencoded的请求
  • 优点:麻烦,没啥优点
  • 缺点:获取并处理校验入参很麻烦
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form_urlencoded") public class TestFormUrlEncodeController { 
       / * <p>不支持GET请求类型</p> * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=application/x-www-form-urlencoded * <li><b>定义方式</b>: 在方法形参的位置,用Map来接收入参,并且,map前面一定要加上{@link RequestParam}注解,否则map也拿不到入参!</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=application/x-www-form-urlencoded</li> * <li><b>兼容的请求方式</b>:POST PUT DELETE</li> * <li><b>适用场景</b>:由于当请求的Content-Type=application/x-www-form-urlencoded时,只支持POST PUT DELETE请求方式, * 但是这种方式对于入参的获取校验处理也很麻烦,所以一般不用这种方式来接收Content-Type=application/x-www-form-urlencoded的请求</li> * <li><b>优点</b>:麻烦,没啥优点</li> * <li><b>缺点</b>:获取并处理校验入参很麻烦</li> * </ul> */ @RequestMapping(value = "/test4_map") public String test4(@RequestParam Map<String, String> paramMap, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); String name = paramMap.get("name"); // 判断:如果paramMap.get("age")为null,则age赋默认值0;否则进行入参类型的转换 Integer age = null == paramMap.get("age") ? 0: Integer.parseInt(paramMap.get("age")); return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age; } } 
调用case

请求方式GET无法将参数传给后端,下面以直接以PUT请求方式作为示例
在这里插入图片描述
可以看到,可以获取到入参

3.2.5 (error)接口定义方式5:每个参数都平铺开来,并尝试获取File文件入参

先说结论,虽然在下面方法定义的,=形参中添加了MultipartFile,但是如果调用接口的时候入参类型是Content-Type=application/x-www-form-urlencoded, 那由于Content-Type=application/x-www-form-urlencoded入参类型限制了入参就无法将【文件】传过来,所以该方法的MultipartFile对象始终为空!

  • 定义方式: 方法形参的位置,把每个参数都平铺开来,也可以使用@RequestParam注解,是时尝试使用MultipartFile类型入参,去接收文件
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form_urlencoded") public class TestFormUrlEncodeController { 
       / * <p> * 虽然在方法定义这里,形参中添加了MultipartFile,但是如果调用接口的时候入参类型是Content-Type=application/x-www-form-urlencoded, * 那由于Content-Type=application/x-www-form-urlencoded入参类型限制了入参就无法将【文件】传过来,所以该方法的MultipartFile对象始终为空! * </p> * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=application/x-www-form-urlencoded * <li><b>定义方式</b>: 在方法形参的位置,把每个参数都平铺开来</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=application/x-www-form-urlencoded</li> * </ul> */ @RequestMapping(value = "/test5_requestparam_file") public String test5(String name, Integer age, Boolean enable, MultipartFile myfile, HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); String fileName = null; if (null != myfile) { 
       fileName = myfile.getOriginalFilename(); } return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age + ", enable = " + enable + ", fileName = " + fileName; } } 
调用case

3.3 form-data

x-www-form-urlencodedform-data它们两个的区别在上面已经说过了,这里不再赘述。
其实form-data这种入参方式,对应的接口的定义方式,跟x-www-form-urlencoded几乎是一样的。

3.3.1 接口定义方式1:在方法形参的位置,把每个参数都平铺开来

  • 定义方式: 方法形参的位置,把每个参数都平铺开来,也可以使用@RequestParam注解
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:虽然这种传参方式,适用于POST PUT DELETE等请求方式,但是一般偏向于应用在 用POSTPUT方式去发送的表单数据,且参数个数少的情形
  • 优点:方便简单
  • 缺点:参数个数如果过多,方法体结构会显得很臃肿,获取文件类型入参也很麻烦
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form") public class TestFormUrlEncodeController { 
       / * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=multipart/form-data * <li><b>定义方式</b>: 在方法形参的位置,把每个参数都平铺开来(文件类型也平铺开来)</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=multipart/form-data</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:虽然这种传参方式,适用于GET POST PUT DELETE等请求方式,但是一般偏向于应用在 用<b>POST</b>或b>PUT</b>方式去发送的表单数据,且参数个数少</li> * <li><b>优点</b>:方便简单</li> * <li><b>缺点</b>:1)参数个数如果过多,方法体结构会显得很臃肿,获取文件类型入参也很麻烦</li> * </ul> */ @RequestMapping(value = "/test1_requestparam") public String test1(String name, @RequestParam(name = "age", required = false) Integer age, Boolean enable, MultipartFile myfile, HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); StringBuilder sb = new StringBuilder(); // 文件处理(如果上传的文件不为空,则把文件的第一行读取出来,放在接口返回结果中) if (null != myfile) { 
       String fileName = myfile.getOriginalFilename(); sb.append(" fileName = ").append(fileName); ArrayList<String> dataList = IoUtil.readLines(myfile.getInputStream(), "UTF8", new ArrayList<String>()); Optional<String> firstLineOpt = dataList.stream().findFirst(); if (firstLineOpt.isPresent()) { 
       sb.append(", firstLine = " + firstLineOpt.get()); } } return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age + ", enable = " + enable + ", ===> 【fileDetail】: " + sb.toString(); } } 
调用case

注意看上面这个/param_type/body_form_urlencoded/test1_requestparam接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以POST请求作为示例
在这里插入图片描述
可以看到,参数都获取到了。

3.3.2 接口定义方式2:把入参封装到一个实体中

  • 定义方式: 把入参封装到一个实体中,并且形参定义那里,一定不能使用RequestParamRequestBody修饰,否则调用方无法传参
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:虽然这种传参方式,适用于GET POST PUT DELETE等请求方式,但是一般偏向于应用在 用POST PUT方式去发送的表单数据,且表单字段有可能有File文件
  • 优点:方便简单,不管表单字段个数多或少,都可以使用这种方式,一般也是推荐使用这种方式去接收form-data表单数据
  • 缺点:没啥缺点
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form") public class TestFormUrlEncodeController { 
       / * <p>形参定义那里,一定不能使用{@link RequestParam}或{@link RequestBody}修饰,否则调用方无法传参</p> * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=multipart/form-data * <li><b>定义方式</b>: 把入参封装到一个实体中(入参个数多于5个时一般用这种方式)</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=multipart/form-data</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:虽然这种传参方式,适用于GET POST PUT DELETE等请求方式,但是一般偏向于应用在 用<b>POST</b>或<b>PUT</b>方式去发送的表单数据,且表单字段有可能有File文件</li> * <li><b>优点</b>:方便简单,不管表单字段个个数多或少,都可以使用这种方式</li> * <li><b>缺点</b>:没啥缺点</li> * </ul> */ @RequestMapping(value = "/test2_entity") public String test2(StudentDTO studentDTO, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! studentDTO = " + studentDTO; } } 

其中StudentDTO 类的代码如下:

注意下面代码中重写了toString方法,方便把文件名称给输出出来

package com.su.demo.bean.dto; import lombok.Data; import org.springframework.web.multipart.MultipartFile; import java.util.Arrays; @Data public class StudentDTO { 
       / * 姓名 */ private String name; / * 年龄 */ private Integer age; / * 附件 */ private MultipartFile[] myfile; @Override public String toString() { 
       StringBuilder sb = new StringBuilder(); if (null != myfile) { 
       Arrays.stream(myfile) .forEach(multipartFile -> sb.append(", fileName = ").append(multipartFile.getOriginalFilename())); } return "StudentDTO{" + "name='" + name + '\'' + ", age=" + age + ", 【fileDetail】: " + sb.toString() + '}'; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以PUT请求作为示例
在这里插入图片描述

可以看到,参数都获取到了。

3.3.3 接口定义方式3:在方法形参的位置,用HttpServletRequest来接收入参

  • 定义方式: 在方法形参的位置,用HttpServletRequest来接收入参
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:从技术上来说,它支持GET POST、PUT、DELETE等请求方式发送的Content-Type=multipart/data-form的http请求。但是这种方式获取参数真的很麻烦,不太推荐使用
  • 优点:没啥优点
  • 缺点:需要自己在代码中显式的从request中去取数据(尤其文件),很麻烦
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form") public class TestFormUrlEncodeController { 
       / * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=multipart/data-form * <li><b>定义方式</b>: 在方法形参的位置,用{@link HttpServletRequest}来接收入参</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=multipart/data-form</li> * <li><b>兼容的请求方式</b>:GET POST、PUT、DELETE</li> * <li><b>适用场景</b>:从技术上来说,它支持GET POST、PUT、DELETE等请求方式发送的Content-Type=multipart/data-form的http请求。但是这种方式获取参数真的很麻烦,不太推荐使用</li> * <li><b>优点</b>:没啥优点</li> * <li><b>缺点</b>:需要自己在代码中显式的从request中去取数据(尤其文件),很麻烦</li> * </ul> */ @RequestMapping(value = "/test3_request") public String test3(HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); // [注]:直接从request.getInputStream()中是无法获取数据的,只能通过request.getParameter("xxx")的方式去获取 String name = request.getParameter("name"); Integer age = null == request.getParameter("age") ? 0 : Integer.parseInt(request.getParameter("age")); // 获取文件 StringBuilder sb = new StringBuilder(); MultiValueMap<String, MultipartFile> multiFileMap = ((StandardMultipartHttpServletRequest) request).getMultiFileMap(); if (!CollectionUtils.isEmpty(multiFileMap)) { 
       List<MultipartFile> multipartFileList = multiFileMap.get("myfile"); if (!CollectionUtils.isEmpty(multipartFileList)) { 
       for (MultipartFile multipartFile : multipartFileList) { 
       sb.append(" , fileName = ").append(multipartFile.getOriginalFilename()); } } } return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age + ", 【fileDetail】: " + sb.toString(); } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以GET请求作为示例
在这里插入图片描述
可以看到,参数都获取到了。

3.3.4 接口定义方式4:用Map来接收入参

  • 定义方式: 在方法形参的位置,用Map来接收入参,并且,map前面一定要加上RequestParam注解,否则map也拿不到入参!
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:从技术上来说,它支持GET POST PUT DELETE等请求方式发送的Content-Type=multipart/data-form的http请求。但是这种方式获取参数真的很麻烦,不太推荐使用
  • 优点:没啥优点
  • 缺点:需要自己在代码中显式的从request中去取数据(尤其文件),很麻烦
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.TeacherDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.util.Map; @RestController @RequestMapping(value = "/param_type/body_form") public class TestFormUrlEncodeController { 
       / * <ul> * <li><b>入参类别</b>:表单参数方式,Content-Type=application/x-www-form-urlencoded * <li><b>定义方式</b>: 在方法形参的位置,用Map来接收入参,并且,map前面一定要加上{@link RequestParam}注解,否则map也拿不到入参!</li> * <li><b>调用方式</b>: 入参放在表单中,且Content-Type=application/x-www-form-urlencoded</li> * <li><b>兼容的请求方式</b>:GET POST、PUT、DELETE</li> * <li><b>适用场景</b>:从技术上来说,它支持GET POST、PUT、DELETE等请求方式发送的Content-Type=multipart/data-form的http请求。但是这种方式获取参数真的很麻烦,不太推荐使用</li> * <li><b>优点</b>:没啥优点</li> * <li><b>缺点</b>:需要自己在代码中显式的从request中去取数据(尤其文件),很麻烦</li> * </ul> */ @RequestMapping(value = "/test4_map") public String test4(@RequestParam Map<String, Object> paramMap, HttpServletRequest request) { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); String name = (String) paramMap.get("name"); // 判断:如果paramMap.get("age")为null,则age赋默认值0;否则进行入参类型的转换 Integer age = null == paramMap.get("age") ? 0: Integer.parseInt((String) paramMap.get("age")); // map中是没有办法获取文件的,只能再从request中去获取(可以看到,获取的代码写的很麻烦) StringBuilder sb = new StringBuilder(); MultiValueMap<String, MultipartFile> multiFileMap = ((StandardMultipartHttpServletRequest) request).getMultiFileMap(); if (!CollectionUtils.isEmpty(multiFileMap)) { 
       List<MultipartFile> multipartFileList = multiFileMap.get("myfile"); if (!CollectionUtils.isEmpty(multipartFileList)) { 
       for (MultipartFile multipartFile : multipartFileList) { 
       sb.append(" , fileName = ").append(multipartFile.getOriginalFilename()); } } } return requestMetaInfo + " ---> SUCCESS! name = " + name + ", age = " + age + ", 【fileDetail】: " + sb.toString(); } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以DELETE请求作为示例
在这里插入图片描述
可以看到,参数都获取到了。

3.4 xml

这种入参方式,入参是xml格式的,且放在http请求的请求体当中,并且在发起http请求时Content-Type=application/xml。 xml格式内容如下所示:

<?xml version="1.0" encoding="UTF-8"?> <bookDTO> <name>三国演义</name> <price>66</price> </bookDTO> 

由于Content-Type=application/xml这种传参方式我平日没有使用过,所以这里示例用的xml格式比较简单

3.4.1 接口定义方式1:用一个实体接收入参

  • 定义方式: 用一个实体接收入参,且注意实体使用了@XmlRootElement注解进行标注
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:需要接收xml类型内容的场景
  • 优点:方便简单, xml内容直接映射到实体里面
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.BookDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @RestController @RequestMapping(value = "/param_type/xml") public class TestXmlController { 
       / * <ul> * <li><b>入参类别</b>:xml格式的内容,放在body中进行传参 * <li><b>定义方式</b>: 用一个实体接收入参</li> * <li><b>调用方式</b>: xml内容放在请求的body中,且Content-Type=application/xml</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:需要接收xml类型内容的场景</li> * <li><b>优点</b>:方便简单, xml内容直接映射到实体里面</li> * <li><b>缺点</b>:</li> * </ul> */ @RequestMapping(value = "/test1_entity") public String test1(@RequestBody BookDTO bookDTO, HttpServletRequest request){ 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! userDTO = " + bookDTO; } } 

其中,BookDTO的代码如下所示,注意它使用了@XmlRootElement注解

package com.su.demo.bean.dto; import lombok.Data; import javax.xml.bind.annotation.XmlRootElement; @Data @XmlRootElement public class BookDTO { 
       private String name; private Double price; } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以POST请求作为示例
在这里插入图片描述
可以看到,参数都获取到了。

3.4.2 接口定义方式2:用原生的HttpServletRequest接收

  • 定义方式: 在方式形参的位置,用原生的HttpServletRequest接收
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:需要接收xml类型内容的场景
  • 优点:直接通过request.getInputStream()的方式,可以以String形式获取到全部的xml的内容,之后代码在爱咋解析就咋解析。
  • 缺点:后续的解析也是个麻烦……
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.BookDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @RestController @RequestMapping(value = "/param_type/xml") public class TestXmlController { 
       / * <ul> * <li><b>入参类别</b>:xml格式的内容,放在body中进行传参数 * <li><b>定义方式</b>: 在方式形参的位置,用原生的{@link HttpServletRequest}接收 * <li><b>调用方式</b>: 参数放在请求体 body 当中 * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:需要接收xml类型内容的场景</li> * <li><b>优点</b>:{@link HttpServletRequest}是整个请求,可以获取到所有的数据.且HttpServletRequest、HttpServletResponse都是内置对象,可以使用</li> * <li><b>缺点</b>:代码中再去从request中拿到参数,老麻烦,可以看下面的代码</li> * </ul> */ @RequestMapping(value = "/test2_request") public String test2(HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); ServletInputStream inputStream = request.getInputStream(); // 用hutool工具包的read方式,将inputStream读取成string String body = IoUtil.read(inputStream, "UTF-8"); System.out.println("body = " + body); // 拿到body之后,可以再自行进行xml格式的解析,并从中获取数据 return requestMetaInfo + " ---> SUCCESS! input body = " + body; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以POST请求作为示例
在这里插入图片描述

可以看到,参数都获取到了。

(error)3.4.3 接口定义方式3:用原生的HttpServletRequest接收

提前说明,这种定义方式,是无法获取到Content-Type=application/xml的body参数的!

  • 定义方式: 在方法形参的位置,把每个参数都平铺开来
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import com.su.demo.bean.dto.BookDTO; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @RestController @RequestMapping(value = "/param_type/xml") public class TestXmlController { 
       / * <p>这种接口定义方式,接收不到Content-Type=application/xml的body参数</p> * <ul> * <li><b>入参类别</b>:xml格式的内容,放在body中进行传参数 * <li><b>定义方式</b>: 在方法形参的位置,把每个参数都平铺开来 * <li><b>调用方式</b>: xml格式的内容,放在请求体 body 当中,且Content-Type=application/xml * </ul> */ @RequestMapping(value = "/test3_query") public String test3(String name, @RequestParam(value = "price", required = false) Double price, HttpServletRequest request){ 
       return "name = " + name + ", price = " + price; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式。但是实测发现,无论使用哪种请求方式,后端都获取不到入参!下面只以POST请求作为示例
在这里插入图片描述
可以看到,参数获取不到。

3.5 raw

raw原始类型,可以上传任意格式的文本,比如 text、json、xml、html等。

3.5.1 接口定义方式1:用@RequestBody接收

  • 定义方式: 用@RequestBody和String类型入参接收参数
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:任意格式的【文本】内容,放在请求体 body 当中,且Content-Type=text/plain
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.nio.charset.StandardCharsets; @RestController @RequestMapping(value = "/param_type/raw") public class TestRawController { 
       / * <ul> * <li><b>入参类别</b>:任意格式的【文本】,比如 text、json、xml、html等,x放在body中进行传参数 * <li><b>定义方式</b>: 用{@link RequestBody}和String类型入参接收参数</li> * <li><b>调用方式</b>: 任意格式的【文本】内容,放在请求体 body 当中,且Content-Type=text/plain * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:任意格式的【文本】内容,放在请求体 body 当中,且Content-Type=text/plain</li> * </ul> */ @RequestMapping("/test1_requestbody") public String test1(@RequestBody String body, HttpServletRequest request){ 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! input body = " + body; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以POST请求作为示例
在这里插入图片描述

可以看到,参数获取到了。

3.5.2 接口定义方式2:用原生的HttpServletRequest接收

  • 定义方式: 用原生的HttpServletRequest接收参数
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:任意格式的【文本】内容,放在请求体 body 当中,且Content-Type=text/plain
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.nio.charset.StandardCharsets; @RestController @RequestMapping(value = "/param_type/raw") public class TestRawController { 
       / * <ul> * <li><b>入参类别</b>:任意格式的【文本】,比如 text、json、xml、html等,x放在body中进行传参数 * <li><b>定义方式</b>: 用原生的{@link HttpServletRequest}接收参数</li> * <li><b>调用方式</b>: 任意格式的【文本】内容,放在请求体 body 当中,且Content-Type=text/plain * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:任意格式的【文本】</li> * </ul> */ @RequestMapping("/test2_request") public String test2(HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); ServletInputStream inputStream = request.getInputStream(); // 用hutool工具包的read方式,将inputStream读取成string String body = IoUtil.read(inputStream, StandardCharsets.UTF_8); System.out.println("body = " + body); // 拿到body之后,可以再自行进行xml格式的解析,并从中获取数据 return requestMetaInfo + " ---> SUCCESS! input body = " + body; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以PUT请求作为示例
在这里插入图片描述
可以看到,参数获取到了。

3.6 binary

binary,对应着http请求中的Content-Type:application/octet-stream,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件

3.6.1 接口定义方式1:用@RequestBody接收

  • 定义方式: 用@RequestBody和String类型入参接收参数
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:http请求中的Content-Type:application/octet-stream,上传二进制数据
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.nio.charset.StandardCharsets; @RestController @RequestMapping(value = "/param_type/binary") public class TestBinaryController { 
       / * <ul> * <li><b>入参类别</b>:对应着http请求中的Content-Type:application/octet-stream,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件</li> * <li><b>定义方式</b>: 用{@link RequestBody}和String类型入参接收参数</li> * <li><b>调用方式</b>: http请求中的Content-Type:application/octet-stream,上传二进制数据</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:http请求中的Content-Type:application/octet-stream,上传二进制数据</li> * </ul> */ @RequestMapping("/test1_requestbody") public String test1(@RequestBody String body, HttpServletRequest request){ 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); return requestMetaInfo + " ---> SUCCESS! input body = " + body; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以POST请求作为示例
在这里插入图片描述
可以看到,参数获取到了。

3.6.2 接口定义方式2:用原生的HttpServletRequest接收

  • 定义方式: 用原生的HttpServletRequest接收参数
  • 兼容的请求方式GET POST PUT DELETE
  • 适用场景:http请求中的Content-Type:application/octet-stream,上传二进制数据
代码
package com.su.demo.controller.param_type; import cn.hutool.core.io.IoUtil; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.nio.charset.StandardCharsets; @RestController @RequestMapping(value = "/param_type/binary") public class TestBinaryController { 
       / * <ul> * <li><b>入参类别</b>:对应着http请求中的Content-Type:application/octet-stream,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件</li> * <li><b>定义方式</b>: 用{@link RequestBody}和String类型入参接收参数</li> * <li><b>调用方式</b>: http请求中的Content-Type:application/octet-stream,上传二进制数据</li> * <li><b>兼容的请求方式</b>:GET POST PUT DELETE</li> * <li><b>适用场景</b>:http请求中的Content-Type:application/octet-stream,上传二进制数据</li> * </ul> */ @RequestMapping("/test2_request") public String test2(HttpServletRequest request) throws IOException { 
       // 从request中获取一些接口请求时的元数据信息,包括请求方式,Content-type等 String requestMetaInfo = String.format("method: [%s], uri: [%s], Content-Type: [%s] ", request.getMethod(), request.getRequestURI(), request.getHeader("Content-Type")); ServletInputStream inputStream = request.getInputStream(); // 用hutool工具包的read方式,将inputStream读取成string String body = IoUtil.read(inputStream, StandardCharsets.UTF_8); System.out.println("body = " + body); // 拿到body之后,可以再自行进行xml格式的解析,并从中获取数据 return requestMetaInfo + " ---> SUCCESS! input body = " + body; } } 
调用case

注意看上面这个接口的定义方式,它并没有指定请求方式,因此它支持GET POST PUT DELETE等所有的请求方式(已经过验证)。为节约篇幅,下面只以POST请求作为示例
在这里插入图片描述

可以看到,参数获取到了。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/130298.html

(0)
上一篇 2025-08-18 12:33
下一篇 2025-08-18 12:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信