精华内容
下载资源
问答
  • Django框架中序列化和反序列化

    千次阅读 多人点赞 2018-09-29 11:35:43
    1.序列化 DRF的核心 就是 前后端分离的核心 前后端分离开发的核心: 将模型转换为json 称之为 序列化 将json转换为模型 称之为 反序列化 1.序列化器的字段 Serializer 序列化器 # 将模型转换为json 称之为 序列...

    1.序列化

    DRF的核心 就是 前后端分离的核心

    前后端分离开发的核心:
    将模型转换为json 称之为 序列化
    将json转换为模型 称之为 反序列化

    1.序列化器的字段

    Serializer 序列化器
    为了得到模型里的字段,序列化器中的字段应与模型类中的字段名一致

        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            # read_only=True 只能读 不能修改
            id = serializers.IntegerField(read_only=True,label='id')
            name = serializers.CharField(max_length=20,label='书籍名')
            pub_date = serializers.DataField(label='发布日期')
            readcount = serializers.IntegerField()
            is_delete = serializers.BooleanField()
            image = serializers.ImageField()
    
    

    2.序列化

    创建序列器
    序列化器的第一个参数:instance 用于序列化操作
    序列化器的第二个参数:data 用于反序列化操作
    除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

    serializer = AccountSerializer(account, context={'request': request})
    

    通过context参数附加的数据,可以通过Serializer对象的context属性获取。

    
        ''' views.py '''
    
        book = BookInfo.objects.get(id=2)
        
        s = BookInfoSerializers(instance=book)
    
        # 我们是通过 序列化器的data属性来获取 模型转换为字典的数据
        s.data
    
    
        # 传递多个数据
        # 应用: 查询所有书籍列表
    
        books = BookInfo.objects.all()
        # 创建序列化器,将所有书籍信息传递给序列化器
        # books = [BookInfo,BookInfo,...] 对象列表
        s = BookInfoSerializers(books,many=True)
        
        person = PeopleInfo.objects.get(id=6)
    
        # 序列化器初始化
        s = PeopleInfoSerializer(instance=person)
    
    
    

    3.关联序列化器的操作

    对于关联字段,可以采用以下几种方式:
    1) PrimaryKeyRelatedField
    2) StringRelatedField
    3) 使用关联对象的序列化器

    
    
    #########关联序列化器##########################
    
        class PeopleInfoSerializer(serializers.Serializer):
            """英雄数据序列化器"""
            GENDER_CHOICES = (
                (0, 'male'),
                (1, 'female')
            )
            id = serializers.IntegerField(label='ID', read_only=True)
            name = serializers.CharField(label='名字', max_length=20)
            gender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
            description = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)
    
    
            ''' PrimaryKeyRelatedField '''
            # 设置关联外键的时候,要将 read_only=True
            # 包含read_only=True参数时,该字段将不能用作反序列化使用
            # book = serializers.PrimaryKeyRelatedField(read_only=True,label='外键')
            # 或者
            # 包含queryset参数时,将被用作反序列化时参数校验使用
            # queryset 将关联模型的所有数据传递给这个属性就可以
            book = serializers.PrimaryKeyRelatedField(label='外键',queryset=BookInfo.objects.all())
    
            '''StringRelatedField'''
            # 现在通过  PrimaryKeyRelatedField得到的是一个  外键的一个值  2
            # 接下来通过 一个设置 来获取 书籍的名字
    
            # StringRelatedField 可以获取关联模型中的 __str_ 里的字符串
            book = serializers.StringRelatedField()
    
            ''' 使用关联对象的序列化器  拿到所有数据 '''
            book = BookInfoSerializer()
        
    

    4.关联查询

    关联模型类名小写_set 作为字段名

    
        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            id = serializers.IntegerField(read_only=True,label='id')
            name = serializers.CharFIeld(max_length=20,label='书籍名')
            pub_date = serializers.DataField(label='发布日期')
            readcount = serializers.IntegerField()
            is_delete = serializers.BooleanField()
            iamge = serializers.ImageField()
    
            
            # 书籍和人物的关系是 1:n   ===> many=True
            peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True,many=True)
    
            def __str__(self):
                return self.name
    
    

    2.反序列化

    反序列化 分为两个:

    • 数据校验
    • 数据入库

    2.1 数据校验

    使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

    在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

    验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。

    验证成功,可以通过序列化器对象的validated_data属性获取数据。

    在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为

    1. 数据校验的第一种方式

    在定义序列化器字段的时候,规定是什么类型 就要提交符合规则的数据
    例如:DateField 就需要传入符合日期规则的数据

    
        ##############将JSON转换为模型  反序列化#############
    
         ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            id = serializers.IntegerField(read_only=True,label='id')
            name = serializers.CharFIeld(max_length=20,label='书籍名')
            pub_date = serializers.DataField(label='发布日期')
           
            peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True,many=True)
    
            def __str__(self):
                return self.name
    
        ''' views.py '''
    
        dict = {
            'name':'itcast',
            'pub_date':'123'   # Flase
            # 'pub_date':'2010-1-1'  # True
        }
    
        # 1.创建序列器
        # 序列化器的第一个参数:instance 用于序列化操作
        # 序列化器的第二个参数:data 用于反序列化操作
        serializer = BookInfoSerializer(data=dict)
    
        # 2.需要调用序列化器的 is_valid 方法 valid验证  返回True False
        # 如果数据可用  返回True
        serializer.is_valid()
    
        # raise_exception=True 可以设置为True 来抛出异常
        serializer.is_valid(raise_exception=True)
    
    
    
    
    

    2.数据校验的第二种方式

    字段的选项
    required : 进行反序列化的时候,必须传这个字段
    min_length,max_length 作用于字符串
    min_value,max_value 作用于Int整型
    default 不传入数据 设置默认值

    
        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            id = serializers.IntegerField(read_only=True,label='id')
            name = serializers.CharFIeld(min_length=5,max_length=20,label='书籍名',)
            pub_date = serializers.DataField(label='发布日期',required=True)
    
    
            def __str__(self):
                return self.name
    
        ''' views.py '''
        dict = {
            'name':'itcast',
            'pub_date':'123'   # 若去掉pub_date 则报错
        }   
    
    
    

    3.数据校验的第三种方式

    对单个字段的数据进行验证
    语法形式为: 在序列化器中实现方法 def validate_字段名()

    
            
    
        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            id = serializers.IntegerField(read_only=True,label='id')
            name = serializers.CharFIeld(min_length=5,max_length=20,label='书籍名',)
            pub_date = serializers.DataField(label='发布日期',required=True)
            readcount = serializers.IntegerField(default=0,required=False)
    
            def __str__(self):
                return self.name
    
            def validate_readcount(self,value):
                # value 就是字段传递过来的数据
                if value < 0:
                    raise serializers.ValidationError('阅读量不能为负数')
    
                # 需要将value返回回去
                return value
    
        ''' views.py '''
        dict = {
            'name':'itcast',
            'readcount':-20,  # 报异常
        }   
    
    
    

    4.数据校验的第四种方式

    对多个字段的数据进行验证时
    语法形式为: 在序列化器中实现方法 def validate(self,attrs)

    
        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            id = serializers.IntegerField(read_only=True,label='id')
            name = serializers.CharFIeld(min_length=5,max_length=20,label='书籍名',)
            pub_date = serializers.DataField(label='发布日期',required=True)
            readcount = serializers.IntegerField(default=0,required=False)
            commentcount = serializers.IntegerField(default=0,required=False)
    
    
            def __str__(self):
                return self.name
    
            # 对多个字段进行验证
            # def validate(self,attrs):
            def validate(self,data):
                # attrs  -->  其实就是data
                readcount = data.get('readcount')
                commentcount = data['commentcount']
    
                if readcount < commentcount:
                    raise serializers.ValidationError('评论量不能大于阅读量')
    
                # 要将数据返回
                return data
    
    
        ''' views.py '''
        # 自定义需求:评论量不能大于阅读量
        dict = {
            'name':'itcast',
            'readcount':20, 
            'commentcount':100
        }   
    
    
    

    5.数据校验的第五种方式

    自定义验证方法
    同时给字段添加自定义验证方法

        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            # 自定义验证方法
            def custom_validate(self):
                if self == 'admin':
                raise serializers.ValidationError('我就是来捣乱的')
    
            id = serializers.IntegerField(read_only=True,label='id')
           
            # validators=[]  是给字段 添加自定义验证方法
            name = serializers.CharFIeld(min_length=5,max_length=20,label='书籍名',validators=[custom_validate])
           
    
            def __str__(self):
                return self.name
    
    
        ''' views.py '''
        # 规定:评论量不能大于阅读量
        dict = {
            'name':'itcast',
            'readcount':20, 
            'commentcount':100
        }   
    
    
    

    2.2 数据入库

    6.数据保存 save方法

    继承自Serializer的序列化 我们在调用save方法的时候,需要手动实现create方法,
    调用save方法之前,必须调用 is_valid方法,
    即 要想保存数据,必须保证数据是经过校验的。

    
        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            def create(self,validated_data):
    
                # dict -->  data --> attrs  -->  validated_data
                # validated_data 此处其实就是views.py中的dict
                # validated_data 已经被验证过的数据
    
                # *  对列表进行解包    *list
                # ** 对字典进行解包    **dict
                #   此处解包  将dict中的值 赋值给对象中的对应字段
                book = BookInfo.objects.create(**validated_data)
    
                # create 需要将创建的对象返回
                return book 
    
    
    
         ''' views.py '''
    
        # 规定:评论量不能大于阅读量
        dict = {
            'name':'itcast',
            'readcount':20, 
            'commentcount':100
        }   
    
    
    
        serializer = BookInfoSerializer(data=dict)
        serializer.is_valid(raise_exception=True)
    
        # 3. 保存需要调用序列化器的save方法
        # 继承自Serializer的序列化 我们在调用save方法的时候,需要手动实现create方法
        serializer.save()
    
    
    
    

    7.序列化器中传入两个参数,即数据的更新操作

    如果我们在序列化器中既传入了对象,又传入了数据
    系统会认为我们在更新数据
    继承自Serializer的类,要更新数据的时候,需要手动实现update方法

     
        ''' serializers.py '''
    
        class BookInfoSerializer(serializers.Serializer):
    
            def update(self,instance,validated_data):
                # instance : 就是我们在更新数据时,传入序列化器的对象
                # validated_data : 验证之后的数据
    
                instance.name = validated_data.get('name',instance.name)
                instance.pub_date = validated_data.get('pub_date',instance.pub_date)
                instance.readcount = validated_data.get('readcount',instance.readcount)
                instance.commentcount = validated_data.get('commentcount',instance.commentcount)
    
                instance.save()
    
                # update()方法需要我们手动返回对象
                return instance
                
    
    
        '''views.py '''
    
        # 1.获取对象
        book = BookInfo.objects.get(id=2)
        # 2.保存数据
        data = {
            'name':'lalala',
            'pub_date':'2018-1-1',
            'readcount':1000,
            'commentcount':10
        }    
    
        # 3.创建序列化器
        s = BookInfoSerializer(instance=book,data=data)
        # 4.验证数据
        s.is_valid(raise_exception=True)
        # 5.保存数据
        s.save()
    
    
      
    

    3.ModelSerializer

    如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

    ModelSerializer与常规的Serializer相同,但提供了:
    基于模型类自动生成一系列字段
    包含默认的create()和update()的实现

    
        ''' serializers.py '''
    
        class BookSerializer(serializers.ModelSerializer):
            
            # 如何设置   通过class Meta
            class Meta:
                model = BookInfo    # 设置关联模型     model就是关联模型
                # fields = '__all__'  # fields设置字段   __all__表示所有字段
                # fields = ['id','name','pub_date']  # fields设置字段  []列表显示来设置
                exclude = ['image']   # exclude 排除列表中的字段,剩余的字段都显示
    
                read_only_fields = ('id','readcount','commentcount')
    
                # 我们可以对自动生成的字段  进行额外的设置
                extra_kwargs = {
                    # 字段名:{选项:值}
                    'pub_date':{'required':True},
                    'readcount':{
                        'max_value':10000,
                        'min_value':0
                    }
                }
    
        '''views.py'''
    
        #########ModelSerializer##############
        data = {
                'name':'abc',
                'pub_date':'2018-1-1',
                'readcount':1000,
                'commentcount':10
            }    
    
        s = BookSerializer(data=data)
        s.is_valid(raise_exception=True)
        s.save()
    
    
    展开全文
  • DRF 中文文档: 需要的朋友们请点击... 序列化器(Serializer) 1. 自定义型:继承rest_framework.serializers.Serializer 2....序列化器的字段和选项类型 常用字段类型: 字段 字段构造方式 BooleanField...

    DRF 中文文档: 需要的朋友们请点击...

     

    序列化器(Serializer)

    • 1. 自定义型:  继承rest_framework.serializers.Serializer
    • 2. 模型类型:  继承rest_framework.serializers.ModelSerializer


    序列化器的字段和选项类型

    • 常用字段类型
    字段字段构造方式
    BooleanFieldBooleanField()
    NullBooleanFieldNullBooleanField()
    CharFieldCharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
    EmailFieldEmailField(max_length=None, min_length=None, allow_blank=False)
    RegexFieldRegexField(regex, max_length=None, min_length=None, allow_blank=False)
    SlugFieldSlugField(maxlength=50, min_length=None, allow_blank=False) 
    正则字段,验证正则模式 [a-zA-Z0-9-]+
    URLFieldURLField(max_length=200, min_length=None, allow_blank=False)
    UUIDFieldUUIDField(format='hex_verbose') 
    format: 
    1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 
    2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 
    3)'int' - 如: "123456789012312313134124512351145145114" 
    4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
    IPAddressFieldIPAddressField(protocol='both', unpack_ipv4=False, **options)
    IntegerFieldIntegerField(max_value=None, min_value=None)
    FloatFieldFloatField(max_value=None, min_value=None)
    DecimalFieldDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
    max_digits: 最多位数
    decimal_palces: 小数点位置
    DateTimeFieldDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
    DateFieldDateField(format=api_settings.DATE_FORMAT, input_formats=None)
    TimeFieldTimeField(format=api_settings.TIME_FORMAT, input_formats=None)
    DurationFieldDurationField()
    ChoiceFieldChoiceField(choices)
    choices与Django的用法相同
    MultipleChoiceFieldMultipleChoiceField(choices)
    FileFieldFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ImageFieldImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ListFieldListField(child=, min_length=None, max_length=None)
    DictFieldDictField(child=)

     

    • 选项参数:
    参数名称作用
    max_length最大长度
    min_lenght最小长度
    allow_blank是否允许为空
    trim_whitespace是否截断空白字符
    max_value最小值
    min_value最大值

     

    • 通用参数:
    参数名称说明
    read_only表明该字段仅用于序列化输出,默认False
    write_only表明该字段仅用于反序列化输入,默认False
    required表明该字段在反序列化时必须输入,默认True
    default反序列化时使用的默认值
    allow_null表明该字段是否允许传入None,默认False
    validators该字段使用的验证器
    error_messages包含错误编号与错误信息的字典
    label用于HTML展示API页面时,显示的字段名称
    help_text用于HTML展示API页面时,显示的字段帮助提示信息


    创建Serializer对象

    • 构造方法:Serializer(instance=None, data=empty, **kwarg)
    • 参数1,序列化必须传入的模型类对象
    • 参数2,反序列化时把数据传入data
    • 额外参数:例如context={'XX':'XX'},可通过context属性获取, context上下文解析详解上面官方文档


    序列化注意点:

    • 1. 序列化时如果被序列化是多条查询集,通过添加many=True,列表形式
      • 如果关联对象有多个,也可以在序列化器字段添加many=True
    • 2. 如果模型类存在外键字段,处理方式如下:
      • ①PrimaryKeyRelatedField,需设置read_only=True或queryser参数
        • 被序列化后是关联字段数据
      • ②StringRelatedField,被序列化是关联对象__str__返回值
      • ③HyperlinkedRelatedField,需设置read_only,view_name
        • 被序列化为关联对象数据的API链接
      • ④SlugRelateField,需设置read_only,slug_field
        • 被序列化后是关联对象的指定字段数据
      • ⑤使用关联对象的序列化器类的实例
      • ⑥重写to_representation 可修改被序列化后的返回值


    反序列化

    • 验证:在反序列化时,对数据验证,验证成功后才可获取数据或保存为模型类对象
      • ①调用is_valid方法验证,成功True,失败False
      • ②验证失败时,通过序列化器对象的errors属性获取错误信息,返回字典包含字段和字段错误,如果非字段错误,可修改配置中NON_FIELD_ERRORS_KEY来控制键名
      • ③验证成功时,通过序列化器对象的validated_date属性获取数据
    • 注意点:带参数raise_exception=True在反序列化时is_valid()方法在验证失败时抛出serializers.ValidationError,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。


    自定义验证行为:

    • 1. validate_字段名:在序列化器中添加方法,方法名validate_字段名,参数为value,对value做校验,raise
      • serializers.ValidationError('XXXX'),返回值value
    • 2. validate:在序列化器中添加validate方法,可同时对多个字段进行验证
      • 参数为attrs,从attrs中获取值,然后进行逻辑处理,抛出异常,返回值attrs
    • 3.validator:在序列化器上方编写函数,参数value,对value校验,抛出异常
      • 在序列化器字段中加入validator选项参数,为列表形式,值为函数名。
    • 4.REST framework提供的validators:
      • UniqueValidator单字段唯一:字段中设置,参数为queryset
      • UniqueTogetherValidation联合唯一:class Meta中设置,参数queryset和fields

     

    • 保存:如果验证成功,向基于validated_data完成数据对象的创建,可以通过create和update来实现
      • 1.新建:在序列化器中重写create方法,参数为validate_data,
        • 返回值为模型类.objects.create(**validated_data)
      • 2.更新:在序列化器中重写update方法,参数instance即要更新的实例和validate_data
        • 对validate_data字典获取其值,对无传递值给予默认值 instance.字段,并赋给instance.字段,然后调用instance.save()提交,返回值instance
    • 注意点:
      • ①实现了create和update方法后,在反序列化时既可以序列化对象.save()返回数据对象实例并保存或更新到数据库
      • ②调用save时,如果有传instance实例,则调用update方法更新数据,否则调用create方法新建数据。
      • ③调用save可传参,参数可从validated_data中获取
      • ④如果没有传递所有required字段,会抛出验证异常,可通过使用partial=True实现部分字段更新


    模型类序列化器ModelSerializer

    • 可基于模型类自动生成一系列字段,会自动生成valiators和实现了默认的create和update方法
    class 序列化器(serializers.ModelSerializer):    # 可在这里自定义序列化器字段
        class Meta:                
            model = 模型类名           # 参照哪个模型类                
            fields = '__all__'        # 这个代表所有字段,可以指定哪些字段,是元组类型()                
            exclude=('XXX',)          # 排除哪些字段,也是元组类型               
            depth = 1                 # 默认使用主键关联,可生成简单嵌套,整数,代表嵌套层级               
            read_only_fields= ('XXX',)        # 指明只读字段,即仅用于序列化输出的字段               
            extra_kwargs={字段:{选项:值} }  # 为序列化器字段添加或修改原有的选项参数,嵌套字典类型

     

    展开全文
  • 序列化与反序列化之Parcelable和Serializable浅析

    万次阅读 多人点赞 2016-09-26 15:50:41
    ok~,了解这么,下面来看一如何进行对象序列化和反序列化的列子: package com.zejian.ipctest; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io....

    转载请注明出处(万分感谢!):
    http://blog.csdn.net/javazejian/article/details/52665164
    出自【zejian的博客】

    本篇小部分内容摘自android开发艺术探索

      在日常的应用开发中,我们可能需要让某些对象离开内存空间,存储到物理磁盘,以便长期保存,同时也能减少对内存的压力,而在需要时再将其从磁盘读取到内存,比如将某个特定的对象保存到文件中,隔一段时间后再把它读取到内存中使用,那么该对象就需要实现序列化操作,在java中可以使用Serializable接口实现对象的序列化,而在android中既可以使用Serializable接口实现对象序列化也可以使用Parcelable接口实现对象序列化,但是在内存操作时更倾向于实现Parcelable接口,这样会使用传输效率更高效。接下来我们将分别详细地介绍这样两种序列化操作~~~~。

    序列化与反序列

    首先来了解一下序列化与反序列化。

    • 序列化

      由于存在于内存中的对象都是暂时的,无法长期驻存,为了把对象的状态保持下来,这时需要把对象写入到磁盘或者其他介质中,这个过程就叫做序列化。

    • 反序列化

      反序列化恰恰是序列化的反向操作,也就是说,把已存在在磁盘或者其他介质中的对象,反序列化(读取)到内存中,以便后续操作,而这个过程就叫做反序列化。

      概括性来说序列化是指将对象实例的状态存储到存储媒体(磁盘或者其他介质)的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。

    • 实现序列化的必要条件

      一个对象要实现序列化操作,该类就必须实现了Serializable接口或者Parcelable接口,其中Serializable接口是在java中的序列化抽象类,而Parcelable接口则是android中特有的序列化接口,在某些情况下,Parcelable接口实现的序列化更为高效,关于它们的实现案例我们后续会分析,这里只要清楚知道实现序列化操作时必须实现Serializable接口或者Parcelable接口之一即可。

    • 序列化的应用情景

      主要有以下情况(但不限于以下情况)

    • 1)内存中的对象写入到硬盘;
    • 2)用套接字在网络上传送对象;
    • 3)通过RMI(Remote Method Invoke 远程方法调用)传输对象;

      接下来我们分别介绍两种序列化的实现方式

    Serializable

      Serializable是java提供的一个序列化接口,它是一个空接口,专门为对象提供标准的序列化和反序列化操作,使用Serializable实现类的序列化比较简单,只要在类声明中实现Serializable接口即可,同时强烈建议声明序列化标识。如下:

    package com.zejian.ipctest;
    
    import java.io.Serializable;
    
    /**
     * Created by zejian
     * Time 2016/9/25.
     * Description:
     */
    public class Client implements Serializable{
    
        /**
         * 生成序列号标识
         */
        private static final long serialVersionUID = -2083503801443301445L;
    
        private int id;
        private String name;
    
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

      如上述代码所示,Client类实现的Serializable接口并声明了序列化标识serialVersionUID,该ID由编辑器生成,当然也可以自定义,如1L,5L,不过还是建议使用编辑器生成唯一标识符。那么serialVersionUID有什么作用呢?实际上我们不声明serialVersionUID也是可以的,因为在序列化过程中会自动生成一个serialVersionUID来标识序列化对象。既然如此,那我们还需不需要要指定呢?由于serialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化后的对象中serialVersionUID只有和当前类的serialVersionUID相同才能够正常被反序列化,也就是说序列化与反序列化的serialVersionUID必须相同才能够使序列化操作成功。具体过程是这样的:序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。报出如下UID错误:

    Exception in thread "main" java.io.InvalidClassException: com.zejian.test.Client; 
    local class incompatible: stream classdesc serialVersionUID = -2083503801443301445, 
    local class serialVersionUID = -4083503801443301445

      因此强烈建议指定serialVersionUID,这样的话即使微小的变化也不会导致crash的出现,如果不指定的话只要这个文件多一个空格,系统自动生成的UID就会截然不同的,反序列化也就会失败。ok~,了解这么多,下面来看一个如何进行对象序列化和反序列化的列子:

    package com.zejian.ipctest;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    /**
     * Created by zejian
     * Time 2016/9/25.
     * Description:
     */
    public class Stest {
    
        public static void main(String[] args) throws Exception {
    
            //把对象序列化到文件
            Client client = new Client();
            client.setId(000001);
            client.setName("client");
    
            ObjectOutputStream oo = new ObjectOutputStream
                    (new FileOutputStream("/Users/zejian/Desktop/cache.txt"));
            oo.writeObject(client);
            oo.close();
    
            //反序列化到内存
            ObjectInputStream oi = new ObjectInputStream
                (new FileInputStream("/Users/zejian/Desktop/cache.txt"));
            Client c_back = (Client) oi.readObject();
            System.out.println("Hi, My name is " + c_back.getName());
            oi.close();
    
        }
    }

      从代码可以看出只需要ObjectOutputStream和ObjectInputStream就可以实现对象的序列化和反序列化操作,通过流对象把client对象写到文件中,并在需要时恢复c_back对象,但是两者并不是同一个对象了,反序列化后的对象是新创建的。这里有两点特别注意的是如果反序列类的成员变量的类型或者类名,发生了变化,那么即使serialVersionUID相同也无法正常反序列化成功。其次是静态成员变量属于类不属于对象,不会参与序列化过程,使用transient关键字标记的成员变量也不参与序列化过程。
      关键字transient,这里简单说明一下,Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。
      另外,系统的默认序列化过程是可以改变的,通过实现如下4个方法,即可以控制系统的默认序列化和反序列过程:

    package com.zejian.ipctest;
    
    import java.io.IOException;
    import java.io.ObjectStreamException;
    import java.io.Serializable;
    
    /**
     * Created by zejian
     * Time 2016/9/25.
     * Description:
     */
    public class Client implements Serializable{
    
        /**
         * 生成序列号标识
         */
        private static final long serialVersionUID = -4083503801443301445L;
    
    
        private int id;
        private String name;
    
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    
        /**
         * 序列化时,
         * 首先系统会先调用writeReplace方法,在这个阶段,
         * 可以进行自己操作,将需要进行序列化的对象换成我们指定的对象.
         * 一般很少重写该方法
         * @return
         * @throws ObjectStreamException
         */
        private Object writeReplace() throws ObjectStreamException {
            System.out.println("writeReplace invoked");
            return this;
        }
        /**
         *接着系统将调用writeObject方法,
         * 来将对象中的属性一个个进行序列化,
         * 我们可以在这个方法中控制住哪些属性需要序列化.
         * 这里只序列化name属性
         * @param out
         * @throws IOException
         */
        private void writeObject(java.io.ObjectOutputStream out) throws IOException {
            System.out.println("writeObject invoked");
            out.writeObject(this.name == null ? "zejian" : this.name);
        }
    
        /**
         * 反序列化时,系统会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,
         * 反序列化回来.然后通过readResolve方法,我们也可以指定系统返回给我们特定的对象
         * 可以不是writeReplace序列化时的对象,可以指定其他对象.
         * @param in
         * @throws IOException
         * @throws ClassNotFoundException
         */
        private void readObject(java.io.ObjectInputStream in) throws IOException,
                ClassNotFoundException {
            System.out.println("readObject invoked");
            this.name = (String) in.readObject();
            System.out.println("got name:" + name);
        }
    
    
        /**
         * 通过readResolve方法,我们也可以指定系统返回给我们特定的对象
         * 可以不是writeReplace序列化时的对象,可以指定其他对象.
         * 一般很少重写该方法
         * @return
         * @throws ObjectStreamException
         */
        private Object readResolve() throws ObjectStreamException {
            System.out.println("readResolve invoked");
            return this;
        }
    }

      通过上面的4个方法,我们就可以随意控制序列化的过程了,由于在大部分情况下我们都没必要重写这4个方法,因此这里我们也不过介绍了,只要知道有这么一回事就行。ok~,对于Serializable的介绍就先到这里。

    Parcelable

      鉴于Serializable在内存序列化上开销比较大,而内存资源属于android系统中的稀有资源(android系统分配给每个应用的内存开销都是有限的),为此android中提供了Parcelable接口来实现序列化操作,Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如通过Intent在activity间传输数据,而Parcelable的缺点就使用起来比较麻烦,下面给出一个Parcelable接口的实现案例,大家感受一下:

    package com.zejian.ipctest;
    import android.os.Parcel;
    import android.os.Parcelable;
    
    /**
     * Created by zejian
     * Time 2016/9/25.
     * Description:
     */
    public class NewClient implements Parcelable {
    
        public int id;
        public String name;
        public User user;
    
        /**
         * 当前对象的内容描述,一般返回0即可
         * @return
         */
        @Override
        public int describeContents() {
            return 0;
        }
    
        /**
         * 将当前对象写入序列化结构中
         * @param dest
         * @param flags
         */
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(this.id);
            dest.writeString(this.name);
            dest.writeParcelable(this.user,0);
        }
    
        public NewClient() {
        }
    
        /**
         * 从序列化后的对象中创建原始对象
         * @param in
         */
        protected NewClient(Parcel in) {
            this.id = in.readInt();
            this.name = in.readString();
           //User是另一个序列化对象,此方法序列需要传递当前线程的上下文类加载器,否则会报无法找到类的错误
           this.user=in.readParcelable(Thread.currentThread().getContextClassLoader());
        }
    
        /**
         * public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。
         * 重写接口中的两个方法:
         * createFromParcel(Parcel in) 实现从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层,
         * newArray(int size) 创建一个类型为T,长度为size的数组,供外部类反序列化本类数组使用。
         */
        public static final Parcelable.Creator<NewClient> CREATOR = new Parcelable.Creator<NewClient>() {
            /**
             * 从序列化后的对象中创建原始对象
             */
            @Override
            public NewClient createFromParcel(Parcel source) {
                return new NewClient(source);
            }
    
            /**
             * 创建指定长度的原始对象数组
             * @param size
             * @return
             */
            @Override
            public NewClient[] newArray(int size) {
                return new NewClient[size];
            }
        };
    }

      从代码可知,在序列化的过程中需要实现的功能有序列化和反序列以及内容描述。其中writeToParcel方法实现序列化功能,其内部是通过Parcel的一系列write方法来完成的,接着通过CREATOR内部对象来实现反序列化,其内部通过createFromParcel方法来创建序列化对象并通过newArray方法创建数组,最终利用Parcel的一系列read方法完成反序列化,最后由describeContents完成内容描述功能,该方法一般返回0,仅当对象中存在文件描述符时返回1。同时由于User是另一个序列化对象,因此在反序列化方法中需要传递当前线程的上下文类加载器,否则会报无法找到类的错误。
      简单用一句话概括来说就是通过writeToParcel将我们的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成我们的对象。也可以将Parcel看成是一个类似Serliazable的读写流,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,这个过程需要我们自己来实现并且写的顺序和读的顺序必须一致。ok~,到此Parcelable接口的序列化实现基本介绍完。
      那么在哪里会使用到Parcelable对象呢?其实通过Intent传递复杂类型(如自定义引用类型数据)的数据时就需要使用Parcelable对象,如下是日常应用中Intent关于Parcelable对象的一些操作方法,引用类型必须实现Parcelable接口才能通过Intent传递,而基本数据类型,String类型则可直接通过Intent传递而且Intent本身也实现了Parcelable接口,所以可以轻松地在组件间进行传输。

    方法名称含义
    putExtra(String name, Parcelable value)设置自定义类型并实现Parcelable的对象
    putExtra(String name, Parcelable[] value)设置自定义类型并实现Parcelable的对象数组
    public Intent putParcelableArrayListExtra(String name, ArrayList value)设置List数组,其元素必须是实现了Parcelable接口的数据

      除了以上的Intent外系统还为我们提供了其他实现Parcelable接口的类,再如Bundle、Bitmap,它们都是可以直接序列化的,因此我们可以方便地使用它们在组件间进行数据传递,当然Bundle本身也是一个类似键值对的容器,也可存储Parcelable实现类,其API方法跟Intent基本相似,由于这些属于android基础知识点,这里我们就不过多介绍了。

    Parcelable 与 Serializable 区别

    • 两者的实现差异
        Serializable的实现,只需要实现Serializable接口即可。这只是给对象打了一个标记(UID),系统会自动将其序列化。而Parcelabel的实现,不仅需要实现Parcelabel接口,还需要在类中添加一个静态成员变量CREATOR,这个变量需要实现 Parcelable.Creator 接口,并实现读写的抽象方法。

    • 两者的设计初衷
        Serializable的设计初衷是为了序列化对象到本地文件、数据库、网络流、RMI以便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是由于Serializable效率过低,消耗大,而android中数据传递主要是在内存环境中(内存属于android中的稀有资源),因此Parcelable的出现为了满足数据在内存中低开销而且高效地传递问题。

    • 两者效率选择
        Parcelable的性能比Serializable好,在内存开销方面较小,所以Android应用程序在内存间数据传输时推荐使用Parcelable,如activity间传输数据和AIDL数据传递,而Serializable将数据持久化的操作方便,因此在将对象序列化到存储设置中或将对象序列化后通过网络传输时建议选择Serializable(Parcelable也是可以,只不过实现和操作过程过于麻烦并且为了防止android版本不同而导致Parcelable可能不同的情况,因此在序列化到存储设备或者网络传输方面还是尽量选择Serializable接口)。

    • 两者需要注意的共同点
        无论是Parcelable还是Serializable,执行反序列操作后的对象都是新创建的,与原来的对象并不相同,只不过内容一样罢了。

    Android studio 中的快捷生成方式

    • Android studio 快捷生成Parcelable代码

      在程序开发过程中,我们实现Parcelable接口的代码都是类似的,如果我们每次实现一个Parcelable接口类,就得去编写一次重复的代码,这显然是不可取的,不过幸运的是,android studio 提供了自动实现Parcelable接口的方法的插件,相当实现,我们只需要打开Setting,找到plugin插件,然后搜索Parcelable插件,最后找到android Parcelable code generator 安装即可:
    这里写图片描述

    重启android studio后,我们创建一个User类,如下:

    这里写图片描述

    然后使用刚刚安装的插件协助我们生成实现Parcelable接口的代码,window快捷键:Alt+Insert,Mac快捷键:cmd+n,如下:

    这里写图片描述

    最后结果如下:

    这里写图片描述

    • Android studio 快捷生成Serializable的UID
        在正常情况下,AS是默认关闭serialVersionUID生成提示的,我们需要打开setting,找到检测(Inspections选项),开启 Serializable class without serialVersionUID 检测即可,如下:

    这里写图片描述

    然后新建User类实现Serializable接口,右侧会提示添加serialVersionUID,如下:

    这里写图片描述

    最后在类名上,Alt+Enter(Mac:cmd+Enter),快捷代码提示,生成serialVersionUID即可:

    这里写图片描述

    最终结果如下:
    这里写图片描述

    ok~,以上便是Parcelable与Serializable接口的全部内容,本篇结束。

    展开全文
  • MapReduce序列化和反序列化 序列化(Serialization)是指把结构化对象转化为字节流。 反序列化(Deserialization)是序列化的逆过程。即把字节流转回结构化对象。   Hadoop的序列化格式:Writable 序列化在...

    MapReduce序列化和反序列化

    序列化(Serialization)是指把结构化对象转化为字节流。

    反序列化(Deserialization)是序列化的逆过程。即把字节流转回结构化对象。

     

    Hadoop的序列化格式:Writable

    序列化在分布式环境的两大作用:进程间通信,永久存储。

     

    Writable接口, 有两个方法分别为write和readFields,分别根据 DataInput 和 DataOutput 实现的简单、有效的序列化对象.

    MR的任意key必须实现WritableComparable接口

     




    MapReduce类型

    MapReduce的数据出来模型比较简单,map和reduce函数的输入和输出都是k/v键值对。

     

    Hadoop2.x中的MapReduce中的开发job中的setMapperClass和setReducerClass设置自己的函数,其中默认的类别分别为Mapper和Reducer,整理功能就是不做任何处理,对每行记录直接输出。

    Map函数

    public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
    
      /**
       * The <code>Context</code> MapContextImpl 来实现,context对象发送k/v
       */
      public abstract class Context
        implements MapContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
      }
      
      /**
       * MapTask任务开始时仅被调用一次
       */
      protected void setup(Context context
                           ) throws IOException, InterruptedException {
        // NOTHING
      }
    
      /**
       * 每个inputsplit中的每个k/v都被调用
          */
      @SuppressWarnings("unchecked")
      protected void map(KEYIN key, VALUEIN value, 
                         Context context) throws IOException, InterruptedException {
        context.write((KEYOUT) key, (VALUEOUT) value);
      }
    
      /**
       * MapTask任务结束后被调用一次
       */
      protected void cleanup(Context context
                             ) throws IOException, InterruptedException {
        // NOTHING
      }
      
      /**
       * Expert users can override this method for more complete control over the
       * execution of the Mapper.
       * @param context
       * @throws IOException
       */
      public void run(Context context) throws IOException, InterruptedException {
        setup(context);
        try {
          while (context.nextKeyValue()) {
            map(context.getCurrentKey(), context.getCurrentValue(), context);
          }
        } finally {
          cleanup(context);
        }
      }
    }
    

    Reduce函数

    public class Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
    
      /**
       * The <code>Context</code> passed on to the {@link Reducer} implementations.
       */
      public abstract class Context 
        implements ReduceContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
      }
    
      /**
       * Called once at the start of the task.
       */
      protected void setup(Context context
                           ) throws IOException, InterruptedException {
        // NOTHING
      }
    
      /**
       * This method is called once for each key. Most applications will define
       * their reduce class by overriding this method. The default implementation
       * is an identity function.
       */
      @SuppressWarnings("unchecked")
      protected void reduce(KEYIN key, Iterable<VALUEIN> values, Context context
                            ) throws IOException, InterruptedException {
        for(VALUEIN value: values) {
          context.write((KEYOUT) key, (VALUEOUT) value);
        }
      }
    
      /**
       * Called once at the end of the task.
       */
      protected void cleanup(Context context
                             ) throws IOException, InterruptedException {
        // NOTHING
      }
    
      /**
       * Advanced application writers can use the 
       * {@link #run(org.apache.hadoop.mapreduce.Reducer.Context)} method to
       * control how the reduce task works.
       */
      public void run(Context context) throws IOException, InterruptedException {
        setup(context);
        try {
          while (context.nextKey()) {
            reduce(context.getCurrentKey(), context.getValues(), context);
            // If a back up store is used, reset it
            Iterator<VALUEIN> iter = context.getValues().iterator();
            if(iter instanceof ReduceContext.ValueIterator) {
              ((ReduceContext.ValueIterator<VALUEIN>)iter).resetBackupStore();        
            }
          }
        } finally {
          cleanup(context);
        }
      }
    }
    

    MapReduce类型配置





    重点说明几个选项:

    l  setPartitionerClass  :在map阶段定义分区,默认HashPartitioner,主要可以让多个reduce同时执行

    l  setCombinerClass:在分区后的数据,通过Combiner函数,对相同key进行合并,减少网络传输

    l  setSortComparatorClass: Mapreduce默认是按照key排序,不对value排序,若涉及两个指标的排序,可以设置二次排序来完成

    l  setGroupingComparatorClass: 由于二次排序,map的输出key是组合键,但有时需要按照原来的key传递到对应的reduce上,需要重写分组,可以减少reduce的调用次数




    展开全文
  • json_serializable 包使用 source_gen API 来生成序列化代码,并会为您编写 fromJson 构造函数(及 toJson 方法)。 注:json_serializable 链接 https://pub.dartlang.org/packages/json_serializable 将...
  • AKKA序列化

    千次阅读 2017-10-18 21:44:56
    序列化 Akka有内置的序列化扩展,你可以使用内置的序列化器,也可以自定义。 序列化机制可以在Akka内部用于序列化消息,也可以用于专门序列化。 用法 配置 Akka要想知道那个序列化器用于那些消息,你需要编辑...
  • Oracle序列化

    千次阅读 2019-01-04 23:58:58
     序列是用来生成唯一,连续的整数的数据库对象,在Oracle中没有identity约束,通常就使用序列来自动生成主键或唯一键的值.序列可以按升序排列,也可以按降序排列. 二.常用用法  1.创建序列语法:Create sequence 序列...
  • 关于kafka中的序列化

    千次阅读 2019-05-13 10:59:30
    Serializers前言自定义序列化器使用Apache Avro进行序列化将Avro记录与Kafka一起使用 前言 如前面的示例所示,生产者... 最终,你将希望能够序列化通用格式的记录。 我们将首先展示如何编写自己的序列化程序,...
  • 序列化(自动生成序列化UUID)

    千次阅读 2017-03-27 15:40:07
    在日常的应用开发中,我们可能需要让某些对象离开内存...那么该对象就需要实现序列化操作,在Java中可以使用Serializable接口实现对象的序列化,而在Android中既可以使用Serializable接口实现对象序列化也可以使用Par
  • JS表单序列化与反序列化代码

    千次阅读 2016-12-17 21:28:21
    JS表单序列化与反序列化代码. jQuery有这两方法 .serializeArray() 与.serialize(). .serializeArray()返回: Array 描述: 将用作提交的表单元素的值编译成拥有name和value对象组成的数组。例如[ { name: a v
  • 情况下,Json的序列化与反序列化,需要分别对应不同的字段名称,比如说: 序列化的时候要求:{user_name:"xxx"} 而反序列化的时候需要 {userName:"xxx"} 那么Gson该如何实现?   @...
  • 上回老师又布置了一作业,用MFC实现类的序列化功能,于是乎我就滚去摸索mfc的序列化,经过两三周的时间,终于把这会员管理器搭得差不多了,主要的功能均已实现,算是半成品吧,因为还有一小问题没解决(虽说不...
  • Serializer序列化器----反序列化使用

    千次阅读 2018-07-09 00:11:30
    序列化使用 1. 验证 使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。 在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回...
  • Django序列化

    千次阅读 2019-06-01 10:35:23
    一、序列化器作用 1、数据格式转换: 序列化: 对象 -> 字典 反序列化: 字典 -> 对象(OrderedDict) 2、校验参数合法性; 3、保存和修改数据; 二、定义序列化器 通过继承rest_framework.serializers....
  • Django中的序列化

    千次阅读 2018-11-23 15:44:56
    一. 序列化器 ...序列化: 将模型转换成json数据返回给前端,可以序列化一个模型类,也可以序列化多个模型类(many=True) 反序列化: 将json数据转换成模型,反序列化还可以用来进一步验证信息和保存数据 但...
  • 未标记为可序列化

    千次阅读 2014-09-16 18:04:55
    序列化是指将对象实例的状态存储到存储媒体的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与...
  • .net中的序列化和反序列化

    千次阅读 2007-05-23 17:13:00
    一、为什么要使用序列化?最重要的两原因是:将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本;按值将对象从一应用程序域发送至另一应用程序域。例如,序列化可用于在 ASP.NET 中保存...
  • 多个实例对象转换为字典列表 2. 反序列化功能 数据校验:参数完整性,数据类型 数据保存:新增和更新 序列化器类定义 对比 1 : 模型类定义 from django.db import models class 模型类名(models.Model): # 模型...
  • Avro - 简单介绍,Java版 - 序列化与反序列化官方例子 英文原文http://avro.apache.org/docs/1.7.7/gettingstartedjava.htmlHenvealfAvro 简单介绍数据序列化系统。 丰富的数据结构类型; 快速可压缩的二进制数据...
  • 类的序列化

    千次阅读 2006-12-21 17:58:00
    目录 简介持久存储按值封送基本序列化选择性序列化自定义序列化序列化过程的步骤版本控制序列化规则序列化 序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两...
  • 类继承了Serializable接口之后,使用alt+enter快捷键自动创建序列化id idea默认设置没有开启:alt+enter (不同系统和自定义的配置可能会快捷键可能略有不同)发现并没有提供 进入setting→inspections→...
  • C# Serializable标签 和序列化

    千次阅读 2017-09-07 18:37:59
    今天同事开发Webapi接口的时候,发现一很奇怪的情况,返回值中把model类的私有属性格式成json字符串返回了。和同事看了半天发现是 [Serializable]这标签的原因。同事查找了一下这标签的含义,我先保存一下,...
  • 表单序列化与get,post请求

    千次阅读 2016-07-24 22:08:10
    表单序列化 随着Ajax的出现,表单序列化已经成为一种常见需求。在JS中,可以利用表单字段的type属性,连同name和value属性一起实现对表单的序列化。在编写代码前,先了解一下表单提交期间,浏览器是怎么样将数据...
  • DRF序列化器详细使用

    千次阅读 2018-07-19 09:10:25
    视图的功能:说白了就是接收前端请求,进行数据处理 ...最原始的视图可以实现这样的逻辑处理,但是针对不同的请求,需要在类视图中定义多个方法实现各自的处理,这样是可以解决问题,但是存在一个缺陷,...
  • Jarvis OJ PHPINFO【审计代码反序列化

    千次阅读 2017-11-02 23:44:04
    个选项会在脚本运行时保持新的值,并在脚本结束时恢复。 session_start(); class OowoO { public $mdzz; function __construct() { $this->mdzz = 'phpinfo();'; } function __destruct() { eval($this...
  • 因为浏览器对于json数据支持非常好,有很内建的函数支持。xml数据格式在webservice中应用最为广泛,但是相比于json,它的数据更加冗余,因为需要成对的闭合标签。json使用了键值对的方式,不仅压缩了一定的数据...
  • DRF Serializer序列化器使用

    千次阅读 2018-12-19 21:39:52
    笔记:Serializer序列化器 1,序列化器的作用: DRF框架是基于Django框架的.而DRF Serializer序列化器可以实现接口开发的高度复用. 1,进行数据的校验 2,对数据对象进行转换 1,定义Serializer Django REST framework中...
  • 高性能序列化工具Google Protobuf的使用DEMO

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 137,524
精华内容 55,009
关键字:

多个选项序列化