一個 json 轉換工具_台中搬家公司

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

      在前後端的數據協議(主要指httpwebsocket)的問題上,如果前期溝通好了,那麼數據協議上問題會很好解決,前後端商議一種都可以接受的格式即可。但是如果接入的是老系統、第三方系統,或者由於某些奇怪的需求(如為了節省流量,json 數據使用單字母作為key值,或者對某一段數據進行了加密),這些情況下就無法商議,需要在前端做數據轉換,如果不轉換,那麼奔放的數據格式可讀性差,也會造成項目難以維護。

 

      這也正是我在項目種遇到的問題,網上也找了一些方案,要麼過於複雜,要麼有些功能不能很好的支持,於是有了這個工具 class-converter。歡迎提 issue 和 star~~https://github.com/zquancai/class-converter

 

下面我們用例子來說明下:

面對如下的Server返回的一個用戶user數據:

{
    "i": 1234,
    "n": "name",
    "a": "1a2b3c4d5e6f7a8b"
}

或者這個樣的: 

{
    "user_id": 1234,
    "user_name": "name",
    "u_avatar": "1a2b3c4d5e6f7a8b"
}

數據里的 avatar 字段在使用時,可能需要拼接成一個 url,例如 https://xxx.cdn.com/1a2b3c4d5e6f7a8b.png

當然可以直接這麼做:

const json = {
    "i": 1234,
    "n": "name",
    "a": "1a2b3c4d5e6f7a8b",
};
const data = {};
const keyMap = {
    i: 'id',
    n: 'name',
    a: 'avatar',
}
Object.entries(json).forEach(([key, value]) => {
    data[keyMap[key]] = value;
});
// data = { id: 1234, name: 'name', avatar: '1a2b3c4d5e6f7a8b' }

然後我們進一步就可以把這個抽象成一個方法,像下面這個樣:

const jsonConverter = (json, keyMap) => {
    const data = {};
    Object.entries(json).forEach(([key, value]) => {
        data[keyMap[key]] = value;
    });
    return data;
}

如果這個數據擴展了,添加了教育信息,user 數據結構看起來這個樣:

{
    "i": 1234,
    "n": "name",
    "a": "1a2b3c4d5e6f7a8b",
    "edu": {
        "u": "South China Normal University",
        "ea": 1
    }
}

此時的 jsonConverter 方法已經無法正確轉換 edu 字段的數據,需要做一些修改:

const json = {
    "i": 1234,
    "n": "name",
    "a": "1a2b3c4d5e6f7a8b",
    "edu": {
        "u": "South China Normal University",
        "ea": 1
    }
};
const data = {};
const keyMap = {
    i: 'id',
    n: 'name',
    a: 'avatar',
    edu: {
        key: 'education',
        keyMap: {
            u: 'universityName',
            ea: 'attainment'
        }
    },
}

隨着數據複雜度的上升,keyMap 數據結構會變成一個臃腫的配置文件,此外 jsonConverter 方法會越來越複雜,以至於後面同樣難以維護。但是轉換后的數據格式,對於項目來說,數據的可讀性是很高的。所以,這個轉換必須做,但是方式可以更優雅一點。

寫這個工具的初衷也是為了更優雅的進行數據轉換。

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

 

工具用法

還是上面的例子(這裏使用typescript寫法):

import { toClass, property } from 'class-converter';
// 待解析的數據
const json = {
    "i": 1234,
    "n": "name",
    "a": "1a2b3c4d5e6f7a8b",
};
class User {
    @property('i')
    id: number;
    
    @property('n')
    name: string;
    
    @property('a')
    avatar: string;
}
const userIns = toClass(json, User);

你可以輕而易舉的獲得下面的數據:

// userIns 是 User 的一個實例
const userIns = {
    id: 1234,
    name: 'name',
    avatar: '1a2b3c4d5e6f7a8b',
}
userIns instanceof User // true

Json 類既是文檔又是類似於上文說的與keyMap類似的配置文件,並且可以反向使用。

import { toPlain } from 'class-converter';
const user = toPlain(userIns, User);
// user 數據結構
{
    i: 1234,
    n: 'name',
    a: '1a2b3c4d5e6f7a8b',
};

  

這是一個最簡單的例子,我們來一個複雜的數據結構:

