【博主推荐】asp.net WebService 后台数据API JSON(附源码)

【博主推荐】asp.net WebService 后台数据API(附源码)

Web service是一个基于可编程的web的应用程序,用于开发分布式的互操作的应用程序,也是一种web服务
WebService的特性有以下几点:
1.使用XML(标准通用标记语言)来作为数据交互的格式。
2.跨平台性,因为使用XML所以只要本地应用可以连接网络解析XML就可以实现数据交换,比如安卓、IOS、WindowsPhone等都可以实现对Web service的数据交互。
3.基于HTTP协议,直接跨越防火墙,通用型强;
界面中贴的代码只是主要实现流程,具体的实现方法,外部方法见项目资源源码下载

代码实现

  • 1.给前端数据提供增删改查API;
  • 2.内置使用mysql、oracle数据库,多配置,可以在配置文件自动切换需要的数据库;
  • 3.api接口过滤器机制,可以过滤自己想要过滤的请求;
  • 4.可以提供json和xml的数据格式;
  • 5.代码下载可以直接运用;
  • 6.实现不同的数据库,执行不同的sql语句;
  • 7.内含websocket服务端,接收处理客户端websocket数据;
  • 8.附带websocket客户端源码;
  • 9.带文本日志文件输出;

webservice简单创建过程

先根据这篇教程了解怎么简单创建一个web服务,以便更好深入了解
C#中WebService的创建和调用

1.配置全局应用程序类Global.asax

Application_Start 和 Application_End
第一次访问站点时,创建HttpApplication对象,此时会触发Application_Start,并创建HttpApplication实例池,应用接请求就从池中获取实例,进行处理。在所有的HttpApplication实例闲置达到超时时间,触发应用程序池回收,或者重启站点时就会触发Application_End事件,应用程序池的闲置超时时间可以在iis设置,站点下bin目录下的文件发生改变,webconfig配置改变等导致站点重启的事件都会触发Application_End。

Session_Start 和 Session_End
单个用户访问Web应用时,启动会话,服务器为该用户创建一个独立的Session对象,并触发Session_Start事件,此时Session处于可用状态。用户在该会话建立后可以发起若干次请求,当服务器一段时间内未收到用户请求,达到会话超时时间时,触发Session_End事件,服务器释放为当前用户保存Session的内存。也可以在应用程序中调用Session.Abandon()可以手动取消Session,清空服务器保存的Session,直到再次调用Session时,又会触发Session_Start,但是SessionID不会变化。所有会触发Application_End的事件都会在此之前触发Session_Start。可以在Web.Config中添加设置Session过期时间(timeout单位为分钟)。

Application_BeginRequest 和 Application_EndRequest
在用户会话启动后,每次发起的请求都会触发Application_BeginRequest事件,并在请求完成时触发Application_EndRequest事件。

Application_BeginRequest 里配置过滤

#region 过滤客户端xss恶意脚本提交
if (Request.Cookies != null)
{
    if (XSSFilter.CookieData())
    {
        Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Response.Write(JsonUtil.getText1Json("您提交的Cookie数据有恶意字符!"));
        Response.End();
    }
}
if (Request.UrlReferrer != null)
{
    if (XSSFilter.referer())
    {
        Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Response.Write(JsonUtil.getText1Json("您提交的Referrer数据有恶意字符!"));
        Response.End();
    }
}
if (Request.RequestType.ToUpper() == "POST")
{
    if (XSSFilter.PostData())
    {
        Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Response.Write(JsonUtil.getText1Json("您提交的Post数据有恶意字符!"));
        Response.End();
    }
}
if (Request.RequestType.ToUpper() == "GET")
{
    if (XSSFilter.GetData())
    {
        Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Response.Write(JsonUtil.getText1Json("您提交的Get数据有恶意字符!"));
        Response.End();
    }
}
#endregion

#region 过滤参数
 //遍历Post参数,隐藏域除外
 foreach (string i in this.Request.Form)
 {
     if (i == "__VIEWSTATE") continue;
     this.goErr(this.Request.Form[i].ToString());
 }
 //遍历Get参数。 
 foreach (string i in this.Request.QueryString)
 {
     this.goErr(this.Request.QueryString[i].ToString());
 }
 #endregion

