Java IO -- 序列化

反序列化(Unserialize)漏洞详解 序列化和反序列化漏洞分析   序列化(serialize) 就将对象的状态信息转换为可以存储或传输的形式的过程 在序列化期间,对象将当前的状态写入到临时或持久性的存储区 【将状态信息保存为字符串】。   反序列化(unserialize) 就是把序列化之后的字符串在转化为对象。 其实在序列化的过程中是没有任何的漏洞的,产生漏洞的主要的原因就是在反序列化的过程中,通过我们的恶意篡改会产生魔法函数绕过,字符逃逸,远程命令执行等漏洞,最早发现这些漏洞的大佬是真的牛。 一、简单的魔法函数 魔法函数 调用 阅读详情

序列化与反序列化

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等。在网络传输过程中,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象。这个相反的过程又称为反序列化。

Java对象的序列化与反序列化

在Java中,我们可以通过多种方式来创建对象,并且只要对象没有被回收我们都可以复用该对象。但是,我们创建出来的这些Java对象都是存在于JVM的堆内存中的。只有JVM处于运行状态的时候,这些对象才可能存在。一旦JVM停止运行,这些对象的状态也就随之而丢失了。

但是在真实的应用场景中,我们需要将这些对象持久化下来,并且能够在需要的时候把对象重新读取出来。Java的对象序列化可以帮助我们实现该功能。

对象序列化机制(object serialization)是Java语言内建的一种对象持久化方式,通过对象序列化,可以把对象的状态保存为字节数组,并且可以在有需要的时候将这个字节数组通过反序列化的方式再转换成对象。对象序列化可以很容易的在JVM中的活动对象和字节数组(流)之间进行转换。

在Java中,对象的序列化与反序列化被广泛应用到RMI(远程方法调用)及网络传输中。

相关接口及类

Java为了方便开发人员将Java对象进行序列化及反序列化提供了一套方便的API来支持。其中包括以下接口和类:

java.io.Serializable

java.io.Externalizable

ObjectOutput

ObjectInput

ObjectOutputStream

ObjectInputStream

Serializable 接口

类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。 (该接口并没有方法和字段,为什么只有实现了该接口的类的对象才能被序列化呢?)

当试图对一个对象进行序列化的时候,如果遇到不支持 Serializable 接口的对象。在此情况下,将抛出 NotSerializableException。

如果要序列化的类有父类,要想同时将在父类中定义过的变量持久化下来,那么父类也应该集成java.io.Serializable接口。

下面是一个实现了java.io.Serializable接口的类

package com.hollischaung.serialization.SerializableDemos;
import java.io.Serializable;
/**
 * Created by hollis on 16/2/17.
 * 实现Serializable接口
 */
public class User1 implements Serializable {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

通过下面的代码进行序列化及反序列化

package com.hollischaung.serialization.SerializableDemos;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.*;
/**
 * Created by hollis on 16/2/17.
 * SerializableDemo1 结合SerializableDemo2说明 一个类要想被序列化必须实现Serializable接口
 */
 public class SerializableDemo1 {

    public static void main(String[] args) {
        //Initializes The Object
        User1 user = new User1();
        user.setName("hollis");
        user.setAge(23);
        System.out.println(user);

        //Write Obj to File
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
            oos.writeObject(user);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(oos);
        }

