2.Echarts和RabbiMq

一.Echarts入门

链接: 五分钟上手Echarts入门 案例

二.使用Echarts

1.创建模块

  1. 使用dobbo框架 需要创建stat_service 和stat_interface
  2. stat_service是一个web工程,在这里面需要配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<!-- 监听器监听其他的spring配置文件 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:spring/applicationContext-*.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>
  1. 配置 applicationContext-dubbo.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


    <!--dubbo的应用名称,一般我们都使用项目名称-->
    <dubbo:application name="export_stat_service">
        <!--运维相关-->
        <dubbo:parameter key="qos.enable" value="false"></dubbo:parameter>
    </dubbo:application>

    <!--注册中心,本机的2181端口-->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" ></dubbo:registry>

    <!--非常重要,dubbo提供的访问端口号,8080tomcat容器仅仅是启动项目,真正的访问是这个端口20881-->
    <dubbo:protocol name="dubbo" port="20883"></dubbo:protocol>

    <!--注解支持,dubbo的包扫描-->
    <dubbo:annotation package="cn.itcast.service"></dubbo:annotation>

</beans>
  1. 编写接口和实现类
package cn.itcast.service;

import java.util.List;
import java.util.Map;

public interface StatService {
    List<Map> getFactoryData(String companyId);
    List<Map> getOnlineData(String companyId);
    List<Map> getSellData(String companyId);

}
  1. 编写dao和xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.dao.stat.StatDao">

    <select id="getFactoryData" parameterType="String" resultType="map">

        SELECT
            factory_name as name ,
            SUM(amount) as value
        FROM
            co_contract_product
        WHERE
            company_id = #{companyId}
        GROUP BY
            factory_name
        ORDER BY SUM(amount) DESC
    </select>

    <select id="getOnlineData" parameterType="String">

        SELECT
            product_no as name ,
            SUM(amount) as value
        FROM
            co_contract_product
        WHERE
            company_id =  #{companyId}
        GROUP BY
            product_no
        ORDER BY SUM(amount) DESC
        LIMIT 15
    </select>

    <select id="getSellData" parameterType="String">

        SELECT
            st_online_info.A1 as name,
            a.value as value
        FROM
            st_online_info
        LEFT JOIN (
            SELECT
                DATE_FORMAT(TIME, '%H') AS name,
                COUNT(*) AS value
            FROM
                st_sys_log
            WHERE
                st_sys_log.company_id =  #{companyId}
            GROUP BY
                DATE_FORMAT(TIME, '%H')
        ) a ON a.name=st_online_info.A1
    </select>

</mapper>
  1. 编写controller
package cn.itcast.web.controller.stat;

import cn.itcast.service.StatService;
import cn.itcast.web.controller.BaseController;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;

/**
 * @author cyy
 * @date 2020/3/22 18:43
 */
@RequestMapping(value = "/stat")
@Controller
public class StatController extends BaseController {

    @Reference
    private StatService statService;

//    跳转到统计分析页面
    @RequestMapping(value = "/toCharts")
    public String toCharts(String chartsType){

        return "stat/stat-"+chartsType;
    }


    @RequestMapping(value = "/getFactoryData")
    @ResponseBody
    public List<Map> getFactoryData(){

        return  statService.getFactoryData(companyId);
    }

    @RequestMapping(value = "/getOnlineData")
    @ResponseBody
    public  List<Map> getOnlineData(){

        return statService.getOnlineData(companyId);
    }

    @RequestMapping(value = "/getSellData")
    @ResponseBody
    public List<Map> getSellData(){
        return statService.getSellData(companyId);
    }

}

2. 前台页面访问

3. 根据 官网可进行样式的更换

在这里插入图片描述

        // 指定图表的配置项和数据
        option = {
            xAxis: {
                type: 'category',
                data: titles
            },
            yAxis: {
                type: 'value'
            },
            series: [{
                data: values,
                type: 'line'
            }]
        };

在这里插入图片描述

 option = {
          xAxis: {
              type: 'category',
              data: titles
          },
          yAxis: {
              type: 'value'
          },
          series: [{
              data:values,
              type: 'line',
              smooth: true
          }]
      };

三.邮件发送

1.编写工具类

package cn.itcast.common.utils;


