说是手机充值系统有点装了,其实就是调用了聚合数据的支付接口,其实挺简单的事 但是我发现博客园竟然没有类似文章,我就个出头鸟把我的代码贡献出来吧
首先说准备工作:
去聚合数据申请账号-添加手机支付的认证-认证通过后为账户充值。
上述工作完成后,开始准备开发要用到的必要参数:
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 }
这几个函数具体的功能就不用说了 ,是代码很简单,都是网络链接发送请求和接受请求是时用的,我主要介绍的是点中未提供的一些
示例代码中用到了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(<b>OpenID</b>+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(<b>OpenID</b>+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映射到外网进行调试(微信的外网调试也可以这么做,非常方便哦)