        //Read Obj from File
        File file = new File("tempFile");
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream(file));
            User1 newUser = (User1) ois.readObject();
            System.out.println(newUser);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(ois);
            try {
                FileUtils.forceDelete(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

//OutPut:
//User{name='hollis', age=23}
//User{name='hollis', age=23}

Externalizable接口

除了Serializable 之外,java中还提供了另一个序列化接口Externalizable

为了了解Externalizable接口和Serializable接口的区别,先来看代码,我们把上面的代码改成使用Externalizable的形式。

package com.hollischaung.serialization.ExternalizableDemos;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

/**
 * Created by hollis on 16/2/17.
 * 实现Externalizable接口
 */
public class User1 implements Externalizable {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void writeExternal(ObjectOutput out) throws IOException {

    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.hollischaung.serialization.ExternalizableDemos;

import java.io.*;

/**
 * Created by hollis on 16/2/17.
 */
public class ExternalizableDemo1 {

    //为了便于理解和节省篇幅,忽略关闭流操作及删除文件操作。真正编码时千万不要忘记
    //IOException直接抛出
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Write Obj to file
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
        User1 user = new User1();
        user.setName("hollis");
        user.setAge(23);
        oos.writeObject(user);
        //Read Obj from file
        File file = new File("tempFile");
        ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file));
        User1 newInstance = (User1) ois.readObject();
        //output
        System.out.println(newInstance);
    }
}
//OutPut:
//User{name='null', age=0}

通过上面的实例可以发现,对User1类进行序列化及反序列化之后得到的对象的所有属性的值都变成了默认值。也就是说,之前的那个对象的状态并没有被持久化下来。这就是Externalizable接口和Serializable接口的区别:

Externalizable继承了Serializable,该接口中定义了两个抽象方法:writeExternal()与readExternal()。当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。由于上面的代码中,并没有在这两个方法中定义序列化实现细节,所以输出的内容为空。还有一点值得注意:在使用Externalizable进行序列化的时候,在读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。所以,实现Externalizable接口的类必须要提供一个public的无参的构造器。

按照要求修改之后代码如下:

package com.hollischaung.serialization.ExternalizableDemos;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

/**
 * Created by hollis on 16/2/17.
 * 实现Externalizable接口,并实现writeExternal和readExternal方法
 */
public class User2 implements Externalizable {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.writeInt(age);
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        age = in.readInt();
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.hollischaung.serialization.ExternalizableDemos;

import java.io.*;

/**
 * Created by hollis on 16/2/17.
 */
public class ExternalizableDemo2 {

    //为了便于理解和节省篇幅,忽略关闭流操作及删除文件操作。真正编码时千万不要忘记
    //IOException直接抛出
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Write Obj to file
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
        User2 user = new User2();
        user.setName("hollis");
        user.setAge(23);
        oos.writeObject(user);
        //Read Obj from file
        File file = new File("tempFile");
        ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file));
        User2 newInstance = (User2) ois.readObject();
        //output
        System.out.println(newInstance);
    }
}
//OutPut:
//User{name='hollis', age=23}

这次,就可以把之前的对象状态持久化下来了。

如果User类中没有无参数的构造函数,在运行时会抛出异常:java.io.InvalidClassException

ObjectOutput和ObjectInput 接口

ObjectInput接口 扩展自 DataInput 接口以包含对象的读操作。

DataInput 接口用于从二进制流中读取字节,并根据所有 Java 基本类型数据进行重构。同时还提供根据 UTF-8 修改版格式的数据重构 String 的工具。

对于此接口中的所有数据读取例程来说,如果在读取所需字节数之前已经到达文件末尾 (end of file),则将抛出 EOFException(IOException 的一种)。如果因为到达文件末尾以外的其他原因无法读取字节,则将抛出 IOException 而不是 EOFException。尤其是,在输入流已关闭的情况下,将抛出 IOException。

ObjectOutput 扩展 DataOutput 接口以包含对象的写入操作。

DataOutput 接口用于将数据从任意 Java 基本类型转换为一系列字节,并将这些字节写入二进制流。同时还提供了一个将 String 转换成 UTF-8 修改版格式并写入所得到的系列字节的工具。

对于此接口中写入字节的所有方法,如果由于某种原因无法写入某个字节,则抛出 IOException。

ObjectOutputStream类和ObjectInputStream类

通过前面的代码片段中我们也能知道,我们一般使用ObjectOutputStream的writeObject方法把一个对象进行持久化。再使用ObjectInputStream的readObject从持久化存储中把对象读取出来。

Transient 关键字

Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

序列化ID

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID)

序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。

本文转载自:Hollis: Java对象的序列化与反序列化

java安全(五)java反序列化 序列化 在调用RMI时,发现接收发送数据都是反序列化数据. 例如JSON和XML等语言,在网络上传递信息,都会用到一些格式化数据,大多数处理方法中,JSON和XML支持的数据类型就是基本数据类型,整型、浮点型、字符串、布尔等,如果开发者希望在传输数据的时候直接传输一个对象,那么就不得不想办法扩展基础的JSON(XML)语法。比如,Jackson和Fastjson这类序列化库,在JSON(XML)的基础上进行改造,通过特定的语法来传递对象. RMI使用java等语言内置的序列化方法,将一个对象转化成一串二进制 阅读详情

相关推荐

Java中的序列化与反序列化

序列化(Serialization)与反序列化(Deserialization)是编程中常见的两个概念,它们主要涉及到将数据结构或对象状态转换为可以存储或传输的格式,以及将存储或传输的格式转换回原始的数据结构或对象状态的过程。这两个过程在数据持久化、网络通信、对象深拷贝等多个场景中发挥着重要作用。

yuiezt的专栏 4231

序列化与反序列化介绍

序列化与反序列化介绍

shsh1234567890的博客 1万+

给麒麟KylinOS服务器加把锁:手把手配置符合等保要求的密码强度策略

本文详细介绍了如何在麒麟KylinOS服务器上配置符合等保要求的密码强度策略,包括pwquality.conf和login.defs的核心参数设置、等保合规的进阶配置技巧以及企业环境中的平衡艺术。通过实战案例和测试方法,帮助管理员构建坚固的密码防线,确保系统安全。