import javax.mail.Address;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class MailUtil {

   //实现邮件发送的方法
   public static void sendMsg(String to ,String subject ,String content) throws Exception{
   	//1. 邮件服务设置
   	Properties props = new Properties();
   	props.setProperty("mail.smtp.host", "smtp.163.com");  //设置主机地址   smtp.qq.com    smtp.sina.com

   	props.setProperty("mail.smtp.auth", "true");//认证

   	//2.产生一个用于邮件发送的Session对象
   	Session session = Session.getInstance(props);

   	//3.产生一个邮件的消息对象
   	MimeMessage message = new MimeMessage(session);

   	//4.设置消息的发送者
   	Address fromAddr = new InternetAddress("邮箱");
   	message.setFrom(fromAddr);

   	//5.设置消息的接收者
   	Address toAddr = new InternetAddress(to);
   	//TO 直接发送  CC抄送    BCC密送
   	message.setRecipient(MimeMessage.RecipientType.TO, toAddr);

   	//6.设置主题
   	message.setSubject(subject);
   	//7.设置正文
   	message.setText(content);

   	//8.准备发送,得到火箭
   	Transport transport = session.getTransport("smtp");
   	//9.设置火箭的发射目标
   	transport.connect("smtp.sina.com", "邮箱", "授权码");
   	//10.发送
   	transport.sendMessage(message, message.getAllRecipients());

   	//11.关闭
   	transport.close();
   }

}

2.在注册的时候给用户发送一封邮件

 @RequestMapping(value = "/edit", name = "保存用户信息")
   public String edit(User user){

       //在实体类中设置企业信息
       user.setCompanyId(companyId);
       user.setCompanyName(companyName);

       //1、判断user.getId,是新建还是编辑
       if (StringUtil.isEmpty(user.getId())){
           //2、调用userService新建
           user.setId(UUID.randomUUID().toString());
           //  !!**new 新增用户时,获取用户的密码**
           String password=user.getPassword();
           user.setPassword(Encrypt.md5(user.getPassword(), user.getEmail()));
      		   userService.save(user);

   	//  !!  **new 新增用户时,需要给用户发送一封邮件**
   		 String to =user.getEmail();
               String subject="主题  ";
               String content ="用户名"+to+"密码为"+password;
               MailUtil.sendMsg(to,subject,content);
 
       }else {
           //3、调用userService编辑
           userService.update(user);
       }

       //4、重定向到list.do
       return "redirect: /system/user/list.do";
   }

3.发送邮件存在问题

  • 邮件发送过慢
  • 解决:异步拆分为两个程序,采用队列的方式进行监听

四.消息中间件

1.了解消息中间件

  • 消息中间件是分布式系统中最重要的组件,主要解决应用解耦,异步消息,流量削峰

2.MQ的两种模式

  1. 队列模式
  • 普通队列:一个提供者发送每条消息,都有一个消费者进行接收
    在这里插入图片描述
  • work模式:一个提供者发送多条消息,有多个消费者进行接收,但是每个消费者只能接收到一条消息,消费者之间消息不能重复(轮询机制发送)
    在这里插入图片描述
  1. 订阅模式
  • fanout模式:一个提供者发送多条消息,同时有多个消费者收到同样的消息
    在这里插入图片描述
  • direct模式:增加一个关键字,一个提供者发送多条消息时,里面包含关键字,多个消费者根据关键字进行过滤,匹配成功的接收到消息
    在这里插入图片描述
  • topic模式:增加一个通配符,一个提供者发送多条消息时,里面包含关键字,多个消费者根据通配符进行过滤,匹配成功的接收到消息
    在这里插入图片描述

五.安装RabbitMq

1.第一步:下载并安装erlang

  1. 需要配置环境变量
变量名:ERLANG_HOME
变量值就是刚才erlang的安装地址,点击确定。
点击“新建”,将%ERLANG_HOME%\bin加入到path中。
  1. cmd 输入erl,看到版本号就说明erlang安装成功了。

2.下载并安装RabbitMQ

  1. 安装rabbitMQ-server
  2. RabbitMQ安装好后接下来安装RabbitMQ-Plugins。打开命令行cd,输入RabbitMQ的sbin目录。
    然后在后面输入rabbitmq-plugins enable rabbitmq_management命令进行安装
    在这里插入图片描述
  3. 在cmd 运行 倒数第二个
    在这里插入图片描述
  4. 访问http://localhost:15672 默认用户名和密码都是guest

3.安装过程中遇到的问题

  • 无法访问15672 提示节点已经在本机存在
  • 解决:在服务中关掉进程,重启计算机,然后在cmd重新执行rabbitmq-server.bat 登陆成功

六.RabbitMQ后台操作

1.添加一个用户

在这里插入图片描述

2.添加一个虚拟主机

在这里插入图片描述
给虚拟主机增加用户

3.MQ端口号

在这里插入图片描述

七.RabbitMQ队列模式

1.队列模式–普通队列(手工回执)

应用场景:并发量不是很大,比如:新增用户发邮件

//6、消费队列
channel.basicConsume("heima123_queue", true, new MyConsumer(channel));

第二个参数代表自动回执,拿到这条消息之后,不管是否消费成功,都进行回执。

回执指的是告诉RabbitMQ,消息已经被消费了,所以消息在RabbitMQ服务里物理删除了。

