吃透FastJSON,認準此文!

JSON 介紹

JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。它使得人們很容易的進行閱讀和編寫。同時也方便了機器進行解析和生成。它採用一種 "鍵 : 值" 對的文本格式來存儲和表示數據,在系統交換數據過程當中經常被使用,是一種理想的數據交換語言。前端

"XML 的時代已通過去,如今是 JSON 的時代" 。相信如今這個觀點不少人已經默默認同,那麼咱們是否有認真思考過爲何如今 JSON 可以頂替 XML 的地位。咱們來簡單看下兩種的表示方式:java

<?xml version="1.0" encoding="gb2312"?>
<class>
    <stu id="001">
        <name>楊過</name> 
        <sex></sex>
        <age>20</age>
    </stu>  
    <stu id="002">
        <name>小龍女</name>    
        <sex></sex>
        <age>21</age>
    </stu>
</class>
[
    {
        "id""001",
        "name""楊過",
        "sex""男",
        "age""20"
    },
    {
        "id""002",
        "name""小龍女",
        "sex""女",
        "age""21"
    }
]

兩種方式都是用來描述簡單的班級信息,信息很少,可是明顯能夠看出 JSON 比 XML更加簡潔。具體區別可爲如下幾點:編程

  • 可讀性: JSON 和 XML 的可讀性可謂不相上下,一邊是簡易的語法,一邊是規範的標籤形式,很難分出勝負
  • 可擴展性: XML 天生有很好的擴展性,JSON 固然也有,所以 XML 能擴展的,JSON 也能夠擴展
  • 編碼難度: XML 有豐富的編碼工具,好比 DOM4J,JDom 等,JSON 也提供許多工具。可是在沒有工具的狀況下,由於 XML 有不少結構上的字符,編程難度相對較高。
  • 解碼難度: XML 的解析須要考慮到子節點父節點,難度較大,而 JSON 的解析難度幾乎爲 0,看上去就能理解數據結構

JSON 認知

JSON 具備如下形式
  • JSON 對象

源網侵刪json

{
    "id""002",
    "name""小龍女",
    "sex""女",
    "age""21"
}

這就是一個簡單的JSON 對象,咱們觀察能夠得出 JSON 的一些語法:設計模式

  1. 數據在花括號中 []
  2. 數據以 鍵 : 值 對的形式出現(其中鍵多以字符串的形式出現,值可爲字符串,數值,以及 JSON 對象)
  3. 每兩個 鍵 : 值 對以逗號分隔 , , 最後一個鍵值對需省略 ,

咱們按照上面的 3 點特徵,即可很簡單的構建出一個 JSON 對象數組

  • JSON 數組

圖片源網侵刪網絡

["value1","value2","value3"]

數據結構

[
    {
        "id""001",
        "name""楊過",
        "sex""男",
        "age""20"
    },
    {
        "id""002",
        "name""小龍女",
        "sex""女",
        "age""21"
    }
]

數組的表示方式也很簡單:ide

  1. 頭尾由 [] 包裹
  2. 數據主鍵以 , 隔開
  • JSON 字符串

圖片源網侵刪工具

'{"id""001""name""楊過""sex""男""age""20"}'

JSON 字符串與 Java 的字符串很是類似。

  1. 它必須以 "" 或者 '' 包裹數據,支持字符串的各類操做
  2. 裏面的數據格式能夠爲 json對象,也能夠是 json數組亦或者是兩個基本形式的組合變形

以上即是 JSON 的基本形式,JSON 可使用於各類語言,每一個語言皆有本身各自的JSON 實現方式。下面咱們主要來熟悉一下 Java 語言中的 FastJSON 的使用。

FastJSON

FastJSON 是由阿里巴巴工程師基於 JAVA 開發的一款 JSON 解析器和生成器,可用於將 Java 對象轉換爲其 JSON 表示形式,它還能夠用於將 JSON 字符串轉換爲等效的 Java 對象。FastJSON 能夠處理任意 Java 對象,包括沒有源代碼的預先存在的對象

FastJSON 使用十分方便,咱們只須要在 Maven 工程的 pom 文件中引入如下依賴便可:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.73</version>
</dependency>

FastJSON API 的入口類是 com.alibaba.fastjson.JSON,經常使用的序列化操做均可以在JSON類上的靜態方法直接完成。

圖片

API

咱們已經在項目中引入 FastJSON 的依賴,和已經存在了一個用戶類:

@Data
public class User {
    private int id;

    private String name;

    private String sex;
    
    private int age;
}
toJSONString(Object o)

這個方法平時最多見了,將JavaBean序列化成 JSON 文本

圖片

咱們經過傳入一個對象,即可以將對象轉成 JSON 字符串,這裏咱們傳入的不只僅是JavaBean 還能夠是一個 Map 對象

圖片

傳入一個 Map 對象 咱們一樣能夠獲取到一個 JSON 字符串。List 對象也很適用:

圖片

結果是一個標準的 JSONArray 的字符串

若是說 toJSONString(Object o) 的輸出結果只有單調的一行讓你看起來有點吃力,那麼咱們可使用 toJSONString(Object o, boolean prettyFormat) 來讓輸出結果看起來舒服點:

