说是手机充值系统有点装了,其实就是调用了聚合数据的支付接口,其实挺简单的事 但是我发现博客园竟然没有类似文章,我就个出头鸟把我的代码贡献出来吧 

首先说准备工作:

去聚合数据申请账号-添加手机支付的认证-认证通过后为账户充值。

上述工作完成后,开始准备开发要用到的必要参数:

appid:在个人中心-我的数据中可找到对应的APPKEY(每个不同的接口都需要使用对应的appkey)

openid:个人中心-用户中心-账户信息(这个是唯一的程序中会使用到)

 

 

对应的接口都有比较详细的数据接收已经返回参数的说明,具体开发中会用到,具体的请查看链接:https://www.juhe.cn/docs/api/id/85

接下来要准备开发中的用到几个辅助函数,在对应的API文档中有示例代码,也可以使用下面的:

  1    /// <summary>
  2         /// Http (GET/POST)
  3         /// </summary>
  4         /// <param name="url">请求URL</param>
  5         /// <param name="parameters">请求参数</param>
  6         /// <param name="method">请求方法</param>
  7         /// <returns>响应内容</returns>
  8         static string sendPost(string url, IDictionary<string, string> parameters, string method)
  9         {
 10             if (method.ToLower() == "post")
 11             {
 12                 HttpWebRequest req = null;
 13                 HttpWebResponse rsp = null;
 14                 System.IO.Stream reqStream = null;
 15                 try
 16                 {
 17                     req = (HttpWebRequest)WebRequest.Create(url);
 18                     req.Method = method;
 19                     req.KeepAlive = false;
 20                     req.ProtocolVersion = HttpVersion.Version10;
 21                     req.Timeout = 5000;
 22                     req.ContentType = "application/x-www-form-urlencoded;charset=utf-8";
 23                     byte[] postData = Encoding.UTF8.GetBytes(BuildQuery(parameters, "utf8"));
 24                     reqStream = req.GetRequestStream();
 25                     reqStream.Write(postData, 0, postData.Length);
 26                     rsp = (HttpWebResponse)req.GetResponse();
 27                     Encoding encoding = Encoding.GetEncoding(rsp.CharacterSet);
 28                     return GetResponseAsString(rsp, encoding);
 29                 }
 30                 catch (Exception ex)
 31                 {
 32                     return ex.Message;
 33                 }
 34                 finally
 35                 {
 36                     if (reqStream != null) reqStream.Close();
 37                     if (rsp != null) rsp.Close();
 38                 }
 39             }
 40             else
 41             {
 42                 //创建请求
 43                 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + "?" + BuildQuery(parameters, "utf8"));
 44 
 45                 //GET请求
 46                 request.Method = "GET";
 47                 request.ReadWriteTimeout = 5000;
 48                 request.ContentType = "text/html;charset=UTF-8";
 49                 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
 50                 Stream myResponseStream = response.GetResponseStream();
 51                 StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
 52 
 53                 //返回内容
 54                 string retString = myStreamReader.ReadToEnd();
 55                 return retString;
 56             }
 57         }
 58         /// <summary>
 59         /// 把响应流转换为文本。
 60         /// </summary>
 61         /// <param name="rsp">响应流对象</param>
 62         /// <param name="encoding">编码方式</param>
 63         /// <returns>响应文本</returns>
 64         static string GetResponseAsString(HttpWebResponse rsp, Encoding encoding)
 65         {
 66             System.IO.Stream stream = null;
 67             StreamReader reader = null;
 68             try
 69             {
 70                 // 以字符流的方式读取HTTP响应
 71                 stream = rsp.GetResponseStream();
 72                 reader = new StreamReader(stream, encoding);
 73                 return reader.ReadToEnd();
 74             }
 75             finally
 76             {
 77                 // 释放资源
 78                 if (reader != null) reader.Close();
 79                 if (stream != null) stream.Close();
 80                 if (rsp != null) rsp.Close();
 81             }
 82         }
 83         /// <summary>
 84         /// 组装普通文本请求参数。
 85         /// </summary>
 86         /// <param name="parameters">Key-Value形式请求参数字典</param>
 87         /// <returns>URL编码后的请求数据</returns>
 88         static string BuildQuery(IDictionary<string, string> parameters, string encode)
 89         {
 90             StringBuilder postData = new StringBuilder();
 91             bool hasParam = false;
 92             IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();
 93             while (dem.MoveNext())
 94             {
 95                 string name = dem.Current.Key;
 96                 string value = dem.Current.Value;
 97                 // 忽略参数名或参数值为空的参数
 98                 if (!string.IsNullOrEmpty(name))//&& !string.IsNullOrEmpty(value)
 99                 {
100                     if (hasParam)
101                     {
102                         postData.Append("&");
103                     }
104                     postData.Append(name);
105                     postData.Append("=");
106                     if (encode == "gb2312")
107                     {
108                         postData.Append(HttpUtility.UrlEncode(value, Encoding.GetEncoding("gb2312")));
109                     }
110                     else if (encode == "utf8")
111                     {
112                         postData.Append(HttpUtility.UrlEncode(value, Encoding.UTF8));
113                     }
114                     else
115                     {
116                         postData.Append(value);
117                     }
118                     hasParam = true;
119                 }
120             }
121             return postData.ToString();
122         }
123         /// <summary>  
124         /// 获取时间戳  
125         /// </summary>  
126         /// <returns></returns>  
127         public static string GetTimeStamp()
128         {
129             TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
130             return Convert.ToInt64(ts.TotalSeconds).ToString();
131         } 
View Code

 