3.配置POST,GET请求返回JOSN

Web.config

<system.web>
	<webServices>
      <protocols>
        <add name="HttpPost" />
        <add name="HttpGet" />
        <add name="HttpSoap" />
        <add name="Documentation" />
      </protocols>
    </webServices>
</system.web>
      
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules>
      <remove name="ApplicationInsightsWebTracking" />
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
    </modules>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Methods" value="OPTIONS,POST,GET" />
        <add name="Access-Control-Allow-Headers" value="x-requested-with" />
        <add name="Access-Control-Allow-Origin" value="*" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>

2.新建asmx WEB服务文件

在这里插入图片描述
建好后的界面配置
在这里插入图片描述
dwsh.asmx代码

using DataServiceBLL;
using DataServiceUtil;
using System;
using System.Web.Script.Services;
using System.Web.Services;

namespace DataServiceAPI.dsa.api.v1.data
{
    /// <summary>
    /// dwsh 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    [System.Web.Script.Services.ScriptService]
    // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 
    // [System.Web.Script.Services.ScriptService]
    public class dwsh : System.Web.Services.WebService
    {
        #region 实例化
        public OperDataBLL operDataBLL = new OperDataBLL();
        #endregion

		//api接口见下面效果代码
    }
}

3.效果展示

3.1新增api

在这里插入图片描述
代码