圖片

經過 JSON 自帶的格式化,讓輸出結果看起來更加清晰,真是貼心~

有小夥伴估計想着這兩種我平時都用膩歪了,哪裏有的着在你這看,小菜一想,言之有理。那就介紹一下 toJSONString 的擴展用法。

JSON.toJSONString(Object object, SerializerFeature... features)

咱們能夠看到這個方法裏面有個參數 SerializerFeature...,可能感到有點陌生,確實,我也很陌生,咱們先來看下什麼是 SerializerFeature,經過源碼咱們能夠發現 SerializerFeature 原來是個枚舉類:

看到這張圖咱們不要暈,裏面雖然有不少實例,可是大部分都被 @deprecated 註釋了,說明這些已經廢棄了。那有哪些是咱們平時常常用到的呢:

對象 描述
SerializerFeature.UseSingleQuotes 使用單引號而不是雙引號,默認爲false
SerializerFeature.PrettyFormat 結果是否格式化,默認爲false
SerializerFeature.WriteDateUseDateFormat 若是時間是data、時間戳類型,按照這種格式初始化時間 "yyyy-MM-dd HH:mm"
SerializerFeature.WriteMapNullValue 是否輸出值爲null的字段,默認爲false
SerializerFeature.WriteClassName 序列化時寫入類型信息,默認爲false

使用案例:

  • SerializerFeature.UseSingleQuotes

使用單引號而不是雙引號,默認爲false

圖片

  • SerializerFeature.PrettyFormat

結果是否格式化,默認爲false

圖片

  • SerializerFeature.WriteDateUseDateFormat

若是時間是data、時間戳類型,按照這種格式初始化時間 "yyyy-MM-dd HH:mm"

圖片

經過這種方式咱們將日期輸出成了固定的格式:yyyy-MM-dd HH:mm,有時候咱們不想獲得這種格式那該怎麼辦,辦法總會有的:

圖片

這個方式支持自定義時間格式,可是用到方法是toJSONStringWithDateFormat(),這裏須要注意下,不要到時候用錯了方法,還說小菜 渣男 ~

  • SerializerFeature.WriteMapNullValue

是否輸出值爲null的字段,默認爲false

這個用什麼用處了,咱們應該很清楚開發規範中鼓勵用JavaBean傳遞參數,儘可能減小經過 Map 傳遞參數,由於 Map 至關於一個黑盒,對於使用者來講根本不知道里面存在哪些字段,而對於建立者來講估計也會忘記裏面存在哪些字段,爲了解決這個痛,JSON 也推出瞭解決方法:

圖片

經過普通方式的 toJSONString() 方法,空值彷彿被 吃掉 了,這極可能會成爲一個開發災難!

  • SerializerFeature.WriteClassName

序列化時寫入類型信息,默認爲false。這個方法能夠在反序列化的時候用到,用法以下:

圖片

經過這樣咱們能夠看到咱們序列化的對象是什麼類型的。

上面這些即是 toJSONString 的擴展用法,小夥伴們有沒有滿滿的收穫~

vx 搜:小菜良記

更多幹貨值得關注,每篇都是初戀的味道,釘~

  • parseObject(String text)

上面說到的是 序列化,那麼對應的即是 反序列化

反序列化就是把JSON格式的字符串轉化爲Java Bean對象。

用法十分簡單,能夠將一個標準的 JSON 字符串 轉爲一個 JSONObject 對象,因爲JSONObject 類 實現了 Map 接口,所以咱們能夠經過 get() 來獲取到值。

咱們已經知道了 Map 的致命不足,因此咱們更但願能獲得一個 JavaBean 對象。

固然也是能夠的!咱們經過傳入咱們想要轉換的對象類型,就能夠獲得咱們想要的JavaBean

除了 基本反序列化 以外,還有一種 泛型反序列化 可供使用

經過 泛型 ,咱們就能夠不用傳入一個 Class 對象,而直接獲取到咱們的 JavaBean

FastJSON 序列化還有一個用處那即是進行 深克隆。有看過我前面文章的小夥伴們相信如今對軟件設計模式都有必定的瞭解了,其中原型模式涉及到的 深克隆 和 淺克隆

淺克隆的實現方式十分簡單,咱們只須要實現 Cloneable 接口,而後重寫 clone()方法 :

圖片

結果中咱們看到的好人卡 都是屬於小王的,這就是 淺克隆 的弊端的了。咱們想要實現 深克隆 有許多種方式:

  • 手動爲引用屬性賦值
  • 藉助 FastJSON
  • 使用 java 流的序列化對象

方法有許多,咱們重點看下 FastJSON 的實現方式,經過 FastJSON 的反序列化,咱們獲得的兩個對象其實是不一樣的,這也很方便的實現了 深克隆

parseArray(String text)

這是一個將 JSON字符串 轉爲 JSONArray 的方法

圖片

一樣咱們也能夠經過使用 泛型序列化 來實現一樣的功能:

圖片

