微信JSApi支付~訂單號和(he)微信交易號
談談transactionId和out_trade_no
前一篇微信JSApi支付~坑和如何填坑文章反映不錯,所以又寫了個后篇,呵呵。
每個(ge)(ge)(ge)第(di)三(san)方(fang)在線支(zhi)付(fu)系(xi)(xi)統(tong)(tong)中都會有至少兩類訂(ding)(ding)單(dan)(dan)號(hao),其一為支(zhi)付(fu)系(xi)(xi)統(tong)(tong)的(de)訂(ding)(ding)單(dan)(dan)號(hao),我們(men)(men)(men)稱(cheng)為transactionId,其二為商(shang)(shang)戶(hu)平(ping)臺(tai)的(de)訂(ding)(ding)單(dan)(dan)號(hao),我們(men)(men)(men)通常稱(cheng)為out_trade_no,這兩個(ge)(ge)(ge)號(hao)一般用來對賬,在第(di)三(san)方(fang)支(zhi)付(fu)平(ping)臺(tai)你可以(yi)通過(guo)這兩個(ge)(ge)(ge)訂(ding)(ding)單(dan)(dan)號(hao)來查詢訂(ding)(ding)單(dan)(dan)的(de)狀態(tai),而在商(shang)(shang)戶(hu)自己的(de)網(wang)站后臺(tai),也可以(yi)查詢它(ta)的(de)狀態(tai),一般地,transactionId由支(zhi)付(fu)系(xi)(xi)統(tong)(tong)生成,并在回調(diao)時轉回給(gei)商(shang)(shang)戶(hu);而out_trade_no一般在商(shang)(shang)戶(hu)平(ping)臺(tai)生成,自己可以(yi)設計自己的(de)規則,然后把這個(ge)(ge)(ge)ID轉到第(di)三(san)方(fang)支(zhi)付(fu)平(ping)臺(tai),在支(zhi)付(fu)成功后,第(di)三(san)方(fang)同樣把這個(ge)(ge)(ge)號(hao)轉回來,我們(men)(men)(men)通過(guo)這個(ge)(ge)(ge)號(hao)進行商(shang)(shang)戶(hu)系(xi)(xi)統(tong)(tong)的(de)其它(ta)操作。
看一下第三方支付的流程圖
對第三方支付的封裝
封裝要求通用,對任何一個項目都可以靈活的使用它,這是最重要的,要想實現松耦合,需要記住委托的(de)概念,我(wo)們在訂單(dan)回調時(shi),定(ding)義一個(ge)訂單(dan)所要數據的(de)實(shi)體,然后以(yi)這個(ge)實(shi)體做為參數,定(ding)義一個(ge)委(wei)托,當然你(ni)完全可以(yi)使用.net為我(wo)們提供的(de)Action,Func等通用的(de)委(wei)托對象,這在大(da)叔(shu)框架(jia)里通常被看到,也(ye)是大(da)叔(shu)的(de)常客!
下面是(shi)微信支付(fu)的封(feng)裝,可以看到業務代(dai)碼只寫(xie)自(zi)己業務,而不處理任務微信API相(xiang)關的東西
/// <summary> /// 返回鏈接(jie)串 /// </summary> /// <returns></returns> public string Get() { int money = 10; string orderID = "Lind0001"; Logger.LoggerFactory.Instance.Logger_Info("發送(song)訂單號" + orderID); return JsApiImplement.Send(money, orderID); } //微信回調 public void Notify() { JsApiImplement.Notify((model) => { Logger.LoggerFactory.Instance.Logger_Info("回調訂單號" + model.Out_Trade_No); //更新領域訂單(dan)狀態,用戶賬戶數據,流(liu)水等 }); }
微信回(hui)調(diao)實體是(shi)大(da)叔自己(ji)定義(yi)的(de)(de),應該可以滿(man)足大(da)部(bu)分業務的(de)(de)需要了,主要用(yong)于(yu)回(hui)調(diao)業務層(ceng)的(de)(de)方(fang)法(fa)
/// <summary> /// 微信回調數據(ju)模型 /// </summary> public class NotifyModel { /// <summary> /// 當次交易存儲到微信平臺的訂單號 /// </summary> public string Transaction_Id { get; set; } /// <summary> /// 系統(tong)本身生成的訂(ding)單號 /// </summary> public string Out_Trade_No { get; set; } /// <summary> /// 對應當前公眾號的用戶OpenId /// </summary> public string OpenId { get; set; } /// <summary> /// 微信用戶唯一標(biao)識 /// </summary> public string UniqueId { get; set; } }
而對于方法回調JsApiImplement.Notify方(fang)法,我們在底層進行了封(feng)裝,對外公開一(yi)個(ge)委(wei)托(tuo),這個(ge)委(wei)托(tuo)實現了方(fang)法的(de)回調(diao),當執行到微信核心業務(wu)時,回調(diao)業務(wu)層的(de)方(fang)法即可。
/// <summary> /// JsApi微信回調 /// </summary> public static void Notify(Action<NotifyModel> action) { var context = System.Web.HttpContext.Current; ResultNotify resultNotify = new ResultNotify(context); resultNotify.ProcessNotify(action); }
其實,我在看微信API時,也發現了不少問題,感覺他們的.net開發人員功力不夠,或者說代碼不是很嚴謹,但一些公用基類,應該聲明為abstract,一般必須要子類實現(xian)的方法,應該聲明為abstract,但它們都沒有這(zhe)樣做,感覺(jue)很奇怪,哈哈,下(xia)面是我對微信Notify
類的(de)修改,加了(le)一些應(ying)該加的(de),去了(le)一些應(ying)該去的(de),感覺舒服多(duo)了(le)!
/// <summary> /// 回調處理基類(lei) /// 主要負責接(jie)收微信支付后臺發送過(guo)來的(de)數(shu)據(ju),對(dui)數(shu)據(ju)進行簽名驗證 /// 子類在此類基(ji)礎上進(jin)行派生并重寫自(zi)己的回調處理(li)過(guo)程 /// </summary> public abstract class Notify { public HttpContext page { get; set; } public Notify(HttpContext page) { this.page = page; } /// <summary> /// 接(jie)收從微(wei)信(xin)支付后臺發送過來的數(shu)據并驗證簽名 /// </summary> /// <returns>微信(xin)支付后臺返回的數據</returns> public WxPayData GetNotifyData() { //接收從微信后(hou)臺POST過來的數據(ju) System.IO.Stream s = page.Request.InputStream; int count = 0; byte[] buffer = new byte[1024]; StringBuilder builder = new StringBuilder(); while ((count = s.Read(buffer, 0, 1024)) > 0) { builder.Append(Encoding.UTF8.GetString(buffer, 0, count)); } s.Flush(); s.Close(); s.Dispose(); Log.Info(this.GetType().ToString(), "Receive data from WeChat : " + builder.ToString()); //轉換數(shu)據格式并驗證簽名 WxPayData data = new WxPayData(); try { data.FromXml(builder.ToString()); } catch (WxPayException ex) { //若簽名錯誤,則立(li)即返(fan)回結果給微信支付(fu)后臺 WxPayData res = new WxPayData(); res.SetValue("return_code", "FAIL"); res.SetValue("return_msg", ex.Message); Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml()); page.Response.Write(res.ToXml()); page.Response.End(); } Log.Info(this.GetType().ToString(), "Check sign success"); return data; } //派生類自已必須重寫這個方法(fa) public abstract void ProcessNotify(Action<NotifyModel> action); }
對于(yu)第三方支付就說到這(zhe)樣,希望大家自己也對一些東西(xi)進行(xing)封裝,方便其它項目(mu)中直接使用它們(men)!