|
瞻仰一下吧,或许能够从中学习到东西。
http://blog.csdn.net/sufei1013/archive/2010/02/08/5299547.aspx
这两天写支付宝接口, 这个话题不新了, 因为很多人都 做过了, 在这里我说说我的看法吧, 先说一下实现其实支付宝公司已经给我们做的很好了, 只要少量的改动就OK了,只是有的程序员不太明天他们的动作流程而以,我就以及时到帐为例子来说了,呵呵
在这之前就大家先下载一下c#版的及时到帐代码 这里是下载地址http://dev.alipay.com/devclub/mvnforum/viewthread_thread,4;jsessionid=595DB7442AAA5CD2FC849E7C2FBE51D7
先看一下程序的结构吧
支付宝有一个类文件叫 AliPay 是一些加密算法之类的东西,包括构造URL
要吧看一下这个类的全部内容
代码 using System.Web;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System;
/// <summary>
/// New Interface for AliPay
/// </summary>
namespace Gateway
{
public class AliPay
{
/// <summary>
/// 与ASP兼容的MD5加密算法
/// </summary>
public static string GetMD5(string s, string _input_charset)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(s));
StringBuilder sb = new StringBuilder(32);
for (int i = 0; i < t.Length; i++)
{
sb.Append(t.ToString(\"x\").PadLeft(2, '0'));
}
return sb.ToString();
}
/// <summary>
/// 冒泡排序法
/// 按照字母序列从a到z的顺序排列
/// </summary>
public static string[] BubbleSort(string[] r)
{
int i, j; //交换标志
string temp;
bool exchange;
for (i = 0; i < r.Length; i++) //最多做R.Length-1趟排序
{
exchange = false; //本趟排序开始前,交换标志应为假
for (j = r.Length - 2; j >= i; j--)
{//交换条件
if (System.String.CompareOrdinal(r[j + 1], r[j]) < 0)
{
temp = r[j + 1];
r[j + 1] = r[j];
r[j] = temp;
exchange = true; //发生了交换,故将交换标志置为真
}
}
if (!exchange) //本趟排序未发生交换,提前终止算法
{
break;
}
}
return r;
}
/// <summary>
/// 生成URL链接或加密结果
/// </summary>
/// <param name=\"para\">参数加密数组</param>
/// <param name=\"_input_charset\">编码格式</param>
/// <param name=\"sign_type\">加密类型</param>
/// <param name=\"key\">安全校验码</param>
/// <returns>字符串URL或加密结果</returns>
public static string CreatUrl(
//string gateway,//GET方式传递参数时请去掉注释
string[] para,
string _input_charset,
string sign_type,
string key
)
{
int i;
//进行排序;
string[] Sortedstr = BubbleSort(para);
//构造待md5摘要字符串 ;
StringBuilder prestr = new StringBuilder();
for (i = 0; i < Sortedstr.Length; i++)
{
if (i == Sortedstr.Length - 1)
{
prestr.Append(Sortedstr);
}
else
{
prestr.Append(Sortedstr + \"&\");
}
}
prestr.Append(key);
//生成Md5摘要;
string sign = GetMD5(prestr.ToString(), _input_charset);
//以下是POST方式传递参数
return sign;
//以下是GET方式传递参数
//构造支付Url;
// char[] delimiterChars = { '='};
// StringBuilder parameter = new StringBuilder();
// parameter.Append(gateway);
// for (i = 0; i < Sortedstr.Length; i++)
// {//UTF-8格式的编码转换
// parameter.Append(Sortedstr.Split(delimiterChars)[0] + \"=\" + HttpUtility.UrlEncode(Sortedstr.Split(delimiterChars)[1]) + \"&\");
// }
//
// parameter.Append(\"sign=\" + sign + \"&sign_type=\" + sign_type);
//
// //返回支付Url;
// return parameter.ToString();
}
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
public static string Get_Http(string a_strUrl, int timeout)
{
string strResult;
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(a_strUrl);
myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.Default);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch (Exception exp)
{
strResult = \"错误:\" + exp.Message;
}
return strResult;
}
}
} 而我们一般不用管这个类,只要保证能调用 的到就行了,不用管他
我们要做的很少,他是怎么工作的呢,
这是开发文档里的工作图
其实我们要处理的只有三个Aspx的文件,
先看第一个吧 Default.aspx
这是一个请求的界面
代码 using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Gateway;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void BtnAlipay_Click(object sender, EventArgs e)
{
//业务参数赋值;
string gateway = \"https://www.alipay.com/cooperate/gateway.do?\"; //支付接口
string service = \"create_direct_pay_by_user\"; //服务名称,这个是识别是何接口实现何功能的标识,请勿修改
string seller_email = \"写自己的\"; //商家签约时的支付宝帐号,即收款的支付宝帐号
string sign_type = \"MD5\"; //加密类型,签名方式“不用改”
string key = \"写自己的\"; //安全校验码,与partner是一组,获取方式是:用签约时支付宝帐号登陆支付宝网站www.alipay.com,在商家服务我的商家里即可查到。
string partner = \"写自己的\"; //商户ID,合作身份者ID,合作伙伴ID
string _input_charset = \"utf-8\"; //编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。
string show_url = \"http://www.alipay.com/\"; //展示地址,即在支付页面时,商品名称旁边的“详情”的链接地址。
string out_trade_no = TxtOrderno.Text.Trim(); //客户自己的订单号,订单号必须在自身订单系统中保持唯一性
string subject = \"4.0系统支付宝充值\"; //商品名称,也可称为订单名称,该接口并不是单一的只能买一样东西,可把一次支付当作一次下订单
string body = \"商户:\" + TxtOrderno.Text.Trim() + \"通过支付宝给自己充值:\" + TxtTotal_fee.Text.Trim() + \"元\"; //商品描述,即备注
string total_fee = TxtTotal_fee.Text.Trim(); //商品价格,也可称为订单的总金额
//服务器通知url(Alipay_Notify.aspx文件所在路经),必须是完整的路径地址
string notify_url = http://0.0.6.108/Alipay/Alipay_Notify.aspx;
//服务器返回url(Alipay_Return.aspx文件所在路经),必须是完整的路径地址
string return_url = http://0.0.6.108/Alipay/Alipay_Return.aspx;
//构造数组;
//以下数组即是参与加密的参数,若参数的值不允许为空,若该参数为空,则不要成为该数组的元素
string[] para ={
\"service=\"+service,
\"partner=\" + partner,
\"seller_email=\" + seller_email,
\"out_trade_no=\" + out_trade_no,
\"subject=\" + subject,
\"body=\" + body,
\"total_fee=\" + total_fee,
\"show_url=\" + show_url,
\"payment_type=1\",
\"notify_url=\" + notify_url,
\"return_url=\" + return_url,
\"_input_charset=\"+_input_charset
};
//支付URL生成
string aliay_url = AliPay.CreatUrl(
//gateway,//GET方式传递参数时请去掉注释
para,
_input_charset,
sign_type,
key
);
//以下是GET方式传递参数
//Response.Redirect(aliay_url);
//以下是POST方式传递参数
Response.Write(\"<form name='alipaysubmit' method='post' action='https://www.alipay.com/cooperate/gateway.do?_input_charset=utf-8'>\");
Response.Write(\"<input type='hidden' name='service' value=\" + service + \">\");
Response.Write(\"<input type='hidden' name='partner' value=\" + partner + \">\");
Response.Write(\"<input type='hidden' name='seller_email' value=\" + seller_email + \">\");
Response.Write(\"<input type='hidden' name='out_trade_no' value=\" + out_trade_no + \">\");
Response.Write(\"<input type='hidden' name='subject' value=\" + subject + \">\");
Response.Write(\"<input type='hidden' name='body' value=\" + body + \">\");
Response.Write(\"<input type='hidden' name='total_fee' value=\" + total_fee + \">\");
Response.Write(\"<input type='hidden' name='show_url' value=\" + show_url + \">\");
Response.Write(\"<input type='hidden' name='return_url' value=\" + return_url + \">\");
Response.Write(\"<input type='hidden' name='notify_url' value=\" + notify_url + \">\");
Response.Write(\"<input type='hidden' name='payment_type' value=1>\");
Response.Write(\"<input type='hidden' name='sign' value=\" + aliay_url + \">\");
Response.Write(\"<input type='hidden' name='sign_type' value=\" + sign_type + \">\");
Response.Write(\"</form>\");
Response.Write(\"<script>\");
Response.Write(\"document.alipaysubmit.submit()\");
Response.Write(\"</script>\");
}
}
代码里的key和 partner的获取方法
现在我们只要按代码里的信息填写一样就可以了,
然后远行网页
点提交
就会进入
下面的操作就是在支付平台的完成了, 跟咱的程序没有关系了
现在我们应该想,那付完钱之后呢?
我们有两个界面来处理这个问题一个是
Alipay_Return.aspx
代码 using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Collections.Specialized;
using System.IO;
using Gateway;
/// <summary>
/// 创建该页面文件时,请留心该页面文件是可以对其进行美工处理的,原因在于支付完成以后,当前窗口会从支付宝的页面跳转回这个页面。
/// 该页面称作“返回页”,是同步被支付宝服务器所调用,可当作是支付完成后的提示信息页,如“您的某某某订单,多少金额已支付成功”。
/// </summary>
public partial class Alipay_Return : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string alipayNotifyURL = \"https://www.alipay.com/cooperate ... tify_verify\";
//string alipayNotifyURL = \"http://notify.alipay.com/trade/notify_query.do?\";//此路径是在上面链接地址无法起作用时替换使用。
string key = \"写自己的\"; //partner 的对应交易安全校验码(必须填写)
string partner = \"写自己的\"; //partner合作伙伴id(必须填写)
string _input_charset = \"utf-8\";//编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。
alipayNotifyURL = alipayNotifyURL + \"&partner=\" + partner + \"¬ify_id=\" + Request.QueryString[\"notify_id\"];
//获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的
string responseTxt = AliPay.Get_Http(alipayNotifyURL, 120000);
//*******加密签名程序开始//*******
int i;
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = Request.QueryString;
// Get names of all forms into a string array.
String[] requestarr = coll.AllKeys;
//进行排序;
string[] Sortedstr = AliPay.BubbleSort(requestarr);
//构造待md5摘要字符串 ;
StringBuilder prestr = new StringBuilder();
for (i = 0; i < Sortedstr.Length; i++)
{
if (Request.Form[Sortedstr] != \"\" && Sortedstr != \"sign\" && Sortedstr != \"sign_type\")
{
if (i == Sortedstr.Length - 1)
{
prestr.Append(Sortedstr + \"=\" + Request.QueryString[Sortedstr]);
}
else
{
prestr.Append(Sortedstr + \"=\" + Request.QueryString[Sortedstr] + \"&\");
}
}
}
prestr.Append(key);
//生成Md5摘要;
string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset);
//*******加密签名程序结束*******
string sign = Request.QueryString[\"sign\"];
// Response.Write(prestr.ToString()); //调试用,支付宝服务器返回时的完整路径。
if (mysign == sign && responseTxt == \"true\") //验证支付发过来的消息,签名是否正确
{
//更新自己数据库的订单语句,请自己填写一下
string strOrderNO = Request.QueryString[\"out_trade_no\"];//订单号
string strPrice = Request.QueryString[\"total_fee\"];//金额
string strTradeStatus = Request.QueryString[\"TRADE_STATUS\"];//订单状态
//生成对象
//OfficeFinanceServices objOfficeFinanceServices = new OfficeFinanceServices();
//订单信息
string[] login = strOrderNO.Split(new string[] { \"_\" }, StringSplitOptions.RemoveEmptyEntries);
////查询当前的余额
//decimal objdm = objOfficeFinanceServices.OfficeFinanceSelect(Convert.ToInt32(login[0].ToString().Trim()), true);
//OfficeFinance objofficeFinance = new OfficeFinance();
//objofficeFinance.ofId = Convert.ToInt32(login[0].ToString().Trim());
//objofficeFinance.ofOrid = \"cz\";
//objofficeFinance.ofTime = DateTime.Now;
//objofficeFinance.ofType = 1;
//objofficeFinance.ofAmount = Convert.ToDecimal(strPrice.ToString().Trim());
//objofficeFinance.ofRemainAmount = Convert.ToDecimal(strPrice.ToString().Trim()) + objdm;
//objofficeFinance.ofIsCurrentValue = 1;
//objofficeFinance.ofUserId = -10;
//objofficeFinance.ofNote1 = \"支付宝上帐:\" + strPrice.ToString().Trim() + \"元\";
//objofficeFinance.ofNote2 = \"商户:\" + login[1].ToString().Trim() + \" 通过支付宝上帐金额:\" + strPrice + \"元\";
//objOfficeFinanceServices.addOfficeFinanceOne(objofficeFinance);
Response.Write(\"商户:\" + login[1].ToString().Trim() + \"<br>金额:\" + strPrice + \" 交易成功\"); //成功,可美化该页面,提示信息
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = \"MD5结果:mysign=\" + mysign + \",sign=\" + sign + \",responseTxt=\" + responseTxt + \" 交易信息\" + \"商户:\" + login[1].ToString().Trim() + \"<br>金额:\" + strPrice + \" 交易成功\";
StreamWriter fs = new StreamWriter(Server.MapPath(\"Return_DATA/\" + DateTime.Now.ToString().Replace(\":\", \"\")) + \".txt\", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
}
else
{
Response.Write(\"------------------------------------------\");
Response.Write(\"<br>Result:responseTxt=\" + responseTxt);
Response.Write(\"<br>Result:mysign=\" + mysign);
Response.Write(\"<br>Result:sign=\" + sign);
Response.Write(\"支付失败\");
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = \"MD5结果:mysign=\" + mysign + \",sign=\" + sign + \",responseTxt=\" + responseTxt;
StreamWriter fs = new StreamWriter(Server.MapPath(\"Return_DATA/\" + DateTime.Now.ToString().Replace(\":\", \"\")) + \".txt\", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
//支付失败,提示信息
}
}
}
这个是当交易成功后要调用 的界面 在这里只要改动一下就行了, 其实我们要做的只是改一下这里,只要在这里更新一下你的数据库就行了,
代码 //生成对象
//OfficeFinanceServices objOfficeFinanceServices = new OfficeFinanceServices();
//订单信息
string[] login = strOrderNO.Split(new string[] { \"_\" }, StringSplitOptions.RemoveEmptyEntries);
////查询当前的余额
//decimal objdm = objOfficeFinanceServices.OfficeFinanceSelect(Convert.ToInt32(login[0].ToString().Trim()), true);
//OfficeFinance objofficeFinance = new OfficeFinance();
//objofficeFinance.ofId = Convert.ToInt32(login[0].ToString().Trim());
//objofficeFinance.ofOrid = \"cz\";
//objofficeFinance.ofTime = DateTime.Now;
//objofficeFinance.ofType = 1;
//objofficeFinance.ofAmount = Convert.ToDecimal(strPrice.ToString().Trim());
//objofficeFinance.ofRemainAmount = Convert.ToDecimal(strPrice.ToString().Trim()) + objdm;
//objofficeFinance.ofIsCurrentValue = 1;
//objofficeFinance.ofUserId = -10;
//objofficeFinance.ofNote1 = \"支付宝上帐:\" + strPrice.ToString().Trim() + \"元\";
//objofficeFinance.ofNote2 = \"商户:\" + login[1].ToString().Trim() + \" 通过支付宝上帐金额:\" + strPrice + \"元\";
//objOfficeFinanceServices.addOfficeFinanceOne(objofficeFinance);大家现在会问我为什么会把他们注释了呢?
我测试过,,这个界面呢是只到成功的时候 调用 一次以后就再不会调用 了,
所以这样有一个不好的地方 ,就是有些客户他们对转帐操作的很老手,当交易成功之后不等调用这个界面就关闭了浏览器,这个时候会出现什么问题呢?
那支付宝就再也不会调用这个界面 了,只能等下次交易,钱是打上了,我们也收到了,但是就是没有给客户充上钱,这个时候客户就会打电话到公司,怎么回事啊, 钱打过去了, 可是我这边还没有上帐,我们上支付宝一看有啊,但就是没有上帐 ,怎么办,最后只能手动给客户上了,但又怕他程序再自动上一把,呵呵
所以在这里不我建议使用这个页面,如果你只是修改自己的订单状态的话当然是可以的
修改余额就不要在这里写了,而是写在这个Alipay_Notify.aspx页面里,这个界面是当交易状态 发生变化时就会调用 ,在没有收到成功的消息前就会一直调用,
时效是24小时,这样的话我们就不用管他是不是转到了成功页面了,只要把这个页面挂在网上等通知就行了,
当交易成功的时候上帐 就OK了 |
|