weixin_33749242的博客 419

一文带你了解序列化与反序列化基本原理与操作

序列化是指将对象转换为字节序列的过程,以便于存储或传输。在序列化过程中,对象的状态信息将被转换为字节流,可以保存到文件中或通过网络传输给其他计算机。反序列化则是将字节序列恢复为对象的过程。通过反序列化操作,可以从存储的字节流中还原对象的状态。这使得可以在程序重启后,读取保存的字节流并重新构造对象,从而快速恢复对象的状态。在分布式系统中,可以将对象进行序列化,并在不同的计算机之间进行传输。接收方可以通过反序列化操作将字节序列转换为可操作的对象。某些远程通信框架使用序列化和反序列化来实现远程方法调用。

m0_68987535的博客 1万+

AI+Xmind自动生成测试用例(思维导图格式)

最后:我是Walker,一个热爱分享编程知识的程序员,希望能够帮助到你!

Think_and_work的博客 2334

Visual Studio Community与Visual Studio Community与VS Code有啥区别

Visual Studio Code提供了基本的代码编辑、调试和版本控制功能,以及丰富的插件和扩展库。Visual Studio Community和Visual Studio Code在功能上有很大的差异,Visual Studio Community提供了比Visual Studio Code更多的功能,包括代码重构、智能提示、图形化设计等。他的优势在于它的轻量级和灵活性。此外,Visual Studio Code还具有丰富的扩展和插件生态系统,用户可以通过安装插件来扩展其功能,从而满足自己的需求。

m0_56551554的博客 2845

Java IO对象处理流以及序列化

Java IO对象处理流以及序列化

WYSCODER的博客 1467

万字详解Java中的IO及序列化

想要实现自定义序列化和反序列化,可以在被序列化的类中增加和readObject方法来实现。举个例子,看一下中的是如何自定义序列化的:ArrayList实现了接口且有自定义,那么我们就可以对它进行序列化及反序列化。ArrayList底层是通过数组实现的,其中数组其实就是用来保存列表中的元素的。因为是被transient修饰的,所以这个成员变量不会被序列化而保留下来。那么为什么却通过序列化和反序列化把List中的元素保留下来了呢?ArrayList。

2401_89221867的博客 740

基于决策树的英雄联盟比赛胜负预测(含完整代码)

在代码中设置随机种子(例如 RANDOM_SEED = 2024)的主要目的是为了确保每次运行代码时,随机过程的结果是一致的。通过绘制不同参数组合下的准确率图,直观地展示了参数对模型性能的影响,帮助读者更好地理解和选择合适的参数。通过设置相同的随机种子(伪随机数),可以确保每次运行代码时,随机数生成器生成的随机数序列是相同的。如果在开发过程中遇到问题,设置固定的随机种子可以帮助你更容易地定位问题,因为每次运行代码时的数据和结果都是一样的。在科学研究和实验中,结果的可重复性是非常重要的。

oisflo的博客 1920

AI上推荐 之 AutoRec与Deep Crossing模型(改变神经网络的复杂程度)