#region 新增
[WebMethod(Description = "数据新增")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void add(string token, string name, string codedata, string detail)
{
   if (token != ConfigurationHelperUtil.DSA_TOKEN)
   {
       Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
       Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
       Context.Response.Write(JsonUtil.getError205Json());//可json,可文本,可xml
       Context.Response.End();
   }
   else
   {
       string result = "操作成功!";
       int code = 200;
       try
       {
           string sql = "";
           string db = ConfigurationHelperUtil.DSA_DB;
           int num = 0;
           if (db.ToUpper() == "MYSQL")
           {
               sql = "insert into SMS_TEST(NAME, CODE, DETAIL, INSERTTIME)";
               sql += " values('" + name + "', '" + codedata + "', '" + detail + "', now())";
               num = operDataBLL.OperData(sql);
           }
           else if (db.ToUpper() == "ORACLE")
           {
               sql = "insert into SMS_TEST(id,NAME,CODE,DETAIL,INSERTTIME)";
               sql += " values(seq_dswh_id.nextval, '" + name + "', '" + codedata + "', '" + detail + "', sysdate)";
               num = operDataBLL.OperOracleData(sql);
           }
           OperLogUtil.WriteFileLog("新增操作sql:" + sql, ConfigurationHelperUtil.DSA_LOG_TYPE_INFO);
           if (num > 0)
           {
               result = "操作成功";
           }
           else
           {
               result = "未更新数据";
               code = 201;
           }
       }
       catch (Exception)
       {
           result = "操作异常!";
           code = 202;
       }
       string resultJson = JsonUtil.getTextJson(code, result, 1, "[]");
       Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
       Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
       Context.Response.Write(resultJson);//可json,可文本,可xml
       Context.Response.End();
   }
}
#endregion

3.2修改api

在这里插入图片描述
代码

#region 修改
[WebMethod(Description = "数据修改")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void update(string token,string id, string name, string codedata, string detail)
{
   if (token != ConfigurationHelperUtil.DSA_TOKEN)
   {
       Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
       Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
       Context.Response.Write(JsonUtil.getError205Json());//可json,可文本,可xml
       Context.Response.End();
   }
   else
   {
       string result = "操作成功!";
       int code = 200;
       try
       {
           string sql = "";
           string db = ConfigurationHelperUtil.DSA_DB;
           int num = 0;
           if (db.ToUpper() == "MYSQL")
           {
               sql = "update SMS_TEST set NAME='" + name + "', CODE= '" + codedata + "', DETAIL='" + detail + "' where id="+id;
               num = operDataBLL.OperData(sql);
           }
           else if (db.ToUpper() == "ORACLE")
           {
               sql = "update SMS_TEST set NAME= '" + name + "',CODE= '" + codedata + "',DETAIL= '" + detail + "' where id="+id;
               num = operDataBLL.OperOracleData(sql);
           }
           OperLogUtil.WriteFileLog("修改操作sql:" + sql, ConfigurationHelperUtil.DSA_LOG_TYPE_INFO);
           if (num > 0)
           {
               result = "操作成功";
           }
           else
           {
               result = "未更新数据";
               code = 201;
           }
       }
       catch (Exception)
       {
           result = "操作异常!";
           code = 202;
       }
       string resultJson = JsonUtil.getTextJson(code, result, 1, "[]");
       Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
       Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
       Context.Response.Write(resultJson);//可json,可文本,可xml
       Context.Response.End();
   }
}
#endregion

3.3列表api

在这里插入图片描述
代码

#region 查询列表 
[WebMethod(Description = "列表")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
//[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public void getlist(string token, string name)
{
    if (token != ConfigurationHelperUtil.DSA_TOKEN)
    {
        Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Context.Response.Write(JsonUtil.getError205Json());//可json,可文本,可xml
        Context.Response.End();
    }
    else
    {
        string result = "";
        try
        {
            if (name == "" || name == null || name == "null")
            {
                name = "";
            }
            else
            {
                name = " and name like '%" + name + "%'";
            }
            string sql = "select * from SMS_TEST t where 1=1" + name;
            string db = ConfigurationHelperUtil.DSA_DB;
            OperLogUtil.WriteFileLog("查询操作sql:" + sql, ConfigurationHelperUtil.DSA_LOG_TYPE_INFO);
            if (db.ToUpper() == "MYSQL")
            {
                result = operDataBLL.getData(sql);
            }
            else if (db.ToUpper() == "ORACLE")
            {
                result = operDataBLL.getOracleData(sql);
            }
        }
        catch (Exception)
        {
            result = JsonUtil.getError201Json();
        }
        Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Context.Response.Write(result);//可json,可文本,可xml
        Context.Response.End();
    }
}

#endregion

3.4删除api

在这里插入图片描述
代码

#region 删除
[WebMethod(Description = "数据删除")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void del(string token, string id)
{
    if (token != ConfigurationHelperUtil.DSA_TOKEN)
    {
        Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Context.Response.Write(JsonUtil.getError205Json());//可json,可文本,可xml
        Context.Response.End();
    }
    else
    {
        string result = "操作成功!";
        int code = 200;
        try
        {
            string sql = "";
            string db = ConfigurationHelperUtil.DSA_DB;
            int num = 0;
            if (db.ToUpper() == "MYSQL")
            {
                sql = "delete SMS_TESTdelete from SMS_TEST where id="+id;
                num = operDataBLL.OperData(sql);
            }
            else if (db.ToUpper() == "ORACLE")
            {
                sql = "delete SMS_TEST where id="+id;
                num = operDataBLL.OperOracleData(sql);
            }
            OperLogUtil.WriteFileLog("删除操作sql:" + sql, ConfigurationHelperUtil.DSA_LOG_TYPE_INFO);
            if (num > 0)
            {
                result = "操作成功";
            }
            else
            {
                result = "未更新数据";
                code = 201;
            }
        }
        catch (Exception)
        {
            result = "操作异常!";
            code = 202;
        }
        string resultJson = JsonUtil.getTextJson(code, result, 1, "[]");
        Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Context.Response.Write(resultJson);//可json,可文本,可xml
        Context.Response.End();
    }
}
#endregion

3.5分页列表api

在这里插入图片描述
代码

#region 查询列表分页
[WebMethod(Description = "分页列表")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
//[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public void getfyList(string token, string limit, string start, string name)
{
    if (token != ConfigurationHelperUtil.DSA_TOKEN)
    {
        Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Context.Response.Write(JsonUtil.getError205Json());//可json,可文本,可xml
        Context.Response.End();
    }
    else
    {
        string result = "";
        if (!StrUtil.isNum(limit) || !StrUtil.isNum(start))//验证是否合格参数
        {
            result = JsonUtil.getError203Json();
        }
        else
        {
            try
            {
                if (name == "" || name == null || name == "null")
                {
                    name = "";
                }
                else
                {
                    name = " and name like '%" + name + "%'";
                }
                string db = ConfigurationHelperUtil.DSA_DB;
                if (db.ToUpper() == "MYSQL")
                {
                    //limit a,b  a为开始行数  b为几行
                    int ks = (int.Parse(start) - 1) * int.Parse(limit);
                    string sql = "SELECT * FROM SMS_TEST WHERE 1=1" + name + " ORDER BY INSERTTIME desc LIMIT " + ks + ", " + limit;
                    result = operDataBLL.getFyData(sql, "SMS_TEST");
                    OperLogUtil.WriteFileLog("分页列表操作sql:" + sql, ConfigurationHelperUtil.DSA_LOG_TYPE_INFO);
                }
                else if (db.ToUpper() == "ORACLE")
                {
                    string sql = "SELECT * FROM SMS_TEST WHERE 1=1" + name;
                    //false desc   true asc
                    result = operDataBLL.getFyOracleData(sql, "INSERTTIME", false, int.Parse(limit), int.Parse(start));
                    OperLogUtil.WriteFileLog("分页列表操作sql:" + sql, ConfigurationHelperUtil.DSA_LOG_TYPE_INFO);
                }
            }
            catch (Exception)
            {
                result = JsonUtil.getError201Json();
            }
        }
        Context.Response.Charset = ConfigurationHelperUtil.DSA_Encode;
        Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding(ConfigurationHelperUtil.DSA_Encode);
        Context.Response.Write(result);//可json,可文本,可xml
        Context.Response.End();
    }
}

#endregion

4.内置websocket服务端

  • 如要启动websocket,取消这几行代码注释即可
protected void Application_Start(object sender, EventArgs e)
{
    //启动webScoket
    //Thread thread2 = new Thread(new ThreadStart(WebScoket.startWebScoket));//创建线程
    //thread2.Start(); //启动线程

    //WebScoket.startWebScoket();//用于CMS

}
  • websocket代码
using DataServiceBLL;
using DataServiceUtil;
using Newtonsoft.Json.Linq;
using StriveEngine;
using StriveEngine.Core;
using StriveEngine.Tcp.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
namespace DataServiceAPI.App_Code
{
    public class WebScoket
    {
        private static ITcpServerEngine tcpServerEngine;
        private static bool hasTcpServerEngineInitialized;
        public static OperDataBLL operDataBLL = new OperDataBLL();
        public static void startWebScoket()
        {
            OperLogUtil.WriteFileLog("启动WebScoket", ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);
            try
            {
                if (tcpServerEngine == null)
                {
                    tcpServerEngine = NetworkEngineFactory.CreateTextTcpServerEngine(int.Parse(ConfigurationHelperUtil.DSA_WebScoket), new DefaultTextContractHelper("\0"));//DefaultTextContractHelper是StriveEngine内置的ITextContractHelper实现。使用UTF-8对EndToken进行编码。 
                }

                if (hasTcpServerEngineInitialized)
                {
                    tcpServerEngine.ChangeListenerState(true);
                }
                else
                {
                    InitializeTcpServerEngine();
                }
            }
            catch (Exception ee)
            {
                OperLogUtil.WriteFileLog(ee.Message, ConfigurationHelperUtil.DSA_LOG_TYPE_ERROR);
            }
        }

        public static void InitializeTcpServerEngine()
        {
            tcpServerEngine.ClientCountChanged += new CbDelegate<int>(tcpServerEngine_ClientCountChanged);
            tcpServerEngine.ClientConnected += new CbDelegate<System.Net.IPEndPoint>(tcpServerEngine_ClientConnected);
            tcpServerEngine.ClientDisconnected += new CbDelegate<System.Net.IPEndPoint>(tcpServerEngine_ClientDisconnected);
            tcpServerEngine.MessageReceived += new CbDelegate<IPEndPoint, byte[]>(tcpServerEngine_MessageReceived);
            tcpServerEngine.Initialize();
            hasTcpServerEngineInitialized = true;
        }
        public static void tcpServerEngine_ClientCountChanged(int count)
        {
            OperLogUtil.WriteFileLog("在线数量: " + count, ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);
        }
        public static void tcpServerEngine_ClientConnected(System.Net.IPEndPoint ipe)
        {
            string msg = string.Format("{0} 上线", ipe);
            OperLogUtil.WriteFileLog(msg, ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);
        }
        public static void tcpServerEngine_ClientDisconnected(System.Net.IPEndPoint ipe)
        {
            string msg = string.Format("{0} 下线", ipe);
            OperLogUtil.WriteFileLog(msg, ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);
        }
        public static void tcpServerEngine_MessageReceived(IPEndPoint client, byte[] bMsg)
        {
            string msg = System.Text.Encoding.UTF8.GetString(bMsg); //消息使用UTF-8编码
            msg = msg.Substring(0, msg.Length - 1); //将结束标记"\0"剔除
            OperLogUtil.WriteFileLog("收到:" + client.Address + ":" + msg, ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);

            #region 处理接收到的数据
            //此处处理接收到的数据
            #endregion
        }

        #region 根据客户端推送单条信息
        public static void sendInfo(IPEndPoint client, string msg)
        {
            try
            {
                msg = msg + "\0";// "\0" 表示一个消息的结尾
                byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);//消息使用UTF-8编码
                tcpServerEngine.SendMessageToClient(client, bMsg);
            }
            catch (Exception ee)
            {
                OperLogUtil.WriteFileLog(ee.Message, ConfigurationHelperUtil.DSA_LOG_TYPE_ERROR);
            }
        }
        #endregion

        #region 推送消息,推送所有在线的客户端

        public static void sendInfoAll(string msg)
        {
            try
            {
                List<IPEndPoint> list = tcpServerEngine.GetClientList();//获取在线设备
                if (list.Count > 0)
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        try
                        {
                            IPEndPoint client = list[i];
                            if (client == null)
                            {//没有客户端
                                OperLogUtil.WriteFileLog("没有客户端:" + client.Address + ":" + client.Port, ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);
                            }
                            else if (!tcpServerEngine.IsClientOnline(client))
                            {//客户端不在线
                                OperLogUtil.WriteFileLog("客户端不在线:" + client.Address + ":" + client.Port, ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);
                            }
                            else
                            {
                                msg = msg + "\0";// "\0" 表示一个消息的结尾
                                byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);//消息使用UTF-8编码
                                tcpServerEngine.SendMessageToClient(client, bMsg);
                                OperLogUtil.WriteFileLog("客户端:" + client.Address + ":" + client.Port + "发送:" + msg, ConfigurationHelperUtil.DSA_LOG_TYPE_WEBSCOKET);
                            }
                        }
                        catch (Exception ee)
                        {
                            OperLogUtil.WriteFileLog("sendInfoAll1" + ee.Message, ConfigurationHelperUtil.DSA_LOG_TYPE_ERROR);
                        }
                    }
                }
            }
            catch (Exception ee)
            {
                OperLogUtil.WriteFileLog("sendInfoAll2" + ee.Message, ConfigurationHelperUtil.DSA_LOG_TYPE_ERROR);
            }
        }
        #endregion
        

        #region 判断是字符串是数字
        /**
         * 判断字符串是否是数字
         */
        public static Boolean isNumber(String value)
        {
            return isInteger(value);
        }

        /**
         * 判断字符串是否是整数
         */
        public static Boolean isInteger(String value)
        {
            try
            {
                int num = int.Parse(value);
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }
        

        #endregion
    }
}

5.源码下载

【博主推荐】asp.net WebService 后台数据API JSON(附源码)

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xcLeigh

万水千山总是情,打赏两块行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值