这几个函数具体的功能就不用说了 ,是代码很简单,都是网络链接发送请求和接受请求是时用的,我主要介绍的是点中未提供的一些

示例代码中用到了JsonObject这个类 代码中提供的是CSDN的链接,竟然还要2积分才能下载,坑爹啊 在这里我给大家分享出来吧 http://pan.baidu.com/s/1hsqF51y

在项目中应用DLL加入using Xfrog.Net;命名空间

准备工作结束

 

接下来就进入正式编码阶段了 ,开始前我准备说一下重点,其实接口的代码并不复杂,我想说了还是思路吧

1.验证当前账户余额是否够本次充值:调用 http://op.juhe.cn/ofpay/mobile/yue 具体参数参看:https://www.juhe.cn/docs/api/id/85

2.检测手机号是否可以充值:调用http://op.juhe.cn/ofpay/mobile/telcheck    具体参数参看:https://www.juhe.cn/docs/api/id/85/aid/213

3.调用手机直冲接口:   http://op.juhe.cn/ofpay/mobile/onlineorder       具体参数参看: https://www.juhe.cn/docs/api/id/85/aid/214

4.调用订单查询接口:http://op.juhe.cn/ofpay/mobile/ordersta                具体参数参看:https://www.juhe.cn/docs/api/id/85/aid/586

5.编写回调处理页面:QQ上搜索聚合数据的客服,给他账号和回调地址后,让他帮助设置,具体的回调地址接受参数查看:http://code.juhe.cn/docs/detail/id/1565

 

