第七章 (类型转换)Type Convertion

AirDreamer:基于世界模型的无人机通用自主导航框架 世界模型是当前具身智能与自主系统的核心基础概念,指系统对环境动态、物理规律及因果关系的内在表征能力。其原理在于构建可微分、可推演的隐式状态空间,而非依赖静态地图或黑箱策略。技术价值体现在显著提升决策鲁棒性、降低仿真到现实迁移成本,并支持不确定性感知与反事实规划。典型应用场景包括GPS拒止环境下的室内巡检、强干扰条件下的电力线路识别、FPV竞速辅助等需要实时理解物理世界的任务。AirDreamer正是将世界模型深度融入导航闭环的代表性框架,尤其以Mirage架构实现3D空间记忆的物理约束化latent建模,为 阅读详情

第七章 Type Convertion

为什么会有类型转换?

HTTP协议中传递的任何内容都是String类型的,所以一旦我们在服务器上需要一个非String类型的对象,例如:int或者Date,那么我们就需要在收到HTTP请求的数据的时候,首先将String类型的数据变换为我们需要的对应类型的数据,之后再使用。这个过程就是类型转换

类型转换在Struts2中是透明的,即Struts2内置了类型转换机制。

 
转换原理:
以一个例子来说明如何使用Struts2内置的类型转换功能。加入我们希望用户在画面上输入一个字符形式的坐标点,例如(33,2)而我们希望在程序中得到一个Point(33, 2)的类型与之对应。
要想达到上面的功能我们需要一个名字位:ActionName-conversion.properties的文件,在文件中定义Action中的属性和画面字段之间的转换关系。例如:

point = com.jpleasure.convertor.PointConverter

也就是说画面一个叫做point的项目(input类型,name为point)提交到服务器上之后,在向Action中的point属性赋值之前需要使用PointConverter将字符串转换为Point类,在Action中的point属性向画面显示的时候需要使用PointConverter将Point类转换为字符串类型。
其中PointConverter需要实现ognl.TypeConverter接口。TypeConverter有两个接口,一个负责将字符串转变为对象类型,另一个负责将对象类型转换为字符串类型,分别对应着内容的提交和显示。
有些时候我们希望所有的Point类在默认的情况下使用PointConverter来转换,这时候我们需要定义全局的Converter类。这可以在xwork-conversion.properties文件中定义,例如:
com.jpleasure.Point = com.jpleasure.convertor.PointConverter
在Struts2中提供了一个TypeConverter接口的默认实现:
org.apache.struts2.action.util.StrutsTypeConverter
这个类有两个默认的抽象转换方法和performFallbackConversion,performFallbackConversion方法负责处理类型转换出错的处理。
在 自定义TypeConverter的时候,可以实现TypeConverter接口,之后编写TypeConverter的转换方法,也可以从 StrutsTypeConverter继承而来,StrutsTypeConverter本身实现了TypeConverter接口,并且实现了基本的 转换方法。
内建的转换:
Struts2内建了对以下类型的转换的支持:
String
boolean / Boolean
char / Character
int / Integer, float / Float, long / Long, double / Double
dates - 使用HTTP 请求对应地域(Locale)的SHORT形式转换字符串和日期类型。
arrays -每一个字符串内容可以被转换为不同的对象
collections - 转换为Collection类型,默认为ArrayList类型,其中包含String类型。
对于Array类型和Collection类型,需要对其中的每一个元素进行单独的转换。
自定义TypeConverter:
使用如下的代码自定义需要的TypeConverter
public class MyConverter extends StrutsTypeConverter {
    public Object convertFromString(Map context, String[] values, Class toClass) {
       .....
    }
    public String convertToString(Map context, Object o) {
       .....
    }
 }
为了让Struts2框架发现类型转换的错误,需要在出错的情况下在上述的两个方法中抛出XWorkException或者TypeConversionException。

我们使用一个例子来展现如何实现TypeConvertor类型:

// Point 类
package com.jpleasure.conversion;

/**
 * Created by IntelliJ IDEA.
 * User: ma.zhao@dl.cn
 * Date: 2007/09/04
 * Time: 12:33:43
 * To change this template use File | Settings | File Templates.
 */
public class Point {
    private int x;
    private int y;

    public Point() {

    }
   
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer("Point(");
        sb.append(x).append(", ").append(y).append(")");
        return sb.toString();
    }
}

// PointConvertor 类
package com.jpleasure.conversion;

import org.apache.struts2.util.StrutsTypeConverter;

import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: ma.zhao@dl.cn
 * Date: 2007/09/04
 * Time: 12:34:18
 * To change this template use File | Settings | File Templates.
 */
