Serialize và Deserialize Json và Json Array trong Unity


97

Tôi có một danh sách các mục được gửi từ một tệp PHP đến thống nhất bằng cách sử dụng WWW.

Các WWW.textvẻ thích:

[
    {
        "playerId": "1",
        "playerLoc": "Powai"
    },
    {
        "playerId": "2",
        "playerLoc": "Andheri"
    },
    {
        "playerId": "3",
        "playerLoc": "Churchgate"
    }
]

Nơi tôi cắt bớt phần thừa []từ string. Khi tôi cố gắng phân tích cú pháp nó bằng cách sử dụng Boomlagoon.JSON, chỉ đối tượng đầu tiên được truy xuất. Tôi phát hiện ra rằng tôi phải vào deserialize()danh sách và đã nhập MiniJSON.

Nhưng tôi bối rối làm thế nào để deserialize()danh sách này. Tôi muốn lặp qua mọi đối tượng JSON và truy xuất dữ liệu. Làm cách nào để thực hiện việc này trong Unity bằng C #?

Lớp tôi đang sử dụng là

public class player
{
    public string playerId { get; set; }
    public string playerLoc { get; set; }
    public string playerNick { get; set; }
}

Sau khi cắt, []tôi có thể phân tích cú pháp json bằng MiniJSON. Nhưng nó chỉ trở lại là người đầu tiên KeyValuePair.

IDictionary<string, object> players = Json.Deserialize(serviceData) as IDictionary<string, object>;

