4.Json序列化和反序列化

一.序列化的必要性

在項目當中用到的Json序列化是采用的jackson。
本項目當中JSON序列化反序列化的意義:在用戶登陸模塊當中幢痘,用戶的登陸信息是存儲在session當中的唬格,即session當中存儲user對象。
在項目演進的過程當中颜说,需要使用redis做用戶登陸的分布式緩存购岗,所以用戶的登陸信息是存儲在redis當中的,在redis當中設(shè)置的通用方法如下:

在登陸時放到session當中的是一個user對象门粪,但是在設(shè)計redis的時候設(shè)計的redis的key喊积、value都是String類型,所以需要先將用戶對象序列化為JSON庄拇,在獲取的時候在反序列化為對象注服,所以需要做一個序列戶對象的工具
public static String set(String key,String value)
public static String get(String key)

即value設(shè)置的是string類型,所以要將user對象Json為String字符串措近,然后調(diào)用set方法存儲在redis當中。在使用的時候在使用反序列化為User對象女淑。

二.重要設(shè)置

Json的序列化主要是通過ObjectMapper對象去實現(xiàn)的瞭郑,以下五個要在Json項目初始化的時候進行加載,下載靜態(tài)代碼塊當中即可鸭你。以下設(shè)置默認都是true屈张。

        /**
         * ALWAYS:設(shè)置對象的所有字段全部列入:所有的字段都進行序列化
         * NON_NULL:非null的才會序列化
         * NON_DEFAULT:字段沒有默認值(設(shè)置默認值或者設(shè)置的值和默認值相同)的時候不會序列化,若設(shè)置的值和默認值不同袱巨,會參與序列化
         * NON_EMPTY:""和空數(shù)組不會出現(xiàn)在序列戶當中
         */

        objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);

        //取消默認轉(zhuǎn)換timestamps的格式阁谆,若為true,則Json格式化后愉老,設(shè)置的時間字段包含timestamps
        objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);

        //自定義日期格式,此處使用的是自己設(shè)置所有的日期格式皆為以下的格式:yyyy-MM-dd HH:mm:ss
        objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtils.STANDARD_FORMAT));

        /**
         * 忽略空bean轉(zhuǎn)json的錯喔
         * false:當要json序列化的對象為賦值是空的時候场绿,不要報錯
         * true:當要json序列化的對象為賦值是空的時候,會報運行時異常
         */
        objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);


        //反序列化字段
        /**
         * 忽略在Json對象當中存在嫉入,但是在java對象當中不存在對應(yīng)屬性的問題焰盗,防止錯喔
         * 在進行JSon反序列化時璧尸,Json字段當中有一個字段,java實體類當中沒有熬拒,設(shè)置為false不報錯
         */
        objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

三.代碼

在進行反序列化的過程當中爷光,如果要反序列化為List<User>,或者Map<,>,則反序列化的第二個參數(shù)不能簡單的為Class<T> clazz,因為如果要反序列化為List<User>澎粟,則JackSon或在反序列化時蛀序,將user轉(zhuǎn)為LinkedHashMap,這是不合適的活烙,List<User>.class當然也是錯的徐裸。
所以可以使用JackSon提供的TypeReference, 在調(diào)用的時候只需要將返回值的類型寫上即可瓣颅,如返回值是List<User>倦逐,則第二個參數(shù)那寫為new TypeReference<List<User>>() {}即可
或者也可以重載該方法為:public static <T> T string2Obj(String str, Class<?> collectionClass,Class<?>... elements)
collectionClass返回集合,此處是List.class,elements返回集合參數(shù)宫补,可以是多個(多個使用數(shù)組),此處是User.class.

package com.mall.util;

import com.mall.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
import java.util.Date;


import java.text.SimpleDateFormat;

@Slf4j
public class JSONUtil {

    private static ObjectMapper objectMapper=new ObjectMapper();
    static {
        /**
         * ALWAYS:設(shè)置對象的所有字段全部列入:所有的字段都進行序列化
         * NON_NULL:非null的才會序列化
         * NON_DEFAULT:字段沒有默認值(設(shè)置默認值或者設(shè)置的值和默認值相同)的時候不會序列化檬姥,若設(shè)置的值和默認值不同,會參與序列化
         * NON_EMPTY:""和空數(shù)組不會出現(xiàn)在序列戶當中
         */

        objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);