具体代码贴出:

 

            //1.账户余额查询
            string url1 = "http://op.juhe.cn/ofpay/mobile/yue";

            var parameters1 = new Dictionary<string, string>();

            string timestamp = GetTimeStamp();
            parameters1.Add("timestamp", timestamp); //当前时间戳,如:1432788379
            parameters1.Add("key", appkey);//你申请的key
            string signstr =openid+ appkey+timestamp;
            parameters1.Add("sign", CommonManager.String.EncryptMD5SystemDefaultMethod(signstr, false, true)); //校验值,md5(&lt;b&gt;OpenID&lt;/b&gt;+key+timestamp),OpenID在个人中心查询

            string result1 = sendPost(url1, parameters1, "get");

            JsonObject newObj1 = new JsonObject(result1); 
            String errorCode1 = newObj1["error_code"].Value;

            //查询余额是否成功
            if (errorCode1 == "0")
            {

                //判断余额是否够本次充值
                if (double.Parse(newObj1["result"]["money"].Value) > double.Parse(Integrals))
    
                {
                     //msg.InnerText="余额充足!";

                    //5.检测手机号码是否能充值
                    string url5 = "http://op.juhe.cn/ofpay/mobile/telcheck";

                    var parameters5 = new Dictionary<string, string>();

                    parameters5.Add("phoneno", phone); //手机号码
                    parameters5.Add("cardnum", Integrals); //充值金额,目前可选:5、10、20、30、50、100、300
                    parameters5.Add("key", appkey);//你申请的key

                    string result5 = sendPost(url5, parameters5, "get");

                    JsonObject newObj5 = new JsonObject(result5);
                    String errorCode5 = newObj5["error_code"].Value;

                    if (errorCode5 == "0")
                    {
                         //可以充值
                        //7.手机直充接口
                        string url7 = "http://op.juhe.cn/ofpay/mobile/onlineorder";

                        var parameters7 = new Dictionary<string, string>();
                        parameters7.Add("phoneno", phone); //手机号码
                        parameters7.Add("cardnum", Integrals); //充值金额,目前可选:5、10、20、30、50、100、300
                        parameters7.Add("orderid", orderstr); //商家订单号,8-32位字母数字组合
                        parameters7.Add("key", appkey);//你申请的key
                        string md5str = openid + appkey + phone + Integrals + orderstr;
                        parameters7.Add("sign", CommonManager.String.EncryptMD5SystemDefaultMethod(md5str, false, true)); //校验值,md5(&lt;b&gt;OpenID&lt;/b&gt;+key+phoneno+cardnum+orderid),OpenID在个人中心查询

                    
                        string result7 = sendPost(url7, parameters7, "get");

                        JsonObject newObj7 = new JsonObject(result7);
                        String errorCode7 = newObj7["error_code"].Value;

                        if (errorCode7 == "0")
                        {
                            msg.InnerText = "充值订单创建成功,等待商户充值后查看订单状态!";

                            DbSession.Default.FromSql(
                            @"UPDATE TOP(1) TPropLog SET Jhorderid=@Jhorderid,PropStatus=@PropStatus WHERE ID = @ID")
                            .AddInputParameter("@ID", DbType.Int32, id)
                            .AddInputParameter("@PropStatus", DbType.Int32, 3)
                            .AddInputParameter("@Jhorderid", DbType.String, newObj7["result"]["sporder_id"].Value)
                            .Execute();
                            status.SelectedValue = "3";
                        }
                        else
                        {
                            msg.InnerText = "充值订单失败!失败原因:" + newObj7["reason"].Value;
                        }
 
                    }
                    else
                    {
                        msg.InnerText = "手机号不能充值!原因:" + newObj1["reason"].Value;
                    }

      
                }
                else
                {
                    msg.InnerText = "余额不足请充值!当前账户余额为:" + newObj1["result"]["money"].Value;
                }

            }
            else
            {
                 msg.InnerText="余额查询失败!";

            }

里面有几个点注意一下:

1.需要sign签名的几个接口需要按照格式使用MD5进行一个转换,MD5转换的函数网上一大把相信你的项目中也有了我就不提供了 ,按照他提供的格式组织签名就行了

2.我的订单查询接口是写在另外一个函数里的,因为我的逻辑充值后单独可以查询,可根据情况自行更改。

3.回调页面是POST方式传值,所以接受的时候按照他提供的参数接收就行了,根据返回的订单号跟新本地数据

        //聚合话费充值回调页面,页面的设置需要联系聚合客服更改
        protected void Page_Load(object sender, EventArgs e)
        {

            var sporder_id = CommonManager.Web.Request("sporder_id", "");//聚合订单ID
            var orderid = CommonManager.Web.Request("orderid", "");      //鼎鼎订单ID
            var sta = CommonManager.Web.Request("sta", "");               //充值状态1:成功 9:失败
            if (sta == "1")
            { 
               //更新订单状态为充值成功
                DbSession.Default.FromSql(
                        @"UPDATE TOP(1) TPropLog SET PropStatus=@PropStatus WHERE Jhorderid = @Jhorderid")
                        .AddInputParameter("@PropStatus", DbType.Int32, 4)
                        .AddInputParameter("@Jhorderid", DbType.String, sporder_id)
                        .Execute();
                Response.Clear();
                Response.Write("success");
                Response.End();
            }
            if (sta == "9")
            {
                //更新订单状态为充值成功
                DbSession.Default.FromSql(
                        @"UPDATE TOP(1) TPropLog SET PropStatus=@PropStatus WHERE Jhorderid = @Jhorderid")
                        .AddInputParameter("@PropStatus", DbType.Int32, 5)
                        .AddInputParameter("@Jhorderid", DbType.String, sporder_id)
                        .Execute();
                Response.Clear();
                Response.Write("success");
                Response.End();
                //更新订单状态为充值失败
            }

        }

重点回顾:

1.JsonObject.DLL下载

2.签名顺序和字符要按照提供的做

3.回调地址要找客服设置

4.单个手机号每天有充值数量和次数的限制,超过次数会导致订单一直提示进行中,最后失败,失败也会有回调提示的

5.测试的时候可以将vs自带的iis调试工具配合ngrok映射到外网,这样直接就可以调试回调页面,改天我会写一个简单的教程,如何使用vs默认的iis映射到外网进行调试(微信的外网调试也可以这么做,非常方便哦)