zoukankan      html  css  js  c++  java
  • 【KakaJSON手册】02_JSON转Model_02_数据类型

    由于JSON格式能表达的数据类型是比较有限的,所以服务器返回的JSON数据有时无法自动转换成客户端想要的数据类型。

    • 比如服务器返回的时间可能是个毫秒数1565480696,但客户端想要的是Date类型
    • 再比如客户端想要的是浮点数Double类型,但服务器返回的可能是字符串类型"6.45"
    • 再比如客户端想要的是Bool类型,但服务器返回的可能是"true""1"0
    • 再比如客户端想要的是高精度浮点数NSDecimalNumber类型,服务器为了维持精度可能返回字符串"0.1234567890123456789"
    • 上述不同类型之间的匹配转换问题,KakaJSON已经内置了常用的解析功能,全部自动转换,不用做任何额外的配置。本文会介绍一些常见的数据类型匹配、转换功能。

    Int

    struct Student: Convertible {
        var age1: Int8 = 6
        var age2: Int16 = 0
        var age3: Int32 = 0
        var age4: Int64 = 0
        var age5: UInt8 = 0
        var age6: UInt16 = 0
        var age7: UInt32 = 0
        var age8: UInt64 = 0
        var age9: UInt = 0
        var age10: Int = 0
        var age11: Int = 0
    }
    
    let json: [String: Any] = [
        "age1": "suan8fa8",
        "age2": "6suan8fa8",
        "age3": "6",
        "age4": 6.66,
        "age5": NSNumber(value: 6.66),
        "age6": Int32(6),
        "age7": true,
        "age8": "FALSE",
        "age9": Decimal(6.66),
        "age10": NSDecimalNumber(value: 6.66),
        "age11": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    // 解析失败,所以使用默认值6
    XCTAssert(student.age1 == 6)
    // 解析到前面的数字6
    XCTAssert(student.age2 == 6)
    XCTAssert(student.age3 == 6)
    XCTAssert(student.age4 == 6)
    XCTAssert(student.age5 == 6)
    XCTAssert(student.age6 == 6)
    // true为1,false为0
    XCTAssert(student.age7 == 1)
    // 字符串trueTRUEYESyes都为1,字符串falseFALSENO
    o都为0
    XCTAssert(student.age8 == 0)
    XCTAssert(student.age9 == 6)
    XCTAssert(student.age10 == 6)
    XCTAssert(student.age11 == 1565922866)
    

    Float

    struct Student: Convertible {
        var height1: Float = 0.0
        var height2: Float = 0.0
        var height3: Float = 0.0
        var height4: Float = 0.0
        var height5: Float = 0.0
        var height6: Float = 0.0
        var height7: Float = 0.0
        var height8: Float = 0.0
        var height9: Float = 0.0
    }
    
    let json: [String: Any] = [
        "height1": "6.66suan8fa8",
        "height2": "0.12345678",
        "height3": NSDecimalNumber(string: "0.12345678"),
        "height4": Decimal(string: "0.12345678") as Any,
        "height5": 666,
        "height6": true,
        "height7": "NO",
        "height8": CGFloat(0.12345678),
        "height9": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.height1 == 6.66)
    XCTAssert(student.height2 == 0.12345678)
    XCTAssert(student.height3 == 0.12345678)
    XCTAssert(student.height4 == 0.12345678)
    XCTAssert(student.height5 == 666.0)
    // true为1.0,false为0.0
    XCTAssert(student.height6 == 1.0)
    // 字符串trueTRUEYESyes都为1.0,字符串falseFALSENO
    o都为0.0
    XCTAssert(student.height7 == 0.0)
    XCTAssert(student.height8 == 0.12345678)
    XCTAssert(student.height9 == 1565922866)
    

    Double

    struct Student: Convertible {
        var height1: Double = 0.0
        var height2: Double = 0.0
        var height3: Double = 0.0
        var height4: Double = 0.0
        var height5: Double = 0.0
        var height6: Double = 0.0
        var height7: Double = 0.0
        var height8: Double = 0.0
        var height9: Double = 0.0
    }
    
    let json: [String: Any] = [
        "height1": "6.66suan8fa8",
        "height2": "0.1234567890123456",
        "height3": NSDecimalNumber(string: "0.1234567890123456"),
        "height4": Decimal(string: "0.1234567890123456") as Any,
        "height5": 666,
        "height6": true,
        "height7": "NO",
        "height8": CGFloat(0.1234567890123456),
        "height9": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.height1 == 6.66)
    XCTAssert(student.height2 == 0.1234567890123456)
    XCTAssert(student.height3 == 0.1234567890123456)
    XCTAssert(student.height4 == 0.1234567890123456)
    XCTAssert(student.height5 == 666.0)
    // true为1.0,false为0.0
    XCTAssert(student.height6 == 1.0)
    // 字符串trueTRUEYESyes都为1.0,字符串falseFALSENO
    o都为0.0
    XCTAssert(student.height7 == 0.0)
    XCTAssert(student.height8 == 0.1234567890123456)
    XCTAssert(student.height9 == 1565922866)
    

    CGFloat

    struct Student: Convertible {
        var height1: CGFloat = 0.0
        var height2: CGFloat = 0.0
        var height3: CGFloat = 0.0
        var height4: CGFloat = 0.0
        var height5: CGFloat = 0.0
        var height6: CGFloat = 0.0
        var height7: CGFloat = 0.0
        var height8: CGFloat = 0.0
        var height9: CGFloat = 0.0
    }
    
    let json: [String: Any] = [
        "height1": "6.66suan8fa8",
        "height2": "0.1234567890123456",
        "height3": NSDecimalNumber(string: "0.1234567890123456"),
        "height4": Decimal(string: "0.1234567890123456") as Any,
        "height5": 666,
        "height6": true,
        "height7": "NO",
        "height8": 0.1234567890123456,
        "height9": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.height1 == 6.66)
    XCTAssert(student.height2 == CGFloat(0.1234567890123456))
    XCTAssert(student.height3 == CGFloat(0.1234567890123456))
    XCTAssert(student.height4 == CGFloat(0.1234567890123456))
    XCTAssert(student.height5 == 666.0)
    XCTAssert(student.height6 == 1.0)
    XCTAssert(student.height7 == 0.0)
    XCTAssert(student.height8 == CGFloat(0.1234567890123456))
    XCTAssert(student.height9 == CGFloat(1565922866))
    

    Bool

    struct Student: Convertible {
        var rich1: Bool = false
        var rich2: Bool = false
        var rich3: Bool = false
        var rich4: Bool = false
        var rich5: Bool = false
        var rich6: Bool = false
    }
    
    let json: [String: Any] = [
        "rich1": 100,
        "rich2": 0.0,
        "rich3": "1",
        "rich4": NSNumber(value: 0.666),
        "rich5": "true",
        "rich6": "NO"
    ]
    
    let student = json.kj.model(Student.self)
    // 数值0为false,数值非0都是true
    XCTAssert(student.rich1 == true)
    XCTAssert(student.rich2 == false)
    XCTAssert(student.rich3 == true)
    // 0.666是非0,所以为true
    XCTAssert(student.rich4 == true)
    // 字符串trueTRUEYESyes都为true
    XCTAssert(student.rich5 == true)
    // 字符串falseFALSENO
    o都为false
    XCTAssert(student.rich6 == false)
    

    String

    // 不管是String、NSString,还是NSMutableString,都是等效支持的
    
    struct Student: Convertible {
        var name1: String = ""
        var name2: String = ""
        var name3: NSString = ""
        var name4: NSString = ""
        var name5: NSMutableString = ""
        var name6: NSMutableString = ""
        var name7: String = ""
        var name8: String = ""
        var name9: String = ""
    }
    
    let json: [String: Any] = [
        "name1": 666,
        "name2": NSMutableString(string: "777"),
        "name3": [1,[2,3],"4"],
        "name4": NSDecimalNumber(string: "0.123456789012345678901234567890123456789"),
        "name5": 6.66,
        "name6": false,
        "name7": NSURL(fileURLWithPath: "/users/mj/desktop"),
        "name8": URL(string: "http://www.520suanfa.com") as Any,
        "name9": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.name1 == "666")
    XCTAssert(student.name2 == "777")
    // 这里相当于默认调用了数组的description方法
    XCTAssert(student.name3 == "[1, [2, 3], "4"]")
    XCTAssert(student.name4 == "0.123456789012345678901234567890123456789")
    XCTAssert(student.name5 == "6.66")
    XCTAssert(student.name6 == "false")
    XCTAssert(student.name7 == "file:///users/mj/desktop")
    XCTAssert(student.name8 == "http://www.520suanfa.com")
    XCTAssert(student.name9 == "1565922866")
    

    Decimal

    struct Student: Convertible {
        var money1: Decimal = 0
        var money2: Decimal = 0
        var money3: Decimal = 0
        var money4: Decimal = 0
        var money5: Decimal = 0
        var money6: Decimal = 0
        var money7: Decimal = 0
        var money8: Decimal = 0
    }
    
    let json: [String: Any] = [
        "money1": 0.1234567890123456,
        "money2": true,
        "money3": NSDecimalNumber(string: "0.123456789012345678901234567890123456789"),
        "money4": "0.123456789012345678901234567890123456789",
        "money5": 666,
        "money6": "NO",
        "money7": CGFloat(0.1234567890123456),
        "money8": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.money1 == Decimal(string: "0.1234567890123456"))
    XCTAssert(student.money2 == 1)
    XCTAssert(student.money3 == Decimal(string: "0.123456789012345678901234567890123456789"))
    XCTAssert(student.money4 == Decimal(string: "0.123456789012345678901234567890123456789"))
    XCTAssert(student.money5 == 666)
    XCTAssert(student.money6 == 0)
    XCTAssert(student.money7 == Decimal(string: "0.1234567890123456"))
    XCTAssert(student.money8 == Decimal(string: "1565922866"))
    

    NSDecimalNumber

    struct Student: Convertible {
        var money1: NSDecimalNumber = 0
        var money2: NSDecimalNumber = 0
        var money3: NSDecimalNumber = 0
        var money4: NSDecimalNumber = 0
        var money5: NSDecimalNumber = 0
        var money6: NSDecimalNumber = 0
        var money7: NSDecimalNumber = 0
        var money8: NSDecimalNumber = 0
    }
    
    let json: [String: Any] = [
        "money1": 0.1234567890123456,
        "money2": true,
        "money3": Decimal(string: "0.123456789012345678901234567890123456789") as Any,
        "money4": "0.123456789012345678901234567890123456789",
        "money5": 666.0,
        "money6": "NO",
        "money7": CGFloat(0.1234567890123456),
        "money8": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.money1 == NSDecimalNumber(string: "0.1234567890123456"))
    XCTAssert(student.money2 == true)
    XCTAssert(student.money2 == 1)
    XCTAssert(student.money3 == NSDecimalNumber(string: "0.123456789012345678901234567890123456789"))
    XCTAssert(student.money4 == NSDecimalNumber(string: "0.123456789012345678901234567890123456789"))
    XCTAssert(student.money5 == 666)
    XCTAssert(student.money6 == false)
    XCTAssert(student.money6 == 0)
    XCTAssert(student.money7 == NSDecimalNumber(string: "0.1234567890123456"))
    XCTAssert(student.money8 == NSDecimalNumber(string: "1565922866"))
    

    NSNumber

    struct Student: Convertible {
        var money1: NSNumber = 0
        var money2: NSNumber = 0
        var money3: NSNumber = 0
        var money4: NSNumber = 0
        var money5: NSNumber = 0
        var money6: NSNumber = 0
        var money7: NSNumber = 0
        var money8: NSNumber = 0
    }
    
    let json: [String: Any] = [
        "money1": 0.1234567890123456,
        "money2": true,
        "money3": Decimal(string: "0.1234567890123456") as Any,
        "money4": "0.1234567890123456",
        "money5": 666.0,
        "money6": "NO",
        "money7": CGFloat(0.1234567890123456),
        "money8": Date(timeIntervalSince1970: 1565922866)
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.money1 == NSNumber(value: 0.1234567890123456))
    XCTAssert(student.money2 == true)
    XCTAssert(student.money2 == 1)
    XCTAssert(student.money2 == 1.0)
    XCTAssert(student.money3 == NSNumber(value: 0.1234567890123456))
    XCTAssert(student.money4 == NSNumber(value: 0.1234567890123456))
    XCTAssert(student.money5 == 666)
    XCTAssert(student.money5 == 666.0)
    XCTAssert(student.money6 == false)
    XCTAssert(student.money6 == 0)
    XCTAssert(student.money6 == 0.0)
    XCTAssert(student.money7 == NSNumber(value: longDouble))
    XCTAssert(student.money8 == NSNumber(value: 1565922866))
    

    Optional

    // 再多?都不是问题
    
    struct Student: Convertible {
        var rich1: Bool = false
        var rich2: Bool? = false
        var rich3: Bool?? = false
        var rich4: Bool??? = false
        var rich5: Bool???? = false
        var rich6: Bool????? = false
    }
    
    let rich1: Int????? = 100
    let rich2: Double???? = 0.0
    let rich3: String??? = "0"
    let rich4: NSNumber?? = NSNumber(value: 0.666)
    let rich5: String? = "true"
    let rich6: String = "NO"
    
    let json: [String: Any] = [
        "rich1": rich1 as Any,
        "rich2": rich2 as Any,
        "rich3": rich3 as Any,
        "rich4": rich4 as Any,
        "rich5": rich5 as Any,
        "rich6": rich6
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.rich1 == true)
    XCTAssert(student.rich2 == false)
    XCTAssert(student.rich3 == false)
    XCTAssert(student.rich4 == true)
    XCTAssert(student.rich5 == true)
    XCTAssert(student.rich6 == false)
    

    URL

    // 支持URL和NSURL,默认会将String转为URLNSURL
    
    struct Student: Convertible {
        var url1: NSURL?
        var url2: NSURL?
        var url3: URL?
        var url4: URL?
    }
    
    let url = "http://520suanfa.com/红黑树"
    let encodedUrl = "http://520suanfa.com/%E7%BA%A2%E9%BB%91%E6%A0%91"
    
    let json: [String: Any] = [
        "url1": url,
        "url2": URL(string: encodedUrl) as Any,
        "url3": url,
        "url4": NSURL(string: encodedUrl) as Any
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.url1?.absoluteString == encodedUrl)
    XCTAssert(student.url2?.absoluteString == encodedUrl)
    XCTAssert(student.url3?.absoluteString == encodedUrl)
    XCTAssert(student.url4?.absoluteString == encodedUrl)
    

    Data

    // 支持NSData和Data,默认会将String转为DataNSData
    
    struct Student: Convertible {
        var data1: NSData?
        var data2: NSData?
        var data3: Data?
        var data4: Data?
        var data5: NSMutableData?
        var data6: NSMutableData?
    }
    
    let utf8 = String.Encoding.utf8
    let str = "RedBlackTree"
    let data = str.data(using: utf8)!
    
    let json: [String: Any] = [
        "data1": str,
        "data2": data,
        "data3": str,
        "data4": NSMutableData(data: data),
        "data5": str,
        "data6": data
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(String(data: (student.data1)! as Data, encoding: utf8) == str)
    XCTAssert(String(data: (student.data2)! as Data, encoding: utf8) == str)
    XCTAssert(String(data: (student.data3)!, encoding: utf8) == str)
    XCTAssert(String(data: (student.data4)!, encoding: utf8) == str)
    XCTAssert(String(data: (student.data5)! as Data, encoding: utf8) == str)
    XCTAssert(String(data: (student.data6)! as Data, encoding: utf8) == str)
    

    Date

    // 支持Date和NSDate,默认会将毫秒数转为DateNSDate
    
    struct Student: Convertible {
        var date1: NSDate?
        var date2: NSDate?
        var date3: Date?
        var date4: Date?
        var date5: Date?
        var date6: Date?
        var date7: Date?
    }
    
    let milliseconds: TimeInterval = 1565922866
    
    let json: [String: Any] = [
        "date1": milliseconds,
        "date2": Date(timeIntervalSince1970: milliseconds),
        "date3": milliseconds,
        "date4": NSDate(timeIntervalSince1970: milliseconds),
        "date5": "(milliseconds)",
        "date6": NSDecimalNumber(string: "(milliseconds)"),
        "date7": Decimal(string: "(milliseconds)") as Any
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.date1?.timeIntervalSince1970 == milliseconds)
    XCTAssert(student.date2?.timeIntervalSince1970 == milliseconds)
    XCTAssert(student.date3?.timeIntervalSince1970 == milliseconds)
    XCTAssert(student.date4?.timeIntervalSince1970 == milliseconds)
    XCTAssert(student.date5?.timeIntervalSince1970 == milliseconds)
    XCTAssert(student.date6?.timeIntervalSince1970 == milliseconds)
    XCTAssert(student.date7?.timeIntervalSince1970 == milliseconds)
    

    Enum

    // 遵守一下ConvertibleEnum协议即可支持带有RawValue的Enum类型
    
    enum Grade: String, ConvertibleEnum {
        case perfect = "A"
        case great = "B"
        case good = "C"
        case bad = "D"
    }
    
    struct Student: Convertible {
        var grade1: Grade = .perfect
        var grade2: Grade = .perfect
    }
    
    let json: [String: Any] = [
        "grade1": "C",
        "grade2": "D"
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.grade1 == .good)
    XCTAssert(student.grade2 == .bad)
    
    // 换个浮点数试试
    enum Grade2: Double, ConvertibleEnum {
        case perfect = 8.88
        case great = 7.77
        case good = 6.66
        case bad = 5.55
    }
    
    struct Student2: Convertible {
        var grade1: Grade2 = .perfect
        var grade2: Grade2 = .perfect
        var grade3: Grade2 = .perfect
        var grade4: Grade2 = .perfect
    }
    
    let json2: [String: Any] = [
        "grade1": "5.55kaka",
        "grade2": 6.66,
        "grade3": NSNumber(value: 7.77),
        "grade4": NSDecimalNumber(string: "8.88")
    ]
    
    let student2 = json2.kj.model(Student2.self)
    XCTAssert(student2?.grade1 == .bad)
    XCTAssert(student2?.grade2 == .good)
    XCTAssert(student2?.grade3 == .great)
    XCTAssert(student2?.grade4 == .perfect)
    

    Enum数组

    enum Grade: String, ConvertibleEnum {
        case perfect = "A"
        case great = "B"
        case good = "C"
        case bad = "D"
    }
    
    struct Student: Convertible {
        var name: String?
        var grades: [Grade]?
    }
    
    let json: [String: Any] = [
        "name": "Jack",
        "grades": ["D", "B"]
    ]
    
    let stu = json.kj.model(Student.self)
    XCTAssert(stu.name == "Jack")
    XCTAssert(stu.grades?[0] == .bad)
    XCTAssert(stu.grades?[1] == .great)
    

    字典嵌套Enum

    enum Grade: String, ConvertibleEnum {
        case perfect = "A"
        case great = "B"
        case good = "C"
        case bad = "D"
    }
    
    struct Student: Convertible {
        var name: String?
        var grades: [String: Grade]?
    }
    
    let json: [String: Any] = [
        "name": "Jack",
        "grades": ["2019": "D", "2020": "B"]
    ]
    
    let stu = json.kj.model(Student.self)
    XCTAssert(stu.name == "Jack")
    XCTAssert(stu.grades?["2019"] == .bad)
    XCTAssert(stu.grades?["2020"] == .great)
    

    字典嵌套Enum数组

    enum Grade: String, ConvertibleEnum {
        case perfect = "A"
        case great = "B"
        case good = "C"
        case bad = "D"
    }
    
    struct Student: Convertible {
        var name: String?
        var grades: [String: [Grade?]]?
    }
    
    let json: [String: Any] = [
        "name": "Jack",
        "grades": ["2019": ["A", "B"], "2020": ["C", "D"]]
    ]
    
    let stu = json.kj.model(Student.self)
    XCTAssert(stu.name == "Jack")
    XCTAssert(stu.grades?["2019"]?[0] == .perfect)
    XCTAssert(stu.grades?["2019"]?[1] == .great)
    XCTAssert(stu.grades?["2020"]?[0] == .good)
    XCTAssert(stu.grades?["2020"]?[1] == .bad)
    

    Array

    // 支持Array、NSArray、NSMutableArray与Set、NSSet、NSMutableSet之间自动转换
    
    struct Person: Convertible {
        var array1: [Int]?
        var array2: NSArray?
        var array3: NSMutableArray?
        var array4: [Int]?
        var array5: NSArray?
        var array6: NSMutableArray?
    }
    
    let array = [1, 2, 3]
    
    let json: [String: Any] = [
        "array1": NSMutableArray(array: array),
        "array2": array,
        "array3": array,
        "array4": NSMutableSet(array: array),
        "array5": NSSet(array: array),
        "array6": Set(array),
    ]
    
    let person = json.kj.model(Person.self)
    XCTAssert(person.array1 == array)
    XCTAssert(person.array2 == array as NSArray)
    XCTAssert(person.array3 == NSMutableArray(array: array))
    
    for i in array {
        XCTAssert(person.array4?.contains(i) == true)
        XCTAssert(person.array5?.contains(i) == true)
        XCTAssert(person.array6?.contains(i) == true)
    }
    

    Set

    // 支持Set、NSSet、NSMutableSet与Array、NSArray、NSMutableArray之间自动转换
    
    struct Person: Convertible {
        var set1: Set<Int>?
        var set2: NSSet?
        var set3: NSMutableSet?
        var set4: Set<Int>?
        var set5: NSSet?
        var set6: NSMutableSet?
    }
    
    let array = [1, 2, 3]
    
    let json: [String: Any] = [
        "set1": NSMutableSet(array: array),
        "set2": Set(array),
        "set3": Set(array),
        "set4": NSMutableArray(array: array),
        "set5": array,
        "set6": array
    ]
    
    let person = json.kj.model(Person.self)
    for i in array {
        XCTAssert(person.set1?.contains(i) == true)
        XCTAssert(person.set2?.contains(i) == true)
        XCTAssert(person.set3?.contains(i) == true)
        XCTAssert(person.set4?.contains(i) == true)
        XCTAssert(person.set5?.contains(i) == true)
        XCTAssert(person.set6?.contains(i) == true)
    }
    

    Dictionary

    // 支持Dictionary、NSDictionary、NSMutableDictionary之间自动转换
    
    struct Person: Convertible {
        var dict1: [String: Any]?
        var dict2: NSDictionary?
        var dict3: NSMutableDictionary?
    }
    
    let dict = ["no1": 100, "no2": 200]
    
    let json: [String: Any] = [
        "dict1": NSMutableDictionary(dictionary: dict),
        "dict2": dict,
        "dict3": dict
    ]
    
    let person = json.kj.model(Person.self)
    for (k, v) in dict {
        XCTAssert(person.dict1?[k] as? Int == v)
        XCTAssert(person.dict2?[k] as? Int == v)
        XCTAssert(person.dict3?[k] as? Int == v)
    }
    
  • 相关阅读:
    题解 P3709 【大爷的字符串题】
    题解P2730 [USACO3.2]魔板 Magic Squares
    二维凸包
    题解 P2158 [SDOI2008]仪仗队
    搜索专题——DFS A1103 Integer Factorization(30)
    数据结构专题——链表处理A1097.Deduplication on a Linked List(25) (静态链表)
    数据结构专题——链表处理A1052.Linked List Sorting(25) (静态链表)
    数据结构专题——链表处理 A1032.Sharing (静态链表)
    数据结构专题——队列的应用 A1056.Mice and Rice ( 25)
    数据结构专题 ——栈的应用 A1051.Pop Sequence(25)
  • 原文地址:https://www.cnblogs.com/mjios/p/11355295.html
Copyright © 2011-2022 走看看