public class PointConvertor extends StrutsTypeConverter {
   
    // 从字符串转换为对象的方法。
    public Object convertFromString(Map map, String[] strings, Class aClass) {
        if (strings.length > 0) {
            String pointStr = strings[0];
            String[] pointStrArray = pointStr.split(",");
            if (pointStrArray.length == 2) {
                Point p = new Point();
                p.setX(Integer.parseInt(pointStrArray[0]));
                p.setY(Integer.parseInt(pointStrArray[1]));
                return p;
            } else {
                return null;
            }

        } else {
            return null;
        }
    }
   
    // 从对象转换为字符串的方法。
    public String convertToString(Map map, Object o) {
        if (o instanceof Point) {
            return o.toString();
        } else {
            return "";
        }
    }
}

// 测试用PointAction类
package com.jpleasure.action;

import com.jpleasure.conversion.Point;
import com.opensymphony.xwork2.ActionSupport;

/**
 * Created by IntelliJ IDEA.
 * User: ma.zhao@dl.cn
 * Date: 2007/09/04
 * Time: 12:45:11
 * To change this template use File | Settings | File Templates.
 */
public class PointAction extends ActionSupport {
    private Point point;

    public Point getPoint() {
        return point;
    }

    public void setPoint(Point point) {
        this.point = point;
    }

    public String execute() {
        return SUCCESS;
    }
}

// JSP文件
<%--
  Created by IntelliJ IDEA.
  User: ma.zhao@dl.cn
  Date: 2007/09/04
  Time: 12:47:40
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head><title>Point Page</title></head>
<body>
<s:form action="point" namespace="/point" method="post">
    <s:textfield name="point"/>

    <s:property value="point"/>
    <s:submit/>
</s:form>
</body>
</html>


// PointAction配置文件类。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <package name="point" namespace="/point" extends="struts-default">

        <action name="point" class="com.jpleasure.action.PointAction">
            <result>/point/Point.jsp</result>
            <!-- 定义input的result是为了处理转换出错的情况,在输入格式不正确的情况下转移到这个画面 -->
            <result name="input">/point/Point.jsp</result>
        </action>
        <!-- Add actions here -->
    </package>
</struts>

复杂的类型转换:
(1)处理Null值
有些时候我们会被NullPointerException搞的焦头烂额,为什么系统不能为我们定义了但是没有初始化的对象建立一个空的Object的引用呢?Struts2有这个功能,但是在默认情况下Struts2关闭了这个功能,要想开启这个功能,需要在ParameterInterceptor开始处理参数之前在ValueStack中将一个值开启,这个值是:
InstantiatingNullHandler.CREATE_NULL_OBJECTS。
在Java代码中InstantiatingNullHandler.CREATE_NULL_OBJECTS的值是:xwork.NullHandler.createNullObjects
创建空值对象的规则为:
  • 如果属性声明为Collection或List, 将返回一个ArrayList并赋值给空引用.
  • 如果属性声明为Map, 将返回一个HashMap并赋值给空引用.
  • 如果空值属性是一个带有无参构造函数的简单Bean, 将使用ObjectFactory.buildBean(java.lang.Class, java.util.Map)方法创建一个实例.

(2)Collection和Map

简单List转换
//JSP代码
<%--
  Created by IntelliJ IDEA.
  User: mazhao
  Date: 2007/09/04
  Time: 12:47:40
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head><title>Point Page</title></head>
<body>
<s:form action="point" namespace="/point" method="post">
    <s:textfield label="Point" name="point"/>

    <s:textfield label="References" name="references"/>
    <s:textfield label="References" name="references"/>
    <s:textfield label="References" name="references"/>
    <s:textfield label="References" name="references"/>
    <s:textfield label="References" name="references"/>
                   

    <s:property value="point"/>
    <s:submit/>
</s:form>
</body>
</html>

//Action代码
package com.jpleasure.action;

import com.jpleasure.conversion.Point;
import com.opensymphony.xwork2.ActionSupport;

import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: ma.zhao@dl.cn
 * Date: 2007/09/04
 * Time: 12:45:11
 * To change this template use File | Settings | File Templates.
 */
public class PointAction extends ActionSupport {
    private Point point;
    private List references;

    public Point getPoint() {
        return point;
    }

    public void setPoint(Point point) {
        this.point = point;
    }

    public List getReferences() {
        return references;
    }

    public void setReferences(List references) {
        this.references = references;
    }