1. 前言 随着信息技术和互联网的发展, 我们已经步入了一个信息过载的时代,这个时代,无论是信息消费者还是信息生产者都遇到了很大的挑战: 信息消费者:如何从大量的信息中找到自己感兴趣的信息? 信息生产者:如何让自己生产的信息脱颖而出, 受到广大用户的关注? 为了解决这个矛盾, 推荐系统应时而生, 并飞速前进,在用户和信息之间架起了一道桥梁,一方面帮助用户发现对自己有价值的信息, 一方面让信息能够展现在对它感兴趣的用户前面。 推荐系统近几年有了深度学习的助推发展之势迅猛, 从前深度学习的传统推荐模型(协

Miracle8070 5669

JAVA IO流及序列化

BIO、NIO、AIO的区别 BIO(同步阻塞式IO) 就是传统的 java.io 包(上面内容),它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用时可靠的线性顺序。它的有点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。 (一个应用独享一个socket连接) NIO(...

whatkevin1984的博客 239

把 ABAP 接到外部世界的几条路, 从 Web Service 到 RFC、BAPI 与 IDoc 的完整理解

摘要: ABAP 的连接能力是其长期成为企业核心的关键,不仅支持通用协议(HTTP、SOAP、XML),还保留了 SAP 特有的技术(RFC、BAPI、IDoc)。Web Service 是跨系统通信的主轴,依赖 SOAP/WSDL 实现契约化协作,而 Enterprise Service 更强调业务语义的复用与治理。经典技术如 RFC 和 BAPI 因高效稳定仍广泛使用,尤其适合紧耦合场景。ABAP 通过分层工具箱(如代理生成、服务注册)实现灵活集成,平衡新旧技术,满足多样化的企业连接需求。 (字数:15

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 142

Java中的IO及序列化详解

想要实现自定义序列化和反序列化,可以在被序列化的类中增加和readObject方法来实现。举个例子,看一下ArrayList实现了接口且有自定义,那么我们就可以对它进行序列化及反序列化。ArrayList底层是通过数组实现的,其中数组其实就是用来保存列表中的元素的。因为是被transient修饰的,所以这个成员变量不会被序列化而保留下来。那么为什么却通过序列化和反序列化把List中的元素保留下来了呢?ArrayList。

努力分享一些干货 1364

【DRAM存储器五十一】LPDDR5介绍--DFE与Pre-Emphasis

简述LPDDR5的DFE和预加重应用设置

highman110的博客 710

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java IO流 - 序列化流

java IO流 - 序列化流

听海边涛声 851

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

java 序列化 map_数据开发_Java中IO序列化以及RoaringBitmap序列化

JavaIOJava中IO的基本概况,以及在使用过程中涉及到的序列化,同时将Roaringbitmap的序列化以及反序列化做个编写示例JAVA中IO流体系1.四大IO抽象类一、文件 字节流读取和写入:利用文件流实现文件的复制二、文件 字符流使用FileReader与FileWriter实现文本文件的复制三、缓冲 字节流: BufferedInputStream 和 BufferedOutputSt...

weixin_32950005的博客 624

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

java io文件流序列化_Java IO流对象的序列化和反序列化实例详解

Java—IO流 对象的序列化和反序列化序列化的基本操作1.对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化。2.序列化流(ObjectOutputStream),writeObject 方法用于将对象写入输出流中;反序列化流(ObjectInputStream),readObject 方法用于从输入流中读取对象。3.序列化接口(Serializeable)对象必须实现序列化...

weixin_36428079的博客 245

Java—对象序列化,反序列化,IO框架

重定向打印流,可以将本来输出到控制台输出到指定文件。Properties用于读取配置文件。打印流,写入数据最高效方便。注意事项,如代码注释。

qq_34577961的博客 230

java基础----IO序列化Serializable

package com.henu.io; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /* * java.io.Ob...

乔治大哥的博客 500

java 对象序列化 properties IO流

'对象的类需要实现序列化接口' '有一个序列号' import java.io.Serializable; public class Student implements Serializable { private static final long serialVersionUID = 42L; private String name; // private int age; private transient int age; '序列化对象' 'oos.writ..

qq_43141232的博客 253

java io文件流序列化_5.Java中的IO流、File类和序列化

一.File类1.概述:java.io.File:是文件和目录路径类,用于对文件和目录的创建、查找和删除等操作2.File类的四个静态成员变量:public static final char separatorChar:文件名称分隔符的字符表示public static final String separator:文件名称分隔符的字符串表示public static final char...

weixin_36138462的博客 250

java中的序列化类和commons-io框架

序列化流。

luosuss的博客 1002

Java输入输出+对象序列化+新IO

(2018.03.02)File1.File类是java.io包下代表与平台无关的文件和目录;File能新建、删除、重命名文件和目录,File不能访问文件本身。需要使用输入/输出流来访问文件内容本身。2.File类可以使用文件路径字符串来创建File实例,可以是绝对路径或者相对路径(相对于项目工作路径)3.File提供方法操作文件或目录(Java讲义P665)(API:http://tool.os...

Timeless的博客 705

java之文件与IO流及序列化

缓冲流为一种处理流缓冲流缓冲区大小默认为8192字节(一次可读取8192个字节)输入或输出流使用的方法,缓冲输入或缓冲输出流也可以使用转换流为一种处理流转换流应指定编码格式,编码格式为字符串类型,如果不写,则会获取你程序默认的编码格式转换流作用是将字节流和字符流进行转换InputStreamReader是将字节输入流转为字符输入流,OutputStreamWriter是将字符输出流转为字节输出流//序列化版本标识符——格式固定}}}}}......

m0_60027772的博客 736

Java IO之对象的序列化、ObjectInputStream和ObjectOutputStream类

什么是IO流?  byte序列的读写,Java中的IO流是实现输入/输出的基础. Java将数据从源(文件、内存、键盘、网络)读入到内存 中,形成了流,然后将这些流还可以写到另外的目的地(文件、内存、控制台、网络),之所以称为流,是因为这个数据序列在不同时刻所操作的是源的不同部分。按照不同的分类标准,IO流分为不同类型。主要有以下几种方式:按照数据流方向、数据处理的单位和功能。 不管

koozxcv的博客 1万+
上一篇: Java IO -- 字节流 & 字符流
下一篇: Java IO -- 序列化的高级认识
Tennysons
博客等级 码龄10年 0粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值