這種方式有個坑就是:咱們使用 parseArray() 這個方法的時候第二個參數須要傳入咱們要反序列化的對象類型,可是咱們這裏須要傳入的是數組,不知道你有沒有爲數組裏放了兩個同樣的type感到奇怪?沒錯,這就是這個方法的坑,咱們 List 裏面有多少個對象, Type[] 這個數組裏面的個數要與之匹配,否則會拋出如下錯誤:

可是若是一個 List 中存在多個不一樣類型的對象時,咱們可使用這個方法:

toJSONBytes(Object o)

JSON對象轉換成Byte(字節)數組

咱們平時在進行網絡通信的時候,須要將對象轉爲字節而後進行傳輸。咱們使用字符串的時候,不禁然的能夠想到字符串中有個很便捷的 API 能夠將字符串轉爲字節數組

String str = "小菜";
byte[] bytes = str.getBytes();

可是咱們若是要將一個 JavaBean 對象轉爲字節數組的時候,咱們得藉助ByteArrayOutputStream 流的幫助:

圖片

這種方式也能夠很好的將 JavaBean 對象轉爲字節數組,可是代碼難免有點多了!而FastJSON 中也提供了很方便的 API 以供使用:

圖片

而咱們要將字節數組轉爲對象,FastJSON 也一樣支持:

圖片

parseObject()這個方法中咱們又看到了一個奇怪的參數 Feature,咱們點擊進入源碼能夠發現這其實也是一個枚舉類:

圖片

看的一樣雲裏霧裏的,這麼多對象實例,如下咱們對比較經常使用的作出了註釋:

對象 描述
AllowUnQuotedFieldNames 決定parser是否將容許使用非雙引號屬性名
AllowSingleQuotes 決定parser是否容許單引號來包住屬性名稱和字符串值
InternFieldNames 決定JSON對象屬性名稱是否能夠被String#intern 規範化表示,若是容許,則JSON全部的屬性名將會 intern() ;若是不設置,則不會規範化,默認下,該屬性是開放的。
AllowISO8601DateFormat 設置爲true則遇到字符串符合ISO8601格式的日期時,會直接轉換成日期類
AllowArbitraryCommas 容許多重逗號,若是設爲true,則遇到多個逗號會直接跳過
UseBigDecimal 設置爲true則用BigDecimal類來裝載數字,不然用的是double
IgnoreNotMatch 忽略不匹配
DisableCircularReferenceDetect 禁用循環引用檢測
InitStringFieldAsEmpty 對於沒有值得字符串屬性設置爲空串
SupportArrayToBean 支持數組to對象
OrderedField 屬性保持原來的順序
DisableSpecialKeyDetect 禁用特殊字符檢查
UseObjectArray 使用對象數組
writeJSONString(OutputStream os, Object o)

這個方法是將對象寫入輸出流中的:

圖片

傳入的參數還能夠是一個 Writer 對象:

圖片

以上即是咱們平時經常使用的 API,除此以外,在 FastJSON 中還有一個註解@JSONField 咱們也要學會靈活運用

@JSONField
命名重塑

圖片

注: 若屬性是 私有的,必需要有 set() 方法,不然沒法反序列化!

@JSONField 用法簡單,能夠配置在 getter() 、setter() 或者 屬性字段 上

圖片

測試結果:

圖片

這個方法的最大好處即是用來對接奇奇怪怪的文檔,爲何說奇奇怪怪呢,有時候咱們須要調用第三方的接口,可是這個接口返回的值多是不符合命名規範的,那咱們這邊就須要定義一個實體類去接收它(Map雖然也行,可是也不規範)。

這個時候咱們定義的實體類的屬性名就得按照返回的字段名來命名,這對強迫症程序猿來講是致命打擊,這個時候 @JSONField 的用處就來了,咱們簡單看個例子。有個車牌信息實體的返回字段是這樣的:

{"PLATEID" : 01"PLATE": '閩A6666D', "IMAGEURL":'http://...'}

咱們能夠看到返回的字段名全都不知足小駝峯規則,咱們定義的實體類可不能這樣,藉助 @JSONField 的寫法以下:

圖片

測試下是否可以成功接收結果:

圖片

能夠看到咱們已經成功接收到結果了,並且實體類的命名也符合咱們的規範,一箭雙鵰。

圖片

DataFormat

咱們也可使用該註解來將咱們的日期格式化成咱們想要的樣子

圖片

控制序列化

在序列化或反序列化的時候咱們能夠指定字段不序列化,這個有點像 Java 流中的 transient 修飾。FastJSON 中也能夠實現類似的功能:

圖片

可是反序列化有個缺點就是,雖然值是空的,可是屬性名還在~

ordinal

咱們可使用ordinal來指定字段的順序

圖片

經過接收結果能夠看到 屬性字段 按照咱們規定的順序所排列,用處能夠在於咱們返回字段給前端過多的時候,將有用的字段優先排列到前面,能夠更好的取值,而不用一層一層的查找須要的字段。

定製序列化

萬物皆可定製,序列化也不例外~ 咱們可使用serializeUsing制定屬性的序列化類

圖片

經過這種方式咱們針對 age 這個屬性進行了處理,給指定字段加上了單位.

相關文章
相關標籤/搜索