foreach (KeyValuePair<string, object> kvp in players)
{
    Debug.Log(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
}

Cảm ơn!


Tại sao bạn loại bỏ bên ngoài []? Đó là những gì làm cho nó một danh sách. Chỉ cần dừng việc xóa nó và giải mã hóa nó thành một mảng hoặc một danh sách và tôi hy vọng nó sẽ ổn. Vui lòng đăng mã mà bạn đã thử.
Jon Skeet

Cho chúng tôi xem lớp được sử dụng để giải mã hóa. Định dạng thật kỳ lạ, tại sao trình phát thứ hai không được bao bọc bên trong dấu ngoặc nhọn? Nó sẽ deserialize thành một danh sách của một cái gì đó, chẳng hạn như List<PlayerLocation>vì đây một mảng.
Maximilian Gerhardt

@MaximilianGerhardt Xin lỗi, dấu ngoặc nhọn là lỗi chính tả. Đã sửa nó trong câu hỏi và thêm mã nữa. Cảm ơn.
loãng 33 giờ chiều

1
Tôi nghĩ rằng có điều gì đó sai trái với sự hiểu biết của bạn về việc thư viện này ở đây xử lý quá trình giải mã hóa. Nó không phải là quá trình deserialization thông thường (như bạn có thể đã thấy trong Newtonsoft.Json), nhưng Json.Deserialize()LUÔN LUÔN IDictionary<string,object>trả lại cho bạn và bạn hoạt động trên đó List<object>. Nhìn vào stackoverflow.com/a/22745634/5296568 . Tốt hơn là có được một bộ giải không khí JSON tốt hơn, công cụ này thực hiện việc giải không khí bạn đã quen.
Maximilian Gerhardt

@MaximilianGerhardt Tôi đã thử IDictionary<string,object>. Tôi có thể nhận được giá trị, nhưng chỉ là người đầu tiên KeyValuePair<>.
loãng 33 giờ chiều

Câu trả lời:


247

Unity đã thêm JsonUtility vào API của họ sau Bản cập nhật 5.3.3 . Quên tất cả các thư viện của bên thứ 3 trừ khi bạn đang làm điều gì đó phức tạp hơn. JsonUtility nhanh hơn các thư viện Json khác. Cập nhật lên phiên bản Unity 5.3.3 trở lên rồi thử giải pháp bên dưới.

JsonUtilitylà một API nhẹ. Chỉ những loại đơn giản mới được hỗ trợ. Nó không hỗ trợ các bộ sưu tập như Từ điển. Một ngoại lệ là List. Nó hỗ trợ ListListmảng!

Nếu bạn cần tuần tự hóa một Dictionaryhoặc làm điều gì đó khác ngoài việc tuần tự hóa và giải mã hóa các kiểu dữ liệu đơn giản, hãy sử dụng API của bên thứ ba. Nếu không, hãy tiếp tục đọc.

Lớp mẫu để tuần tự hóa:

[Serializable]
public class Player
{
    public string playerId;
    public string playerLoc;
    public string playerNick;
}

1. MỘT ĐỐI TƯỢNG DỮ LIỆU (JSON KHÔNG ĐẾN)

Serializing Part A :

Nối tiếp đến Json với public static string ToJson(object obj);phương thức.

Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";

//Convert to JSON
string playerToJson = JsonUtility.ToJson(playerInstance);
Debug.Log(playerToJson);

Đầu ra :

{"playerId":"8484239823","playerLoc":"Powai","playerNick":"Random Nick"}

Serializing Part B :

Nối tiếp thành Json với public static string ToJson(object obj, bool prettyPrint);phương thức quá tải. Chỉ cần chuyển trueđến JsonUtility.ToJsonhàm sẽ định dạng dữ liệu. So sánh đầu ra bên dưới với đầu ra ở trên.

Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";

//Convert to JSON
string playerToJson = JsonUtility.ToJson(playerInstance, true);
Debug.Log(playerToJson);

Đầu ra :

{
    "playerId": "8484239823",
    "playerLoc": "Powai",
    "playerNick": "Random Nick"
}

Hủy số hóa Phần A :

Hủy phiên bản json với public static T FromJson(string json);phương thức quá tải.

string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = JsonUtility.FromJson<Player>(jsonString);
Debug.Log(player.playerLoc);

Hủy số hóa Phần B :

Hủy phiên bản json với public static object FromJson(string json, Type type);phương thức quá tải.

string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = (Player)JsonUtility.FromJson(jsonString, typeof(Player));
Debug.Log(player.playerLoc);

Hủy số hóa Phần C :

Hủy phiên bản json bằng public static void FromJsonOverwrite(string json, object objectToOverwrite);phương thức này. Khi JsonUtility.FromJsonOverwriteđược sử dụng, sẽ không có phiên bản mới nào của Đối tượng mà bạn đang giải mã hóa sẽ được tạo. Nó sẽ chỉ đơn giản là sử dụng lại cá thể bạn chuyển vào và ghi đè lên các giá trị của nó.

Điều này là hiệu quả và nên được sử dụng nếu có thể.

Player playerInstance;
void Start()
{
    //Must create instance once
    playerInstance = new Player();
    deserialize();
}

void deserialize()
{
    string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";

    //Overwrite the values in the existing class instance "playerInstance". Less memory Allocation
    JsonUtility.FromJsonOverwrite(jsonString, playerInstance);
    Debug.Log(playerInstance.playerLoc);
}

2. NHIỀU DỮ LIỆU (ARRAY JSON)

Json của bạn chứa nhiều đối tượng dữ liệu. Ví dụ playerIdxuất hiện nhiều hơn một lần . Unity's JsonUtilitykhông hỗ trợ mảng vì nó vẫn còn mới nhưng bạn có thể sử dụng lớp trợ giúp từ người này để làm việc với mảngJsonUtility .

Tạo một lớp được gọi là JsonHelper. Sao chép JsonHelper trực tiếp từ bên dưới.

public static class JsonHelper
{
    public static T[] FromJson<T>(string json)
    {
        Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
        return wrapper.Items;
    }

    public static string ToJson<T>(T[] array)
    {
        Wrapper<T> wrapper = new Wrapper<T>();
        wrapper.Items = array;
        return JsonUtility.ToJson(wrapper);
    }

    public static string ToJson<T>(T[] array, bool prettyPrint)
    {
        Wrapper<T> wrapper = new Wrapper<T>();
        wrapper.Items = array;
        return JsonUtility.ToJson(wrapper, prettyPrint);
    }

    [Serializable]
    private class Wrapper<T>
    {
        public T[] Items;
    }
}

Serializing Json Array :

Player[] playerInstance = new Player[2];

playerInstance[0] = new Player();
playerInstance[0].playerId = "8484239823";
playerInstance[0].playerLoc = "Powai";
playerInstance[0].playerNick = "Random Nick";

playerInstance[1] = new Player();
playerInstance[1].playerId = "512343283";
playerInstance[1].playerLoc = "User2";
playerInstance[1].playerNick = "Rand Nick 2";

//Convert to JSON
string playerToJson = JsonHelper.ToJson(playerInstance, true);
Debug.Log(playerToJson);

Đầu ra :

{
    "Items": [
        {
            "playerId": "8484239823",
            "playerLoc": "Powai",
            "playerNick": "Random Nick"
        },
        {
            "playerId": "512343283",
            "playerLoc": "User2",
            "playerNick": "Rand Nick 2"
        }
    ]
}

Hủy số hóa mảng Json :

string jsonString = "{\r\n    \"Items\": [\r\n        {\r\n            \"playerId\": \"8484239823\",\r\n            \"playerLoc\": \"Powai\",\r\n            \"playerNick\": \"Random Nick\"\r\n        },\r\n        {\r\n            \"playerId\": \"512343283\",\r\n            \"playerLoc\": \"User2\",\r\n            \"playerNick\": \"Rand Nick 2\"\r\n        }\r\n    ]\r\n}";

Player[] player = JsonHelper.FromJson<Player>(jsonString);
Debug.Log(player[0].playerLoc);
Debug.Log(player[1].playerLoc);

Đầu ra :

Powai

Người dùng2


Nếu đây là một mảng Json từ máy chủ và bạn không tạo nó bằng tay :

Bạn có thể phải Thêm {"Items":vào trước chuỗi nhận được sau đó thêm }vào cuối chuỗi đó.

Tôi đã tạo một hàm đơn giản cho điều này:

string fixJson(string value)
{
    value = "{\"Items\":" + value + "}";
    return value;
}

thì bạn có thể sử dụng nó:

string jsonString = fixJson(yourJsonFromServer);
Player[] player = JsonHelper.FromJson<Player>(jsonString);

3. Giải mã hóa chuỗi json không có lớp && Hủy tuần tự hóa Json với các thuộc tính số

Đây là một Json bắt đầu bằng một số hoặc thuộc tính số.

Ví dụ:

{ 
"USD" : {"15m" : 1740.01, "last" : 1740.01, "buy" : 1740.01, "sell" : 1744.74, "symbol" : "$"}, 

"ISK" : {"15m" : 179479.11, "last" : 179479.11, "buy" : 179479.11, "sell" : 179967, "symbol" : "kr"},

"NZD" : {"15m" : 2522.84, "last" : 2522.84, "buy" : 2522.84, "sell" : 2529.69, "symbol" : "$"}
}

Unity's JsonUtilitykhông hỗ trợ điều này vì thuộc tính "15m" bắt đầu bằng một số. Một biến lớp không thể bắt đầu bằng một số nguyên.

Tải xuống SimpleJSON.cstừ wiki của Unity .

Để có được tài sản "15 triệu" USD:

var N = JSON.Parse(yourJsonString);
string price = N["USD"]["15m"].Value;
Debug.Log(price);

Để nhận thuộc tính "15m" của ISK:

var N = JSON.Parse(yourJsonString);
string price = N["ISK"]["15m"].Value;
Debug.Log(price);

Để có được thuộc tính "15m" của NZD:

var N = JSON.Parse(yourJsonString);
string price = N["NZD"]["15m"].Value;
Debug.Log(price);

Phần còn lại của các thuộc tính Json không bắt đầu bằng chữ số có thể được xử lý bởi Unity's JsonUtility.


4. KHẮC PHỤC SỰ CỐ JsonUtility:

Các vấn đề khi nối tiếp với JsonUtility.ToJson?

Nhận chuỗi rỗng hoặc " {}" với JsonUtility.ToJson?

Một . Đảm bảo rằng lớp không phải là một mảng. Nếu có, hãy sử dụng lớp trợ giúp ở trên với JsonHelper.ToJsonthay vì JsonUtility.ToJson.

B . Thêm [Serializable]vào đầu lớp mà bạn đang tuần tự hóa.

C . Xóa tài sản khỏi lớp. Ví dụ, trong biến, public string playerId { get; set; } loại bỏ { get; set; } . Unity không thể tuần tự hóa điều này.

Các vấn đề khi deserializing với JsonUtility.FromJson?

Một . Nếu bạn nhận được Null, hãy đảm bảo rằng Json không phải là một mảng Json. Nếu có, hãy sử dụng lớp trợ giúp ở trên với JsonHelper.FromJsonthay vì JsonUtility.FromJson.

B . Nếu bạn nhận được NullReferenceExceptiontrong khi giải kích thước, hãy thêm [Serializable]vào đầu lớp.

C .Bất kỳ vấn đề nào khác, hãy xác minh rằng json của bạn là hợp lệ. Truy cập trang web này ở đây và dán json. Nó sẽ hiển thị cho bạn nếu json hợp lệ. Nó cũng sẽ tạo ra lớp thích hợp với Json. Chỉ cần đảm bảo loại bỏ loại bỏ { get; set; } khỏi mỗi biến và cũng thêm [Serializable]vào đầu mỗi lớp được tạo.


Newtonsoft.Json:

Nếu vì lý do nào đó mà Newtonsoft.Json phải được sử dụng thì hãy xem phiên bản chia nhánh cho Unity tại đây . Lưu ý rằng bạn có thể gặp sự cố nếu sử dụng một số tính năng nhất định. Hãy cẩn thận.


Để trả lời câu hỏi của bạn :

Dữ liệu ban đầu của bạn là

 [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]

Thêm {"Items": vào trước nó rồi thêm } vào cuối nó.

Mã để làm điều này:

serviceData = "{\"Items\":" + serviceData + "}";

Bây giờ bạn có:

 {"Items":[{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]}

Để serialize các nhiều dữ liệu từ php như mảng , bây giờ bạn có thể làm

public player[] playerInstance;
playerInstance = JsonHelper.FromJson<player>(serviceData);

playerInstance[0] là dữ liệu đầu tiên của bạn

playerInstance[1] là dữ liệu thứ hai của bạn

playerInstance[2] là dữ liệu thứ ba của bạn

hoặc dữ liệu bên trong các lớp học với playerInstance[0].playerLoc, playerInstance[1].playerLoc, playerInstance[2].playerLoc......

Bạn có thể sử dụng playerInstance.Lengthđể kiểm tra độ dài trước khi truy cập nó.

LƯU Ý: Xóa { get; set; } khỏi playerlớp học. Nếu bạn có { get; set; }, nó sẽ không hoạt động. Unity của JsonUtilitykhông KHÔNG làm việc với các thành viên lớp được xác định là thuộc tính .


Tôi đang trả về một mảng các hàng mysqltruy vấn từ PHP bằng cách sử dụng json_encode($row). Vì vậy, phản hồi bao gồm nhiều JSONObject trong định dạng [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. Tôi đã thử JsonUtility, nhưng tôi không thể giải mã hóa các đối tượng và nhận các đối tượng json riêng lẻ. Nếu bạn có thể giúp tôi với điều đó.
loãng 33 giờ chiều

2
Nhìn vào đoạn mã tôi đã đăng ở trên. Nó chỉ cho bạn ba cách để làm điều đó với JsonUtility.FromJson. Tôi quên nói với bạn để loại bỏ { get; set; }khỏi playerlớp học. Nếu bạn có { get; set; }, nó sẽ không hoạt động. So sánh playerlớp học của bạn với lớp tôi đã đăng ở trên và bạn sẽ hiểu những gì tôi đang nói.
Lập trình viên

1
Không vấn đề gì. Tôi sẽ chỉnh sửa điều này khi Unity thêm hỗ trợ cho mảng (sẽ rất sớm), vì vậy bạn sẽ không cần lớp Người trợ giúp đó nữa.
Lập trình viên

1
Tôi sẽ không đi xa khi nói rằng "Hãy quên đi tất cả các thư viện của bên thứ 3". JsonUtility có những hạn chế. Nó không trả về một đối tượng JSON mà bạn có thể thực hiện các hành động. Ví dụ: tôi nhận được một tệp json và muốn kiểm tra xem có khóa "thành công" hay không. Không làm được. JsonUtility yêu cầu người tiêu dùng biết chính xác nội dung của tệp json. Ngoài ra, không có trình chuyển đổi Từ điển. Vì vậy, nó thực hiện một số điều tốt nhưng vẫn cần sử dụng bên thứ 3.
Everts

2
Sử dụng JsonHelper. Tốt rồi. Nếu bạn tạo Json với nó, bạn cũng có thể đọc json với nó mà không cần thêm bước nào. Lần duy nhất bạn có thể cần phải làm thêm những thứ khác là nếu bạn nhận được mảng json từ máy chủ và điều đó được bao gồm trong giải pháp nằm trong câu trả lời của tôi. Một cách khác mà không có JsonHelperlà đặt lớp này trong một lớp khác sau đó biến nó thành a List. Điều này đã làm việc cho hầu hết mọi người. Nếu bạn đang tìm cách lưu và tải dữ liệu trò chơi thì hãy xem phần này . Bạn tải và lưu bằng một dòng mã.
Lập trình viên

17

Giả sử bạn có một JSON như thế này

[
    {
        "type": "qrcode",
        "symbol": [
            {
                "seq": 0,
                "data": "HelloWorld9887725216",
                "error": null
            }
        ]
    }
]

Để phân tích cú pháp JSON ở trên thống nhất, bạn có thể tạo mô hình JSON như thế này.

[System.Serializable]
public class QrCodeResult
{
    public QRCodeData[] result;
}

[System.Serializable]
public class Symbol
{
    public int seq;
    public string data;
    public string error;
}

[System.Serializable]
public class QRCodeData
{
    public string type;
    public Symbol[] symbol;
}

Và sau đó chỉ cần phân tích cú pháp theo cách sau ...

var myObject = JsonUtility.FromJson<QrCodeResult>("{\"result\":" + jsonString.ToString() + "}");

Bây giờ bạn có thể sửa đổi JSON / CODE theo nhu cầu của mình. https://docs.unity3d.com/Manual/JSONSerialization.html


Điều này thực sự hoạt động khá tốt, nó hoạt động với một lớp như Biểu tượng không phải là một mảng.
Gennon

4
Tôi đang cố gắng này với sự hợp nhất năm 2018 nhưng điều này không làm việc: các mảng không được phân tích cú pháp
Jean-Michaël Celerier

Được sử dụng trong thống nhất 2018 và 2019. Hoạt động tuyệt vời. Truy cập dữ liệu mảng như: Debug.Log(myObject.result[0].symbol[0].data);hoặc for(var i = 0; i <= myObject.result.Length - 1; i ++) { Debug.Log(myObject.result[i].type); }hoặcforeach (var item in myObject.result) { Debug.Log(item.type); }
Towerss

@Narottam Goyal, phương pháp của bạn không hoạt động trong một số trường hợp, cũng là một giải pháp rất khó khăn cho người mới bắt đầu, tham khảo câu trả lời này của tôi về chủ đề này liên kết
Juned Khan Momin

@JunedKhanMomin câu trả lời của bạn về cơ bản giống nhau nhưng không nhấn mạnh thực tế là câu hỏi này ở đây là về mảng cấp gốc trong dữ liệu JSON cụ thể. Nói chung, bạn nên tham khảo câu trả lời của Lập trình viên , cách này được xây dựng chi tiết hơn.
derHugo

2

bạn phải thêm [System.Serializable]vào PlayerItemlớp, như thế này:

using System;
[System.Serializable]
public class PlayerItem   {
    public string playerId;
    public string playerLoc;
    public string playerNick;
}

0

Đừng cắt []và bạn sẽ ổn. []xác định một mảng JSON chính xác là những gì bạn yêu cầu để có thể lặp lại các phần tử của nó.


0

Giống như @Maximiliangerhardt đã nói, MiniJson không có khả năng des trên không đúng cách. Tôi đã sử dụng JsonFx và hoạt động như một sự quyến rũ. Làm việc với[]

player[] p = JsonReader.Deserialize<player[]>(serviceData);
Debug.Log(p[0].playerId +" "+ p[0].playerLoc+"--"+ p[1].playerId + " " + p[1].playerLoc+"--"+ p[2].playerId + " " + p[2].playerLoc);

0

Để đọc tệp JSON, hãy tham khảo ví dụ đơn giản này

Tệp JSON của bạn (StreamingAssets / Player.json)

{
    "Name": "MyName",
    "Level": 4
}

Tập lệnh C #

public class Demo
{
    public void ReadJSON()
    {
        string path = Application.streamingAssetsPath + "/Player.json";
        string JSONString = File.ReadAllText(path);
        Player player = JsonUtility.FromJson<Player>(JSONString);
        Debug.Log(player.Name);
    }
}

[System.Serializable]
public class Player
{
    public string Name;
    public int Level;
}

1
Còn mảng thì sao? Và câu trả lời này bổ sung điều gì mà không được sử dụng trong câu trả lời được chấp nhận từ hơn 3 năm trước?
derHugo

0

Bạn có thể sử dụng Newtonsoft.Jsonchỉ cần thêm Newtonsoft.dllvào dự án của mình và sử dụng tập lệnh bên dưới

using System;
using Newtonsoft.Json;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{

    [Serializable]
    public class Person
    {
        public string id;
        public string name;
    }
    public Person[] person;

    private void Start()
    {
       var myjson = JsonConvert.SerializeObject(person);

        print(myjson);

    }
}

nhập mô tả hình ảnh ở đây

một giải pháp khác là sử dụng JsonHelper

using System;
using Newtonsoft.Json;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{

    [Serializable]
    public class Person
    {
        public string id;
        public string name;
    }
    public Person[] person;

    private void Start()
    {
        var myjson = JsonHelper.ToJson(person);

        print(myjson);

    }
}

nhập mô tả hình ảnh ở đây


0

NẾU bạn đang sử dụng Vector3 thì đây là những gì tôi đã làm

1- Tôi tạo một lớp Đặt tên là Trình phát

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class Player
{
    public Vector3[] Position;

}

2- sau đó tôi gọi nó như thế này

if ( _ispressed == true)
        {
            Player playerInstance = new Player();
            playerInstance.Position = newPos;
            string jsonData = JsonUtility.ToJson(playerInstance);

            reference.Child("Position" + Random.Range(0, 1000000)).SetRawJsonValueAsync(jsonData);
            Debug.Log(jsonData);
            _ispressed = false;
        }

3- và đây là kết quả

"Vị trí": [{"x": - 2,8567452430725099, "y": - 2,4323320388793947, "z": 0,0}]}


0

Unity <= 2019

Narottam Goyal đã có một ý tưởng hay khi gói mảng trong một đối tượng json, và sau đó deserializing thành một cấu trúc. Phần sau sử dụng Generics để giải quyết vấn đề này cho mọi kiểu mảng, thay vì tạo một lớp mới mọi lúc.

[System.Serializable]
private struct JsonArrayWrapper<T> {
    public T wrap_result;
}

public static T ParseJsonArray<T>(string json) {
    var temp = JsonUtility.FromJson<JsonArrayWrapper<T>>("{\" wrap_result\":" + json + "}");
    return temp.wrap_result;
}

Nó có thể được sử dụng theo cách sau:

string[] options = ParseJsonArray<string[]>(someArrayOfStringsJson);

Thống nhất 2020

Trong Unity 2020 có một gói newtonsoft chính thức là một thư viện json tốt hơn nhiều.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.