Spring MVC 實(shí)現(xiàn) JSON 序列化
1. 前言
WEB 項(xiàng)目,后端使用 JAVA 語(yǔ)言系,前端使用 JS 語(yǔ)言系。兩種語(yǔ)言有各自的語(yǔ)法和數(shù)據(jù)類(lèi)型,不能直接進(jìn)行數(shù)據(jù)交換,這便是所謂的異構(gòu)化系統(tǒng)數(shù)據(jù)通信的問(wèn)題。
異構(gòu)化系統(tǒng)中數(shù)據(jù)通信的基本解決思路是:借助所有語(yǔ)言都能識(shí)別的中間語(yǔ)言,如 XML、JSON…… 進(jìn)行數(shù)據(jù)交換。
本節(jié)課就和大家聊聊控制器是如何把數(shù)據(jù)以 JSON 的格式傳遞給瀏覽器。本節(jié)課程,需要重點(diǎn)理解并掌握 @ResponseBody 注解的作用。
2. @ResponseBody
WEB 應(yīng)用程序中,控制器處理過(guò)的數(shù)據(jù),一般都是通過(guò)視圖技術(shù)渲染成 HTML 后交給瀏覽器進(jìn)行解析。最近幾年,項(xiàng)目整體結(jié)構(gòu)流行采用前后端分離模式。
什么是前后端分離結(jié)構(gòu)?
傳統(tǒng)項(xiàng)目,數(shù)據(jù)由后臺(tái)完全處理,前端頁(yè)面僅僅用來(lái)顯示結(jié)果數(shù)據(jù)。
所謂前后端分離,會(huì)把一部分?jǐn)?shù)據(jù)邏輯交給前端處理。也就意味著,交給前端的數(shù)據(jù)僅僅只是半成品數(shù)據(jù),需要前端語(yǔ)言如 JS 進(jìn)一步處理后再交給 HTML 顯示。
后端一般選擇以 JSON 的格式向前端進(jìn)行數(shù)據(jù)傳遞。Spriing MVC 可以使用 @ResponseBody 完成這個(gè)操作。@ResponseBody 是 Spring MVC 提供的一個(gè)很有意思的注解,一般放置在控制器方法的前面。
2.1 返回字符串
給出一個(gè)控制器的實(shí)例代碼,這個(gè)代碼很普通,不同之處在于方法前面使用了 @ResponseBody 注解。 于是,這個(gè)方法的命運(yùn)被改變了。
@Controller
@RequestMapping("/json")
public class JsonAction {
@RequestMapping("/test01")
@ResponseBody
public String testJson() {
return "Hello";
}
}
控制器方法有 @ResponseBody 注解和沒(méi)有此注解,Spring MVC 對(duì)控制器方法的返回值的理解迥然不同。
- 沒(méi)有 @ResponseBody 注解:Spring MVC 會(huì)把返回值 “hello” 理解為視圖邏輯名,通過(guò)視圖解析器找到視圖物理位置;
- 有 @ResponseBody 注解: Spring MVC 會(huì)把返回值直接寫(xiě)入響應(yīng)包后交給瀏覽器。意味著不需要視圖解析器的參與。
測(cè)試一下上面實(shí)例。
打開(kāi)瀏覽器,在地址欄上輸入:http://localhost:8888/sm-demo/json/test01 。
你在瀏覽器將看到如下圖所示結(jié)果:
2.2 返回對(duì)象
JAVA 中的數(shù)據(jù)很多時(shí)候都是以 OOP 的形式存在的,如學(xué)生對(duì)象數(shù)據(jù)、老師對(duì)象數(shù)據(jù)、用戶(hù)對(duì)象數(shù)據(jù)……
那么,控制器中的方法能不能直接把數(shù)據(jù)以對(duì)象為單位寫(xiě)入響應(yīng)包后返回給瀏覽器了?
如下面的實(shí)例:
@RequestMapping("/test02")
@ResponseBody
public User testJson01() {
return new User("mk", "123");
}
打開(kāi)瀏覽器,在地址欄上輸入:http://localhost:8888/sm-demo/json/test02 。
在瀏覽器你將看到如下圖所示結(jié)果:
拋異常了。對(duì)于出錯(cuò),大家應(yīng)該有預(yù)感。User 是 JAVA 語(yǔ)言中的類(lèi)類(lèi)型,對(duì)于瀏覽器而言對(duì)它的了解是一片空白。但是,為什么前面返回字符串時(shí)卻可以了?
那是因?yàn)樽址彩且环N通用類(lèi)型,瀏覽器沒(méi)有不認(rèn)識(shí)的道理,但是,User 類(lèi)型,瀏覽器只能摸后腦勺了。
如果想讓瀏覽器識(shí)別出 User 類(lèi)型數(shù)據(jù)。想想也簡(jiǎn)單,自己編碼,把對(duì)象數(shù)據(jù)轉(zhuǎn)換成字符串格式。
@RequestMapping("/test03")
@ResponseBody
public String testJson03() {
User user=new User("mk", "123");
return user.getUserName()+","+user.getUserPassword();
}
經(jīng)過(guò)上面的修改后,瀏覽器中能顯示出數(shù)據(jù)。但是,這里會(huì)有 2 個(gè)問(wèn)題需要思考一下:
- 如前所述,前后端分離最主要的思想是讓前端承擔(dān)一部分?jǐn)?shù)據(jù)業(yè)務(wù)邏輯。一串沒(méi)有特定格式的字符串傳遞給前端,真要交給 JS 處理,你還真不怕 JS 煩心,你叫它如何從中識(shí)別出誰(shuí)是誰(shuí);
- 直接返回值給瀏覽器之前,需要通過(guò)手工編碼的方式把 OOP 數(shù)據(jù)格式轉(zhuǎn)換成字符串,這番折騰,勞心勞力。
好!先解決第一個(gè)問(wèn)題。字符串?dāng)?shù)據(jù)類(lèi)型是非結(jié)構(gòu)化的,但是,可以把它轉(zhuǎn)換成具有特定結(jié)構(gòu)格式的 JSON 字符串。
@RequestMapping("/test04")
@ResponseBody
public String testJson04() {
User user = new User("mk", "123");
String json = "{\"userName\":\"" + user.getUserName() + "\",\"userPassWord\":" + "\""
+ user.getUserPassword() + "\"" + "}";
return json;
}
打開(kāi)瀏覽器,地址欄中輸入 http://localhost:8888/sm-demo/json/test04 。
瀏覽器中將顯示如下信息:
傳遞給瀏覽器的雖然還是字符串,但是是具有特定格式的 JSON 字符串,如果要交給 JS 處理,JS 表示很開(kāi)心。
是的,數(shù)據(jù)格式的問(wèn)題解決了,但是,編碼的工作量增加了很多。
其實(shí),你所想要的結(jié)果,Spring MVC 能輕松幫你實(shí)現(xiàn)。
3. Spring MVC 和 JSON
使用 JAVA 作為開(kāi)發(fā)語(yǔ)言,Spring MVC 自然知道數(shù)據(jù)以對(duì)象的形式存在是正道。對(duì)于如何把后端的對(duì)象數(shù)據(jù)傳遞給前端,Spring MVC 有一套優(yōu)雅的解決方案。
只需要簡(jiǎn)簡(jiǎn)單單的 2 步操作,便可以讓開(kāi)發(fā)者省心省力的把 OOP 數(shù)據(jù)序列化成 JSON 格式后響應(yīng)給瀏覽器。
- 打開(kāi)項(xiàng)目中的 WebConfig 類(lèi)文件,在其中添加如下代碼;
@Bean
public MappingJackson2HttpMessageConverter mappConverter() {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter=new MappingJackson2HttpMessageConverter();
return mappingJackson2HttpMessageConverter;
}
Tips: 顧名思義,MappingJackson2HttpMessageConverter 就是一個(gè)消息轉(zhuǎn)換器,其作用就是把數(shù)據(jù)映射成 JSON 格式。
- Spring MVC 默認(rèn)情況下使用的是 jackson 插件完成具體的 JSON 格式序列化。打開(kāi) pom.xml 文件,在其中添加 jackson 依賴(lài)。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
有了上面配置后,幾乎不需要再做任何多余的事情,便能夠把控制器中的 OOP 數(shù)據(jù)以 JOSN 方式序列化給瀏覽器。
測(cè)試下面的控制器方法實(shí)例:
@RequestMapping("/test02")
@ResponseBody
public User testJson02() {
return new User("mk", "123");
}
控制器方法中直接返回一個(gè)對(duì)象,不用擔(dān)心,Spring MVC 會(huì)自動(dòng)轉(zhuǎn)換成 JOSN 格式后發(fā)送給瀏覽器,不信,可以試一下。
再查看瀏覽器中的結(jié)果。
是不是顯示的很漂亮。
4. 小結(jié)
本節(jié)課程和大家一起講解了如何在控制器中把 OOP 數(shù)據(jù)轉(zhuǎn)換成 JSON 格式后傳遞給瀏覽器。開(kāi)發(fā)者可以自己編碼把對(duì)象數(shù)據(jù)轉(zhuǎn)換成特定格式的字符串后響應(yīng)給瀏覽器,但是,這個(gè)過(guò)程很勞心勞力。
使用 Spring MVC 框架提供的 JSON 序列化轉(zhuǎn)換組件,開(kāi)發(fā)者不用關(guān)心底層具體轉(zhuǎn)換過(guò)程便能達(dá)到目的。框架幫開(kāi)發(fā)者解決了很多共性的問(wèn)題,讓開(kāi)發(fā)者可以有更多時(shí)間關(guān)注自己的核心邏輯。
記住!@ResponseBody 注解很重要。