问题:如果消费者拿到消息之后,处理业务时失败了,发生异常,这条消息就永久消失了。

所以一般第二个参数会设置成false,需要手工进行回执。

用到的场景:消费者在处理完业务时,成功之后才手工回执,如果失败则不用回执。

 //确认收到一个或多个消息
   channel.basicAck(envelope.getDeliveryTag() , false);

2.队列模式–Work模式队列

应用场景:并发量也不是很大,消息消费者需要大量的时间去运行。

消息提供者提供一条消息只需要2秒,消息消费者需要1小时运行。效率就非常低,需要有多个消息消息者进行处理。

举例:前台页面(查询去年双11到今年双11整年的销量):【准备数据】【查询数据】

2.1两个一模一样的消费者

两个一模一样的消费者,每个消费者轮流获取消息,消息并不重复。
在这里插入图片描述

2.2一个消费者处理慢一个消费者处理快

应用场景:多个消费者放在多台电脑上,有的电脑快,有的电脑慢。

生产者生产100条消息,消费者1和消费者2还是轮流获取消息,快的会先处理完,慢的处理的非常慢,获取的消息和两个一模一样的消费者获取的消息是一样的,差异在于处理的速度不同
在这里插入图片描述

2.3每次取消息只取一条

在两个消费者上面设置每次只获取一条消息

     //设置每次取的数量
        channel.basicQos(1);

在这里插入图片描述

八.RabbitMQ订阅模式

1.订阅模式–fanout

应用场景:会员提交订单之后,需要处理几件事:
1、付款;2、保存订单,写入订单表;3、减少库存,写入库存表;4、通知物流,写入物流表;5、通知客服,写入客服表;6、通知营销,写入促销表;7、通知售后,写入安装表;8、通知厂家,厂家发货表

消息生产者声明交换机

// 声明exchange
//参数1: 交换机名称
//参数2: 交换机类型
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

消息消费者绑定交换机

// 绑定队列到交换机
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

2.订阅模式–direct

// 声明exchange
//参数1: 交换机名称
//参数2: 交换机类型
channel.exchangeDeclare(EXCHANGE_NAME, "direct");

消息生产者指定关键字

channel.basicPublish(EXCHANGE_NAME, "back", null, message.getBytes());

消息消费者指定关键字

   // 绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "buy");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "back");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "ask");

3.订阅模式–topic

生产者发送消息

channel.basicPublish(EXCHANGE_NAME, "ask.phone", null, message.getBytes());

消费者绑定交换机

channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "ask.*");

channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "*.*");

九.通过RabbitMQ发送邮件(重点)

1.消息的生产者

1.1 引入依赖

<!--rabbit整合spring-->
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>2.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.5</version>
        </dependency>

1.2 applicationContext-mq.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xmlns:contact="http://www.springframework.org/schema/context"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
	http://www.springframework.org/schema/rabbit/spring-rabbit-2.1.xsd
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
	http://www.springframework.org/schema/context
	https://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <!--包扫描-->
   <context:component-scan base-package="cn.itcast.web"></context:component-scan>

    <!-- 公共部分 -->
    <!-- 创建连接类 连接安装好的 rabbitmq -->
    <bean id="connectionFactory"  class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <property name="virtualHost" value="heima111"></property>
        <!-- username,访问RabbitMQ服务器的账户,默认是guest -->
        <property name="username" value="admin" />
        <!-- username,访问RabbitMQ服务器的密码,默认是guest -->
        <property name="password" value="admin" />
        <!-- host,RabbitMQ服务器地址,默认值"localhost" -->
        <property name="host" value="127.0.0.1" />
        <!-- port,RabbitMQ服务端口,默认值为5672 -->
        <property name="port" value="5672" />
    </bean>

    <rabbit:admin connection-factory="connectionFactory"/>

    <!--解析json , MQ会自动将数据转换成json字符串-->
    <bean id="jackson2JsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"/>
    <!--模版对象 用于发送消息-->
    <rabbit:template id="amqpTemplate"  exchange="test-mq-exchange"  connection-factory="connectionFactory"  message-converter="jackson2JsonMessageConverter"  />

    <!--配置队列  durable="true" 表示消息需要持久化 即服务器崩溃会数据不会丢失 auto-delete="false" 表示服务器停止后数据是否自动删除  exclusive:表示该消息队列是否只在当前connection生效。默认false。 -->
    <rabbit:queue id="test_queue_key2"  name="mail.send" durable="true" auto-delete="false" exclusive="false" />

    <!--交换机
        定义消息队列,durable:是否持久化,如果想在RabbitMQ退出或崩溃的时候,不会失去所有的queue和消息,需要同时标志队列(queue)和交换机(exchange)是持久化的,即rabbit:queue标签和rabbit:direct-exchange中的durable=true,而消息(message)默认是持久化的可以看类org.springframework.amqp.core.MessageProperties中的属性public static final MessageDeliveryMode DEFAULT_DELIVERY_MODE = MessageDeliveryMode.PERSISTENT;exclusive: 仅创建者可以使用的私有队列,断开后自动删除;auto_delete: 当所有消费客户端连接断开后,是否自动删除队列
        绑定队列,rabbitmq的exchangeType常用的三种模式:direct,fanout,topic三种,我们用direct模式,即rabbit:direct-exchange标签,Direct交换器很简单,如果是Direct类型,就会将消息中的RoutingKey与该Exchange关联的所有Binding中的BindingKey进行比较,如果相等,则发送到该Binding对应的Queue中。有一个需要注意的地方:如果找不到指定的exchange,就会报错。但routing key找不到的话,不会报错,这条消息会直接丢失,所以此处要小心,auto-delete:自动删除,如果为Yes,则该交换机所有队列queue删除后,自动删除交换机,默认为false
    -->
    <rabbit:direct-exchange name="test-mq-exchange" durable="true" auto-delete="false" id="test-mq-exchange">
        <rabbit:bindings>
            <!--绑定队列 队列名称为mail.send-->
            <rabbit:binding queue="test_queue_key2" key="mail.send"/>
        </rabbit:bindings>
    </rabbit:direct-exchange>
