
**注意:本節內容需要結合2.2.2小節的內容聯合起來一起看,然后理解**
## 一、HTTP協議的四種傳參方式
|HTTP協議組成|協議內容示例|對應Spring注解|
|------|----|-----|
|path info傳參|/articles/12 (查詢id為12的文章,12是參數)|@PathVariable|
|URL Query String傳參|/articles?id=12|@RequestParam|
|Body 傳參|Content-Type: multipart/form-data|@RequestParam|
|Body 傳參|Content-Type: application/json,或其他自定義格式|@RequestBody|
|Headers 傳參|| @RequestHeader|
## 二、常用注解回顧
### 2.1 @RequestBody與@ResponseBody
```
//注意并不要求@RequestBody與@ResponseBody成對使用。
public @ResponseBody AjaxResponse saveArticle(@RequestBody ArticleVO article)
```
如上代碼所示:
* @RequestBody修飾請求參數,注解用于接收HTTP的body,默認是使用JSON的格式
* @ResponseBody修飾返回值,注解用于在HTTP的body中攜帶響應數據,默認是使用JSON的格式。如果不加該注解,spring響應字符串類型,是跳轉到模板頁面或jsp頁面的開發模式。說白了:加上這個注解你開發的是一個數據接口,不加這個注解你開發的是一個頁面跳轉控制器。

在使用@ResponseBody注解之后程序不會再走視圖解析器,也就不再做html視圖渲染,而是直接將對象以數據的形式(默認JSON)返回給請求發送者。那么我們有一個問題:如果我們想接收或XML數據該怎么辦?我們想響應excel的數據格式該怎么辦?我們后文來回答這個問題。
### 2.2. @RequestMapping注解
@RequestMapping注解是所有常用注解中,最有看點的一個注解,用于標注HTTP服務端點。它的很多屬性對于豐富我們的應用開發方式方法,都有很重要的作用。如:
* value: 應用請求端點,最核心的屬性,用于標志請求處理方法的唯一性;
* method: HTTP協議的method類型, 如:GET、POST、PUT、DELETE等;
* consumes: HTTP協議請求內容的數據類型(Content-Type),例如application/json, text/html;
* produces: HTTP協議響應內容的數據類型。下文會詳細講解。
* params: HTTP請求中必須包含某些參數值的時候,才允許被注解標注的方法處理請求。
* headers: HTTP請求中必須包含某些指定的header值,才允許被注解標注的方法處理請求。
```
@RequestMapping(value = "/article", method = POST)
@PostMapping(value = "/article")
```
上面代碼中兩種寫法起到的是一樣的效果,也就是PostMapping等同于@RequestMapping的method等于POST。同理:@GetMapping、@PutMapping、@DeleteMapping也都是簡寫的方式。
### 2.3. @RestController與@Controller
@Controller注解是開發中最常使用的注解,它的作用有兩層含義:
* 一是告訴Spring,被該注解標注的類是一個Spring的Bean,需要被注入到Spring的上下文環境中。
* 二是該類里面所有被RequestMapping標注的注解都是HTTP服務端點。
@RestController相當于 @Controller和@ResponseBody結合。它有兩層含義:
* 一是作為Controller的作用,將控制器類注入到Spring上下文環境,該類RequestMapping標注方法為HTTP服務端點。
* 二是作為ResponseBody的作用,請求響應默認使用的序列化方式是JSON,而不是跳轉到jsp或模板頁面。
### 2.4. @PathVariable 與@RequestParam
PathVariable用于URI上的{參數},如下方法用于刪除一篇文章,其中id為文章id。如:我們的請求URL為“/article/1”,那么將匹配DeleteMapping并且PathVariable接收參數id=1。而RequestParam用于接收普通表單方式或者ajax模擬表單提交的參數數據。
```
@DeleteMapping("/article/{id}")
public @ResponseBody AjaxResponse deleteArticle(@PathVariable Long id) {
@PostMapping("/article")
public @ResponseBody AjaxResponse deleteArticle(@RequestParam Long id) {
```
## 二、接收復雜嵌套對象參數
有一些朋友可能還無法理解RequestBody注解存在的真正意義,表單數據提交用RequestParam就好了,為什么還要搞出來一個RequestBody注解呢?RequestBody注解的真正意義在于能夠使用對象或者嵌套對象接收前端數據。