    public String execute() {

        if(references == null) {
            System.out.println("references is null");
        } else {
            System.out.println("references length is:" + references.size());
           
            for(Object s: references) {
                System.out.println("" + s);
            }
        }

        return SUCCESS;
    }
}

对象类型List转换(key-value pair 方式)
// Person 类型

package org.apache.struts2.showcase.conversion;

import java.io.Serializable;

/**
 *
 */
public class Person implements Serializable {
    private String name;
    private Integer age;

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

    public void setAge(Integer age) { this.age = age; }
    public Integer getAge() { return this.age; }
}

// PersionAction 类型

 package org.apache.struts2.showcase.conversion;

import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

/**
 *
 */
public class PersonAction extends ActionSupport {

    private List persons;

    public List getPersons() { return persons; }
    public void setPersons(List persons) { this.persons = persons; }

 

    public String input() throws Exception {
        return SUCCESS;
    }

    public String submit() throws Exception {
        return SUCCESS;
    }
}
// PersonAction转化配置文件PersonAction-conversion.properties

 

# PersonAction中persons属性(List类型)中元素的类型

Element_persons=org.apache.struts2.showcase.conversion.Person

 

// JSP部分代码

 <s:iterator value="new int[3]" status="stat">
        <s:textfield    label="%{'Person '+#stat.index+' Name'}"
                        name="%{'persons['+#stat.index+'].name'}" />
        <s:textfield    label="%{'Person '+#stat.index+' Age'}"
                        name="%{'persons['+#stat.index+'].age'}" />
  </s:iterator>
其中stat记录了当前循环的信息,其中stat.index表示当前循环的下标。

所以上述代码会生成如下的代码:

<s:textfield    label="Person 1 Name"
                name="persons[0].name" />
<s:textfield    label="Person 1 Age"
                name="persons[0].age" />
<s:textfield    label="Person 2 Name"
                name="persons[1].name" />
<s:textfield    label="Person 2 Age"
                name="persons[1].age" />
<s:textfield    label="Person 3 Name"
                name="persons[2].name" />
<s:textfield    label="Person 3 Age"
                name="persons[2].age" />

 

对象类型List转换(value 方式)

// Address 类型 

package org.apache.struts2.showcase.conversion;


/**
 * @version $Date: 2006-11-23 12:31:52 -0500 (Thu, 23 Nov 2006) $ $Id: Address.java 478625 2006-11-23 17:31:52Z wsmoak $
 */
public class Address {

    private String id;
    private String address;

    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getAddress() { return address; }
    public void setAddress(String address) { this.address = address; }

}

// AddressAction 类型

 package org.apache.struts2.showcase.conversion;

import java.util.LinkedHashSet;
import java.util.Set;

import com.opensymphony.xwork2.ActionSupport;

/**
 * @version $Date: 2006-11-23 12:31:52 -0500 (Thu, 23 Nov 2006) $ $Id: AddressAction.java 478625 2006-11-23 17:31:52Z wsmoak $
 */
public class AddressAction extends ActionSupport {

    private Set addresses = new LinkedHashSet();

    public Set getAddresses() { return addresses; }
    public void setAddresses(Set addresses) { this.addresses = addresses; }


    public String input() throws Exception {
        return SUCCESS;
    }

    public String submit() throws Exception {
        System.out.println(addresses);
        return SUCCESS;
    }
}

 

//AddressAction转换配置文件AddressAction-conversion.properties

KeyProperty_addresses=id
Element_addresses=org.apache.struts2.showcase.conversion.Address
CreateIfNull_addresses=true

 

// JSP代码 

<s:form action="submitAddressesInfo" namespace="/conversion">
  <s:iterator value="%{new int[3]}" status="stat">
   <s:textfield label="%{'Address '+#stat.index}"
        name="%{'addresses(//'id'+#stat.index+'//').address'}" />
  </s:iterator>
  <s:submit />
 </s:form>

 

 上述代码会转换为:

<s:form action="submitAddressInfo" namespace="/conversion">
  <s:textfield label="Address 0"
      name="addresses('id0')" />
  <s:textfield label="Address 1"
      name="addresses('id1')" />
  <s:textfield label="Address 2"
      name="addresses('id2')" />
  <s:submit />
 </s:form>

 

注意两个地方:

