作為一個常年提供各種Http接口的后端而言,如何獲取請求參數可以說是一項基本技能了,本篇為《190824-SpringBoot系列教程web篇之Get請求參數解析姿勢匯總》之后的第二篇,對於POST請求方式下,又可以怎樣獲取請求參數呢
本篇主要內容包括以下幾種姿勢
- @RequestBody json格式
- RequestEntity
- MultipartFile 文件上傳
I. 環境搭建
首先得搭建一個web應用才有可能繼續后續的測試,借助SpringBoot搭建一個web應用屬於比較簡單的活;
創建一個maven項目,pom文件如下
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7</version>
<relativePath/> <!-- lookup parent from update -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
添加項目啟動類Application.cass
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
在演示請求參數的解析實例中,我們使用終端的curl命令來發起http請求(主要原因是截圖上傳太麻煩,還是終端的文本輸出比較方便;缺點是不太直觀)
II. POST請求參數解析
接下來我們正式進入參數解析的妖嬈姿勢篇,會介紹一下常見的一些case(並不能說包含了所有的使用case)
下面所有的方法都放在 ParamPostRest
這個Controller中
@RestController
@RequestMapping(path = "post")
public class ParamPostRest {
}
在正式介紹之前,強烈推薦看一下《190824-SpringBoot系列教程web篇之Get請求參數解析姿勢匯總》, 因為get傳參的姿勢,在post參數解析中同樣適用,下面的內容並不會再次詳細介紹
1. HttpServletRequest
首先看一下最基本的使用case,和get請求里的case一樣,我們先開一個接口
@PostMapping(path = "req")
public String requestParam(HttpServletRequest req) {
return JSONObject.toJSONString(req.getParameterMap());
}
我們測試下兩種post請求下,會出現怎樣的結果
# 常規的表單提交方式
# content-type: application/x-www-form-urlencoded
➜ ~ curl 'http://127.0.0.1:8080/post/req' -X POST -d 'name=yihui&age=18'
{"name":["yihui"],"age":["18"]}%
# json傳提交
➜ ~ curl 'http://127.0.0.1:8080/post/req' -X POST -H 'content-type:application/json;charset:UTF-8' -d '{"name": "yihui", "age": 20}'
{}%
從上面的case中可以知道,通過傳統的表達方式提交的數據時,獲取參數和get獲取參數使用姿勢一樣;然而當然傳入的是json串格式的數據時,直接通過javax.servlet.ServletRequest#getParameter
獲取不到對應的參數
我們通過debug,來看一下在傳json串數據的時候,如果我們要獲取數據,可以怎么做
上面截圖演示了我們從請求的InputStream中獲取post參數;所以再實際使用的時候需要注意,流中的數據只能讀一次,讀完了就沒了; 這個和我們使用GET傳參是有很大的差別的
注意:如果您有一個打印請求參數日志的切面,在獲取post傳的參數時需要注意,是不是把流的數據讀了,導致業務中無法獲取到正確的數據!!!
2. RequestBody
上面說到傳json串數據時,后端直接通過HttpServletRequest
獲取數據不太方便,那么有更優雅的使用姿勢么?下面我們看一下@RequestBody
注解的使用
@Data
public class BaseReqDO implements Serializable {
private static final long serialVersionUID = 8706843673978981262L;
private String name;
private Integer age;
private List<Integer> uIds;
}
@PostMapping(path = "body")
public String bodyParam(@RequestBody BaseReqDO req) {
return req == null ? "null" : req.toString();
}
只需要在參數中添加@RequestBody
注解即可,然后這個接口就支持json串的POST提交了
# json串數據提交
➜ ~ curl 'http://127.0.0.1:8080/post/body' -X POST -H 'content-type:application/json;charset:UTF-8' -d '{"name": "yihui", "age": 20}'
BaseReqDO(name=yihui, age=20, uIds=null)%
# 表單數據提交
➜ ~ curl 'http://127.0.0.1:8080/post/body' -X POST -d 'name=yihui&age=20'
{"timestamp":1566987651551,"status":415,"error":"Unsupported Media Type","message":"Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported","path":"/post/body"}%
說明:使用@RequestBody
注解之后,可解析提交的json串;但不再支持表單提交參數方式(application/x-www-form-urlencoded
)
3. RequestEntity
使用RequestEntity來解析參數,可能並不太常見,它用來解析json串提交的參數也比較合適,使用姿勢也比較簡單
@PostMapping(path = "entity")
public String entityParam(RequestEntity requestEntity) {
return Objects.requireNonNull(requestEntity.getBody()).toString();
}
使用case如下
# json串數據提交
➜ ~ curl 'http://127.0.0.1:8080/post/entity' -X POST -H 'content-type:application/json;charset:UTF-8' -d '{"name": "yihui", "age": 20}'
{name=yihui, age=20}%
# 表單數據提交不行
➜ ~ curl 'http://127.0.0.1:8080/post/entity' -X POST -d 'name=yihui&age=19'
{"timestamp":1566988137298,"status":415,"error":"Unsupported Media Type","message":"Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported","path":"/post/entity"}%
4. MultipartFile 文件上傳
文件上傳也是一個比較常見的,支持起來也比較簡單,有兩種方式,一個是使用MultipartHttpServletRequest參數來獲取上傳的文件;一個是借助 @RequestParam
注解
private String getMsg(MultipartFile file) {
String ans = null;
try {
ans = file.getName() + " = " + new String(file.getBytes(), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
System.out.println(ans);
return ans;
}
/**
* 文件上傳
*
* curl 'http://127.0.0.1:8080/post/file' -X POST -F 'file=@hello.txt'
*
* @param file
* @return
*/
@PostMapping(path = "file")
public String fileParam(@RequestParam("file") MultipartFile file) {
return getMsg(file);
}
@PostMapping(path = "file2")
public String fileParam2(MultipartHttpServletRequest request) {
MultipartFile file = request.getFile("file");
return getMsg(file);
}
測試case如下
# 創建一個文本文件
➜ ~ vim hello.txt
hello, this is yhh's spring test!
# 使用curl -F 實現文件上傳,注意使用姿勢
➜ ~ curl 'http://127.0.0.1:8080/post/file' -F 'file=@hello.txt'
file = hello, this is yhh's spring test!
➜ ~ curl 'http://127.0.0.1:8080/post/file2' -F 'file=@hello.txt'
file = hello, this is yhh's spring test!
5. 其他
上面介紹的幾種有別於GET篇中的請求姿勢,請注意GET請求參數的解析方式,在POST請求中,可能也是適用的,為什么說可能?因為在post請求中,不同的content-type
,對參數的解析影響還是有的;
需要注意的是,對於傳統的表單提交(application/x-www-form-urlencoded)方式,post的參數解析依然可以使用
- @RequsetParam
- POJO(BEAN的解析方式)
- @PathVariable參數解析
- 方法參數解析
II. 其他
0. 項目&相關博文
- 190824-SpringBoot系列教程web篇之Get請求參數解析姿勢匯總
- 工程:https://github.com/liuyueyi/spring-boot-demo
- 項目: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/202-web-params
1. 一灰灰Blog
盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
下面一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛
- 一灰灰Blog個人博客 https://blog.hhui.top
- 一灰灰Blog-Spring專題博客 http://spring.hhui.top