仔細看上面的代碼,是一個paramData對象里面包含了一個bestFriend對象。這種數據結構使用RequestParam就無法接收了,RequestParam只能接收平面的、一對一的參數。像上文中這種數據結構的參數,就需要我們在java服務端定義兩個類,一個類是ParamData,一個類是BestFriend.
```
public class ParamData {
private String name;
private int id;
private String phone;
private BestFriend bestFriend;
public static class BestFriend {
private String address;
private String sex;
}
}
```
* 注意上面代碼中省略了GET、SET方法等必要的java plain model元素。
* 注意成員變量名稱一定要和JSON屬性名稱對應上。
* 注意接收不同類型的參數,使用不同的成員變量類型
完成以上動作,我們就可以使用`@RequestBody ParamData paramData`,一次性的接收以上所有的復雜嵌套對象參數了,參數對象的所有屬性都將被賦值。
## 三、Http數據轉換的原理
大家現在使用JSON都比較普遍了,其方便易用、表達能力強,是絕大部分數據接口式應用的首選。那么如何響應其他的類型的數據?其中的判別原理又是什么?下面就來給大家介紹一下:

* 當一個HTTP請求到達時是一個InputStream,通過HttpMessageConverter轉換為java對象,從而進行參數接收。
* 當對一個HTTP請求進行響應時,我們首先輸出的是一個java對象,然后由HttpMessageConverter轉換為OutputStream輸出。
當我們在Spring Boot應用中集成了jackson的類庫之后,如下的一些HttpMessageConverter將會被加載。
|實現類|功能說明|
|---|---|
|StringHttpMessageConverter|將請求信息轉為字符串|
|FormHttpMessageConverter|將表單數據讀取到MultiValueMap中|
|XmlAwareFormHttpMessageConverter|擴展與FormHttpMessageConverter,如果部分表單屬性是XML數據,可用該轉換器進行讀取|
|ResourceHttpMessageConverter|讀寫org.springframework.core.io.Resource對象|
|BufferedImageHttpMessageConverter|讀寫BufferedImage對象|
|ByteArrayHttpMessageConverter|讀寫二進制數據|
|SourceHttpMessageConverter|讀寫java.xml.transform.Source類型的對象|
|MarshallingHttpMessageConverter|通過Spring的org.springframework,xml.Marshaller和Unmarshaller讀寫XML消息|
|Jaxb2RootElementHttpMessageConverter|通過JAXB2讀寫XML消息,將請求消息轉換為標注的XmlRootElement和XmlType連接的類中|
|MappingJacksonHttpMessageConverter|利用Jackson開源包的ObjectMapper讀寫JSON數據|
|RssChannelHttpMessageConverter|讀寫RSS種子消息|
|AtomFeedHttpMessageConverter|和RssChannelHttpMessageConverter能夠讀寫RSS種子消息|
根據HTTP協議的Accept和Content-Type屬性,以及參數數據類型來判別使用哪一種HttpMessageConverter。當使用RequestBody或ResponseBody時,再結合前端發送的Accept數據類型,會自動判定優先使用MappingJacksonHttpMessageConverter作為數據轉換器。但是,不僅JSON可以表達對象數據類型,XML也可以。如果我們希望使用XML格式該怎么告知Spring呢,那就要使用到produces屬性了。
```
@GetMapping(value ="/demo",produces = MediaType.APPLICATION_XML_VALUE)
```
這里我們明確的告知了返回的數據類型是xml,就會使用Jaxb2RootElementHttpMessageConverter作為默認的數據轉換器。當然實現XML數據響應比JSON還會更復雜一些,還需要結合@XmlRootElement、@XmlElement等注解實體類來使用。同理consumes屬性你是不是也會用了呢。
## 四、自定義HttpMessageConverter
其實絕大多數的數據格式都不需要我們自定義HttpMessageConverter,都有第三方類庫可以幫助我們實現(包括下文代碼中的Excel格式)。但有的時候,有些數據的輸出格式并沒有類似于Jackson這種類庫幫助我們處理,需要我們自定義數據格式。該怎么做?
下面我們就以Excel數據格式為例,寫一個自定義的HTTP類型轉換器。實現的效果就是,當我們返回AjaxResponse這種數據類型的話,就自動將AjaxResponse轉成Excel數據響應給客戶端。
~~~
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
~~~
```
@Service
public class ResponseToXlsConverter extends AbstractHttpMessageConverter<AjaxResponse> {
private static final MediaType EXCEL_TYPE = MediaType.valueOf("application/vnd.ms-excel");
ResponseToXlsConverter() {
super(EXCEL_TYPE);
}
@Override
protected AjaxResponse readInternal(final Class<? extends AjaxResponse> clazz,
final HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return null;
}
//針對AjaxResponse類型返回值,使用下面的writeInternal方法進行消息類型轉換
@Override
protected boolean supports(final Class<?> clazz) {
return (AjaxResponse.class == clazz);
}
@Override
protected void writeInternal(final AjaxResponse ajaxResponse, final HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
final Workbook workbook = new HSSFWorkbook();
final Sheet sheet = workbook.createSheet();
final Row row = sheet.createRow(0);
row.createCell(0).setCellValue(ajaxResponse.getMessage());
row.createCell(1).setCellValue(ajaxResponse.getData().toString());
workbook.write(outputMessage.getBody());
}
}
```
* 實現AbstractHttpMessageConverter接口
* 指定該轉換器是針對哪種數據格式的?如上文代碼中的"application/vnd.ms-excel"
* 指定該轉換器針對那些對象數據類型?如上文代碼中的supports函數
* 使用writeInternal對數據進行輸出處理,上例中是輸出為Excel格式。