第一,没有向服务器提交Address的id属性,那么Address的id属性是什么呢?
KeyProperty_addresses=id表示向服务器提交的内容的key部分("id0”, "id1”, "id2”)会被认定为Addredd的id。

第二,CreateIfNull_addresses=true表示及时客户端没有向服务器提交任何Address内容,服务器也会为AddressAction的addresses 建立一个长度为0的Set。

 

相关的一些经验

开发的过程中不要一味的使用String类型,使用String类型无论在处理的速度还是内存的使用上都不是最好的方式。一般情况下,Java的模型类(JavaBean, Action等都可以视为Java模型类,因为其中表示了模型的信息),一般情况下需要和数据库中的类型一致。这样才能保证最好的性能。

那么像java.util.Date,Integer等类型需要表示到JSP页面上的时候还是需要表示为String类型的,但是Struts2都已经帮助实现了,所以请使用具体的类型吧,不要总是使用String类型。

 

 

用R语言的type.convert函数优化数据类型转换 用R语言的type.convert函数优化数据类型转换在R语言中,经常需要将数据从一个类型转换为另一个类型。为了简化这个过程,R提供了type.convert函数,它可以根据数据的内容自动选择最适合的数据类型。本文将介绍如何使用type.convert函数以及它的一些常见用法和注意事项。 阅读详情

相关推荐

R语言使用type.convert函数将数据转化为最合适的类型

R语言使用type.convert函数将数据转化为最合适的类型

statistics+insight+vista+power 887

java类型转换工具类(TypeConversionUtils)

TypeConversionUtils是一个Java类型转换工具类,它提供了各种类型之间的转换方法。支持基本数据类型和包装类之间的转换:TypeConversionUtils可以实现从基本数据类型到包装类的转换,以及从包装类到基本数据类型的转换。例如,可以将int类型转换为Integer类型,或将Integer类型转换为int类型。支持字符串和基本数据类型或包装类之间的转换:TypeConversionUtils可以将字符串转换为指定的基本数据类型或包装类,以及将基本数据类型或包装类转换为字符串。

Flying_Fish_roe的博客 1291

R语言type.convert函数函数将当前向量从原来的类(class)转换为最合适的新类(character to integer、内容是数值)、(chr to factor、内容包含字符串)

R语言type.convert函数函数将当前向量从原来的类(class)转换为最合适的新类(character to integer、向量内容是数值)、(character to factor、向量内容包字符串)

data+scenario+science+insight 1027

Struts2原创学习笔记

创建Action类1、简单的POJO2、实现接口com.opensymphony.xwork2.Action3、继承com.opensymphony.xwork2.ActionSupport类第三种为常用方式:提供了获取国际化信息的方法、数据校验的方法、默认用户请求的execute方法,同时还增加了对验证、本地化等的支持。还提供了5个字符串类型的静态常量SUCCESS 正常NONE 正常,...

qq_976987735的博客 295

UAP数据类型转换工具类

UAP数据类型转换工具类public class TypeConversionUtil {} Date与String类型转换 Object转String 字符串数组转String

保姆级教程:从零到飞,用QGC地面站搞定PX4无人机全流程配置(含避坑指南)

本文提供了一份详细的QGC地面站使用教程,指导用户从零开始配置PX4无人机,涵盖固件烧录、传感器校准、遥控器设置及航点规划等关键步骤,并包含实用的避坑指南,帮助新手顺利完成首飞。

weixin_30329623的博客 219

Type Conversion(类型转换)

目录一、强制类型转换 和 隐式类型转换二、强制类型转换三、隐式类型转换 一、强制类型转换 和 隐式类型转换 '123' == 123; // true '' == null; // false '' == 0; // true [] == 0; // true [] == ''; // true [] == []; // false [] == ![]; // true [] -> 0 ; ![] -> false -> 0 null == undefin

SeriousLose 1546

设备接入与APP(应用程序)接入华为云iotDA平台的详细操作步骤及获取方式

设备及APP(应用程序) 登录 IoTDA 平台所需的 入场与操作清单内容,提供逐项详细操作步骤和获取方式,并穿插贴士便于理解与实际操作落地。内容基于 华为云 IoTDA 控制台 和 IAM 控制台 的实际使用路径整理。

hy行者勇哥的博客 3058

java的type转化class_第七章 (类型转换)Type Convertion

第七章 Type Convertion为什么会有类型转换?HTTP协议中传递的任何内容都是String类型的,所以一旦我们在服务器上需要一个非String类型的对象,例如:int或者Date,那么我们就需要在收到HTTP请求的数据的时候,首先将String类型的数据变换为我们需要的对应类型的数据,之后再使用。这个过程就是类型转换类型转换在Struts2中是透明的,即Struts2内置了类型转换机制...

weixin_42561249的博客 1645

10年上位机开发踩过的20个坑:C#通信/线程/UI适配避坑指南

通信层:所有通信操作异步化、异常全覆盖,加断线重连+心跳检测,多设备隔离资源;线程层:UI更新必做跨线程判断,共享数据加锁,线程池限流,异常不静默;UI层:适配高分屏/DPI,用布局容器替代固定坐标,多屏场景绑定主屏幕。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 904

高云FPGA系列教程(7):ARM GPIO外部中断

高云GN1NSR-4C共有16个GPIO,每个GPIO可配置成输入或输出模式,支持中断输入,触发方式可选择:上升沿、下降沿、高电平、低电平触发。中断优先级可通过NVIC进行设置,支持 0-7 级可编程中断优先级。

whik1194的博客 1375

深入分析Spring Type Conversion数据转换

  Spring 3 推出了全新的数据类型之间的转换以替换PropertyEditor转换模式,但网上并没有很好的源码解读。Spring MVC是如何用这套转换体系将页面中的数据转成相应的业务对象的呢?首先让我们看看在不使用Spring 容器的情况下,如何使用Spring的类型转换功能。 简单使用 首先我们定义一个类,Point,表示一个点,有横作标与纵...

everyok的博客 1998

【局部规划模块曲线算法】曲线平滑介绍

本文先对轨迹平滑问题做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容(1)适合给移动机器人运动的路径【满足运动学,高阶平滑】(2)高阶的运动学不能够突变的【至少三阶的加速度不能突变,最好四阶的jerk和五阶的snap也不能突变】(3)在转弯的地方不会停下来(4)加减速均衡,节省能量(5)节省时间的。

qq_35635374的博客 5715

C++之转换函数(convertion function)

目录一 类转换为其他类型二 double转换为Fraction 本文介绍一下C++的转换函数,例子是基于侯捷老师的关于一个分数类的例子,然后加上我自己的一些理解。 一 类转换为其他类型 类转换为其他类型,这里的其他类型可以是任何类型,如int、double甚至是你定义的一个类,至于怎么写,就是设计的人的事情了。 下面我以转换为double型为例,请看下面的例子: #include <iostream> #include <string> using namespace std;

weixin_43744293的博客 3018

uniapp - 实现APP后台持续定位+手机息屏后能持续上传位置信息数据,详解后台保活持续运行+手机锁屏保证后台持续/实时定位的解决方案及示例源码(完美兼容安卓android与苹果ios系统手机)

使用uniapp开发app实现后台保活定位能力,uniapp实时定位保活 息屏定位后台运行,uniapp APP实时定位高德 后台运行 支持锁屏息屏运行,持续获取定位信息,uniapp App端后台间隔时间发送定位功能实现,UniApp实现手机应用常活,固定时间内上传手机位置信息,后台(或锁屏)持续/实时定位的实现方案,uni-app后台持续定位,锁屏后能持续上传位置信息,实现后台定位持续无限制定位高德定位,百度定位,UniApp后台持续定位保如何在APP退到后台时保持定位服务,uniapp 切换app仍能

🏆 前端领域优质创作者 1万+

在MATLAB中将C语言代码转化为可执行的mexw64文件

这样,您可以将高效的C语言算法集成到MATLAB环境中,以便更好地利用MATLAB的功能和特性。请记住,在使用mex转换C语言代码之前,您需要正确编写和测试C语言代码,并确保它与MATLAB的mex接口兼容。MATLAB是一种功能强大的数值计算软件,它提供了一个机制,可以将C语言代码转化为MATLAB可执行的mexw64文件。在上述命令中,"-output"选项指定生成的mex文件的名称,"myfunction"是您选择的名称,"myfunction.c"是要编译的C语言源文件。步骤1:编写C语言代码。

CodeRoarX的博客 1427

DM实体转化

using System; using System.Collections.Generic; using System.Data; using System.Reflection; namespace Syit.AHSZY.Mobile.DataServices {     ///     /// 数据服务基类对象     ///

yangtang_newton的专栏 784

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Simulink Data Type Conversion模块使用笔记

Data Type Conversion 是建模很常用的数据转换模块,在这里我想介绍一下在模型定标过程中Vonvert模块使用心得。

weixin_41958861的博客 1万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

WINCC7.3破解文件

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

C++ - 类中定义类型转换(type convertion) 详解

类中定义类型转换(type convertion) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/15498591 类的转换操作符(conversion operator),形式:operator type() const; 意思是把ClassA->type; 即类中的成员变量输出为t...

weixin_34354945的博客 288

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

上一篇: 第四章 Taglib Struts标签库
下一篇: 附录三 文件上传和下载
struts2
博客等级 码龄19年 885粉丝 103原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值