</beans>

1.3 改写userController


    //  1、注入一个AmqpTemplate在方法上面注入
    @Autowired
    private AmqpTemplate amqpTemplate;
    
    //  2、调用amqpTemplate.convertAndSend
            Map map = new HashMap();
            map.put("to",to);
            map.put("subject",subject);
            map.put("content",content);

            //将邮件的内容发送消息
            //两个参数:
            //1、队列名称
            //2、消息内容
            amqpTemplate.convertAndSend("mail.send",map);

2.消息的消费者

2.1 引入依赖

解析发送的内容


    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.41</version>
        </dependency>

 

2.2 applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xmlns:contact="http://www.springframework.org/schema/context"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
	http://www.springframework.org/schema/rabbit/spring-rabbit-2.1.xsd
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
	http://www.springframework.org/schema/context
	https://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <!--连接工厂-->
    <bean id="connectionFactory"  class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <!--<constructor-arg value="${mq.vhost}" />-->
        <property name="virtualHost" value="heima123"></property>
        <!-- username,访问RabbitMQ服务器的账户,默认是guest -->
        <property name="username" value="admin" />
        <!-- username,访问RabbitMQ服务器的密码,默认是guest -->
        <property name="password" value="admin" />
        <!-- host,RabbitMQ服务器地址,默认值"localhost" -->
        <property name="host" value="127.0.0.1" />
        <!-- port,RabbitMQ服务端口,默认值为5672 -->
        <property name="port" value="5672" />
    </bean>
    <rabbit:admin connection-factory="connectionFactory" />

    <rabbit:queue name="mail.send" auto-declare="true" durable="true" />
    <!-- 消费者部分 -->
    <!-- 自定义接口类 -->
    <bean id="myListener" class="cn.itcast.mail.MyListener"></bean>

    <!--解析json-->
    <bean id="jackson2JsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"/>

    <!-- 配置监听acknowledeg="manual"设置手动应答,它能够保证即使在一个worker处理消息的时候用CTRL+C来杀掉这个worker,或者一个consumer挂了(channel关闭了、connection关闭了或者TCP连接断了),也不会丢失消息。因为RabbitMQ知道没发送ack确认消息导致这个消息没有被完全处理,将会对这条消息做re-queue处理。如果此时有另一个consumer连接,消息会被重新发送至另一个consumer会一直重发,直到消息处理成功,监听容器acknowledge="auto" concurrency="30"设置发送次数,最多发送30次 -->
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" concurrency="20">
        <rabbit:listener queues="mail.send" ref="myListener" />
    </rabbit:listener-container>
</beans>

2.3建一个监听类

cn.itcast.mail.MyListener

package cn.itcast.mail;

import cn.itcast.common.utils.MailUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;

import java.util.Map;

/**
 * @author cyy
 * @date 2020/3/26 10:38
 */
public class MyListener implements MessageListener {

//    监听消息
    public void onMessage(Message message) {
        String msg = new String(message.getBody());
       /* System.out.println("msg = " + msg);*/

        Map map = JSONObject.parseObject(msg,Map.class);

        String to = String.valueOf(map.get("to"));
        String subject= String.valueOf(map.get("subject"));
        String content = String.valueOf(map.get("content"));

        System.out.println(to+"====="+subject+"====="+content);
        try {
            MailUtil.sendMsg(to,subject,content);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

2.4 建一个启动类

package cn.itcast.run;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author cyy
 * @date 2020/3/26 10:43
 */
public class MyApplication {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值