- 核心內容介紹
- 問題Q&A匯總
- 本文檔已達38萬字
- 聯系作者-代碼工具獲取
- 作者的其他作品推薦
- vue深入淺出系列
- Spring Security-JWT-OAuth2一本通
- 實戰前后端分離RBAC權限管理系統
- 實戰SpringCloud微服務從青銅到王者
- 第一章 spring boot 2.x基礎及概念入門
- 1.1.spring boot 產生的背景及其優勢
- 1.2.helloworld及項目結構介紹
- 1.3.需要先了解的核心概念
- 1.4.提高開發效率必備工具lombok
- 1.5.IDEA環境下的熱加載與熱部署
- 1.6.開發過程中常用IDEA插件
- 第二章 RESTful接口實現與測試
- 2.1.RESTful接口與http協議狀態表述
- 2.2.1.Spring常用注解及基礎講解
- 2.2.2.常用注解開發一個RESTful接口
- 2.2.3.配合前端axios傳參總結
- 2.3.1 JSON數據處理與PostMan測試
- 2.3.2. Jackson全局配置
- 2.4.使用Mockito編碼完成接口測試
- 2.5. 使用Swagger2構建API文檔
- 2.6.接口文檔多種格式導出離線閱讀
- 2.7.Swagger3-即OpenAPI使用
- 第三章 spring boot 配置管理
- 3.1.結合源碼講解bean自動裝配原理
- 3.2.詳解YAML語法及占位符語法
- 3.3.YAML配置綁定變量兩種方式
- 3.4.配置屬性值數據綁定校驗
- 3.5.加載額外配置文件的兩種方式
- 3.6.使用SpEL表達式綁定配置項
- 3.7.profile不同環境使用不同配置
- 3.8.配置及配置文件的加載優先級
- 3.9.配置文件敏感字段加密
- 第四章 整合數據庫開發框架
- 4.1.整合Spring JDBC操作數據
- 4.2 Spring JDBC多數據源的實現
- 4.3.Spring JDBC JTA實現分布式事務
- 4.4.主流ORM持久層框架選型
- 4.5.java bean的賦值轉換
- 4.6.整合Spring Data JPA操作數據
- 4.6.1.SpringDataJPA實現分頁排序
- 4.7.Spring data JPA的多數據源實現
- 4.8.JPA+atomikos實現分布式事務
- 4.9.1.整合MybatisGenerator操作數據
- 4.9.2.整合mybatisPlus操作數據庫
- 4.10.Mybatis開發最佳實踐總結
- 4.11.Spring mybatis的多數據源實現
- 4.12.1.mybatis+atomikos實現分布式事務
- 4.12.2.mybatisplus+atomikos實現分布式事務
- 4.13.Spring事務與分布式事務
- 4.14.一行代碼實現RESTFul接口
- 4.15.一鍵生成數據庫文檔
- 第五章 整合靜態資源與模板引擎
- 5.1.1.webjars與靜態資源
- 5.1.2.訪問jar內部靜態資源
- 5.2.模板引擎選型與未來趨勢
- 5.3.web應用開發之整合jsp
- 5.4.web應用開發之整合freemarker
- 5.5.web應用開發之整合thymeleaf
- 5.6.thymeleaf基礎語法講解
- 5.7.thymeleaf內置對象與工具類
- 5.8.公共片段(標簽)與內聯js
- 第六章 生命周期內的攔截過濾與監聽
- 6.1.Servlet域對象與屬性變化監聽
- 6.2.Servlet過濾器的實現
- 6.3.spring攔截器及請求鏈路說明
- 6.4.自定義事件的發布與監聽
- 6.5.應用啟動的監聽
- 6.6.類初始化監聽
- 第七章 嵌入式容器的配置與應用
- 7.1.嵌入式容器的運行參數配置
- 7.2.為Web容器配置HTTPS
- 7.3.切換到jetty&undertow容器
- 7.4.打war包部署到外置tomcat容器
- 第八章 統一全局異常處理
- 8.1.設計一個優秀的異常處理機制
- 8.2.自定義異常和相關數據結構
- 8.3.通用全局異常處理邏輯
- 8.4.服務端數據校驗異常處理邏輯
- 8.5.AOP完美處理頁面跳轉異常
- 第九章 日志框架與全局日志管理
- 9.1.日志框架的體系結構
- 9.2.logback日志框架配置
- 9.3.1.log4j2日志框架整合與使用
- 9.3.2.log4j2異步日志配置
- 9.4.攔截器實現統一訪問日志
- 第十章 異步任務與定時任務
- 10.1.實現Async異步任務
- 10.2.為異步任務規劃線程池
- 10.3.通過@Scheduled實現定時任務
- 10.4.quartz簡單定時任務(內存持久化)
- 10.5.quartz動態定時任務(數據庫持久化)
- 10.6.可觀測異步任務線程池
- 第十一章 redis緩存與session共享
- 11.1.使用docker安裝redis
- 11.2.redis數據結構與應用場景
- 11.3.單例哨兵及集群模式整合
- 11.4.使用redisTemplate操作數據
- 11.5.使用Redis Repository操作數據
- 11.6.spring cache緩存基本用法
- 11.7.1.詳述緩存聲明式注解的使用
- 11.7.2.EhCache緩存
- 11.8.緩存雪崩穿透等解決方案
- 11.9.集群多節點應用session共享
- 11.10.介紹redis分布式鎖
- 11.11.RedisLockRegistry分布式鎖
- 11.12.使用redisson實現分布式鎖
- 第十二章 整合分布式文件系統
- 12.1.文件本地上傳與提供訪問服務
- 12.2.MinIO簡介與選型介紹
- 12.3.MinIO的安裝與基礎用法
- 12.4.整合MinIO的JavaSDK
- 12.5.fastdfs簡介及架構說明
- 12.6.使用docker安裝fastdfs
- 12.7.開發一個自定義fastdfs-starter
- 12.8.整合fastdfs操作文件數據
- 第十三章 服務器推送技術
- 13.1.主流服務器推送技術說明
- 13.2.服務端推送事件SSE
- 13.3.雙向實時通信websocket
- 第十四章 郵件發送的整合與使用
- 14.1.基礎協議及郵件配置整合
- 14.2.發送html和基于模板的郵件
- 14.3.發送帶附件和內聯附件郵件
- 第十五章 應用程序監控管理
- 15.1.Actuator應用監控快速入門
- 15.2.Actuator服務保護緩存及跨域
- 15.3.SpringBootAdmin界面化監控
- 第十六章 消息隊列的整合與使用
- 16.1.消息隊列與JMS規范簡介
- 16.2.使用docker安裝activeMQ
- 16.3.activeMQ實現點對點隊列
- 16.4.activeMQ實現發布訂閱隊列
- 16.5.docker安裝RocketMQ
- 16.6.RocketMQ實現2種消費模式
- WebFlux文檔遷移的說明
- 番外篇:周邊技術生態
- centos7安裝docker圖文詳解
- docker安裝mongodb(單點)圖文詳解
- 整合Spring data mongodb操作數據
- windows下如何安裝git
- springboot非web項目構建
- 多種方式shutdown應用服務
- SpringBoot-2.2版本的變化
- SpringBoot中如何使用Cookies
- 使用flyway管理數據庫版本
- SpringBoot解決跨域訪問的問題
- IDEA遠程調試linux上的SB項目
- 附錄一:mybatis-plus
- f1-1.CURD快速入門
- f1-2.條件構造器使用與總結
- f1-3.自定義SQL
- f1-4.表格分頁與下拉分頁查詢
- f1-5.ActiveRecord模式
- f1-6.主鍵生成策略
- f1-7.MybatisPlus代碼生成器
- f1-8.邏輯刪除
- f1-9.字段自動填充
- f1-10.多租戶解決方案
- f1-11 日志打印輸出
- 附錄二:RestTemplate
- f2-1.基本介紹及配置使用
- f2-2.底層HTTP客戶端庫的切換
- f2-3.GET請求使用詳解
- f2-4.POST請求使用詳解
- f2-5.HTTP method使用方法詳解
- f2-6.文件上傳與下載
- f2-7.請求失敗異常處理
- f2-8.自動重試機制
- f2-9.通過BasicAuth認證
- f2-10使用代理作為跳板