        //取消默認轉(zhuǎn)換timestamps的格式
        objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);

        //設(shè)置所有的日期格式皆為以下的格式:yyyy-MM-dd HH:mm:ss
        objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtils.STANDARD_FORMAT));

        /**
         * 忽略空bean轉(zhuǎn)json的錯喔
         * false:當要json序列化的對象為賦值是空的時候粉怕,不要報錯
         * true:當要json序列化的對象為賦值是空的時候健民,會報運行時異常
         */
        objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);


        //反序列化字段
        /**
         * 忽略在Json對象當中存在,但是在java對象當中不存在對應(yīng)屬性的問題贫贝,防止錯喔
         */
        objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * 將對象轉(zhuǎn)換為string
     * @param obj秉犹,首先判斷對象是否為null,然后判斷obj是否為String或子類稚晚,崇堵,是則直接返回,因為是T類型客燕,所以要強轉(zhuǎn)以下鸳劳,不是則序列戶為String
     * @param <T>:表示將此方法申明為泛型方法,或申明方法只有一個類型T
     * @return
     */
    public static <T> String obj2String(T obj){
        if(obj==null){
            return null;
        }
        try {
            return obj instanceof String ? (String)obj:objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("parse object to string error",e);
            return null;
        }
    }
    //將對象轉(zhuǎn)換為string,可以返回格式化好的JSON對象
    public static <T> String obj2StringPretty(T obj){
        if(obj==null){
            return null;
        }
        try {
            return obj instanceof String ? (String)obj:objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("parse object to string error",e);
            return null;
        }
    }

    //反序列化:將一個字符串轉(zhuǎn)換為對象
    public static <T> T string2Obj(String str,Class<T> clazz){

        if(StringUtils.isEmpty(str) || clazz==null){
            return null;
        }
        try {
            return clazz.equals(String.class) ? (T)str : objectMapper.readValue(str,clazz);
        } catch (Exception e) {
            log.warn("parse object to string error",e);
            return null;
        }
    }


    /**
     * 對于復(fù)雜對象都可以使用后面兩個方法
     * 第一個方法:在調(diào)用的時候只需要將返回值的類型寫上即可也搓,如返回值是List<User>赏廓,則第二個剎那火速寫為new TypeReference<List<User>>() {}
     * 第二個方法:collectionClass返回集合,elements返回集合參數(shù)傍妒,可以是多個(多個使用數(shù)組)
     */




    /**
     * 反序列化為集合List<User>,但是傳參數(shù)的時候不能是List<User>.class,所以只能傳User.class或者List.class,但是如果傳入的List.class,
     * 那么就會轉(zhuǎn)為LinkedHashMap幔摸,最后決定使用jackSon的TypeReference是一個接口,可以轉(zhuǎn)換為User
     */
    public static <T> T string2Obj(String str, TypeReference<T> typeReference){
        if(StringUtils.isEmpty(str) || typeReference == null){
            return null;
        }
        try {
            return (T)(typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str,typeReference));
        } catch (Exception e) {
            log.warn("parse object to string error",e);
            return null;
        }
    }

    /**
     * @param str
     * @param collectionClass  颤练?表示是collectionClass,集合的類型
     * @param elements         既忆?表示是         ...表示可以傳遞多個參數(shù),多個參數(shù)的時候傳遞數(shù)組即可,集合當中參數(shù)的類型
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, Class<?> collectionClass,Class<?>... elements){

        JavaType javaType=objectMapper.getTypeFactory().constructParametricType(collectionClass,elements);

        try {
            return objectMapper.readValue(str,javaType);
        } catch (Exception e) {
            log.warn("parse object to string error",e);
            return null;
        }
    }







    public static void main(String[] args) {
        User u1=new User();
        u1.setId(1);
        u1.setEmail("codesheep@163.com");
        u1.setCreateTime(new Date());
        String user1Json=JSONUtil.obj2StringPretty(u1);
        log.info("user1Json:{}",user1Json);
        /*User u2=new User();
        u2.setId(2);
        u2.setEmail("codesheep2@163.com");*/

       /* List<User> userList= Lists.newArrayList();
        userList.add(u1);
        userList.add(u2);
        */
        /*String user1Json=JSONUtil.obj2String(userList);
        String user1JsonPretty=JSONUtil.obj2StringPretty(userList);
        log.info("user1Json:{}",user1Json);
        log.info("user1JsonPretty:{}",user1JsonPretty);*/

        //List<User> userList11=JSONUtil.string2Obj(user1Json,List<User>.class);
        //jackson在反序列化的時候尿贫,如果傳入的List.class,那么就會轉(zhuǎn)為LikedHashMap
        //TypeReference是一個接口电媳,
       /*List<User> userList1=JSONUtil.string2Obj(user1Json, new TypeReference<List<User>>() {
       });

        List<User> userList2=JSONUtil.string2Obj(user1Json,List.class,User.class);
        */
        System.out.println("end");
    }



}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市庆亡,隨后出現(xiàn)的幾起案子匾乓,更是在濱河造成了極大的恐慌,老刑警劉巖又谋,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拼缝,死亡現(xiàn)場離奇詭異,居然都是意外死亡彰亥,警方通過查閱死者的電腦和手機咧七,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來任斋,“玉大人继阻,你說我怎么就攤上這事》峡幔” “怎么了瘟檩?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長澈蟆。 經(jīng)常有香客問我墨辛,道長,這世上最難降的妖魔是什么趴俘? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任睹簇,我火速辦了婚禮,結(jié)果婚禮上寥闪,老公的妹妹穿的比我還像新娘太惠。我一直安慰自己,他們只是感情好疲憋,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布垛叨。 她就那樣靜靜地躺著,像睡著了一般柜某。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敛纲,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天喂击,我揣著相機與錄音,去河邊找鬼淤翔。 笑死翰绊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播监嗜,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼谐檀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裁奇?” 一聲冷哼從身側(cè)響起桐猬,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刽肠,沒想到半個月后溃肪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡音五,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年惫撰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躺涝。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡厨钻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坚嗜,到底是詐尸還是另有隱情夯膀,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布惶傻,位于F島的核電站棍郎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏银室。R本人自食惡果不足惜涂佃,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜈敢。 院中可真熱鬧辜荠,春花似錦、人聲如沸抓狭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽否过。三九已至午笛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苗桂,已是汗流浹背药磺。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煤伟,地道東北人癌佩。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓木缝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親围辙。 傳聞我的和親對象是個殘疾皇子我碟,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容