{
  "i": 10000,
  "n": "name",
  "user": {
    "i": 20000,
    "n": "name1",
    "email": "zqczqc",
    // {"i":1111,"n":"department"}
    "d": "eyJpIjoxMTExLCJuIjoiZGVwYXJ0bWVudCJ9",
    "edu": [
      {
        "i": 1111,
        "sn": "szzx"
      },
      {
        "i": 2222,
        "sn": "scnu"
      },
      {
         "i": 3333
      }
    ]
  }
}

這是後端返回的一個叫package的json對象,字段意義在文檔中這麼解釋:

  • i:package 的 id
  • n:package 的名字
  • user:package 的所有者,一個用戶
    • i:用戶 id
    • n:用戶名稱
    • email:用戶email,但是只有郵箱前綴
    • d:用戶的所在部門,使用了base64編碼了一個json字符串
      • i:部門 id
      • n:部門名稱
    • edu:用戶的教育信息,數組格式
      • i:學校 id
      • sn:學校名稱

我們的期望是將這一段數據解析成,不看文檔也能讀懂的一個json對象,首先我們經過分析得出上面一共有4類實體對象:package、用戶信息、部門信息、教育信息。

下面是代碼實現:

import {
    toClass, property, array, defaultVal,
    beforeDeserialize, deserialize, optional
} from 'class-converter';
// 教育信息
class Education {
    @property('i')
    id: number;
    
    // 提供一個默認值
    @defaultVal('unknow')
    @prperty('sn')
    schoolName: string;
}
// 部門信息
class Department {
    @property('i')
    id: number;
    
    @prperty('n')
    name: string;
}
// 用戶信息
class User {
  @property('i')
  id: number;
  @property('n')
  name: string;
  
  // 保留一份郵箱前綴數據
  @optional()
  @property()
  emailPrefix: string;
  
  @optional()
  // 這裏希望自動把後綴加上去
  @deserialize(val => `${val}@xxx.com`)
  @property()
  email: string;
  
  @beforeDeserialize(val => JSON.parse(atob(val)))
  @typed(Department)
  @property('d')
  department: Department;
  
  @array()
  @typed(Education)
  @property('edu')
  educations: Education[];
}
// package
class Package {
  @property('i')
  id: number;
  
  @property('n')
  name: string;
  
  @property('user', User)
  owner: User;
} 

數據已經定義完畢,這時只要我們執行toClass方法就可以得到我們想要的數據格式:

{
  id: 10000,
  name: 'name',
  owner: {
    id: 20000,
    name: 'name1',
    emailPrefix: 'zqczqc',
    email: "zqczqc@xxx.com",
    department: {
        id: 1111,
        name: 'department'
    },
    educations: [
      {
        id: 1111,
        schoolName: 'szzx'
      },
      {
        id: 2222,
        schoolName: 'scnu'
      },
      {
        id: 3333,
        schoolName: 'unknow'
      }
    ]
  }
}

上面這一份數據,相比後端返回的數據格式,可讀性大大提升。這裏的用法出現了@deserialize@beforeDeserialize@yped的裝飾器,這裏對這幾個裝飾器是管道方式調用的(前一個的輸出一個的輸入),這裏做一個解釋:

  • beforeDeserialize 第一個參數可以最早拿到當前屬性值,這裏可以做一些解碼操作
  • typed這個是轉換的類型,入參是一個類,相當於自動調用toClass,並且調動時的第一個參數是beforeDeserialize的返回值或者當前屬性值(如果沒有@beforeDeserialize裝飾器)。如果使用了@array裝飾器,則會對每一項數組元素都執行這個轉換
  • deserialize這個裝飾器是最後執行的,第一個參數是beforeDeserialize返回值,@typed返回值,或者當前屬性值(如果前面兩個裝飾器都沒設置的話)。在這個裝飾器里可以做一些數據訂正的操作

這三個裝飾器是在執行toClass時才會調用的,同樣的,當調用toPlain時也會有對應的裝飾器@serialize@fterSerialize,結合@typed進行一個相反的過程。下面將這兩個轉換過程的流程繪製出來。

調用 toClass的過程:

調用 toPlain的過程是調用 toClass的逆過程,但是有些許不一樣,有一個注意點就是:在調用 toClass時允許出現一對多的情況,就是一個屬性可以派生出多個屬性,所以調用調用 toPlain時需要使用 @serializeTarget來標記使用哪一個值作為逆過程的原始值,具體用法可以參考文檔。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

您可能也會喜歡…