开发微信应用,微信支付是永远要面对的。现在的微信支付相对以往已经很稳定,很少出现诡异情况。再加上无数人开发的经验分享,现在开发微信支付已经没什么难度了。

我这次主要是想基于沐雪微信平台的微商城业务来分析微信支付到底该怎么做。主要讲思路,代码也同时会献上。

一、思考:1、支付前系统该做什么?2、支付的时候该怎么处理业务?3、同步和异步回调该怎么处理业务逻辑?4、安全性,稳定性,数据一致性如何保证?

分析:第1个问题:支付前的一个页面一般来说是订单确认页面,在支付前,必须把该订单的所有数据(订单编号等基本数据,用户信息,订单商品信息,物流信息等)都保存到数据库,状态设置为“待支付”;再跳转到微信支付页面,微信支付页面接收到参数(订单编号,wid,业务模块编号)立即处理逻辑:

 public class PayController : BaseController
{
string module = "支付页面"; /// <summary>
/// 微信支付
/// </summary>
/// <param name="wid"></param>
/// <param name="moduletype">业务分类</param>
/// <param name="orderNo"></param>
/// <returns></returns>
public ActionResult WXPaySubmit(int wid,string moduletype,string orderNo)
{
string parameters = string.Format("wid:{0},moduletype:{1},orderNo:{2}", wid,moduletype, orderNo);
string operating = "微信支付页面"; bool isWeiXin = false;
ViewBag.errorInfo = "";
ViewBag.pay_json = "";
string pay_uri = "";
string userAgent = base.Request.UserAgent; try
{
LogHelper.Info(parameters, 0, fromplat, module, operating); if (userAgent.ToLower().IndexOf("micromessenger") > -1)
{
isWeiXin = true;
}
ViewBag.isWeiXin = isWeiXin;
ViewBag.pay_uri = pay_uri; if (string.IsNullOrWhiteSpace(orderNo))
{
ViewBag.errorInfo = "订单号为空,不能进行支付!";
return View();
}
ViewBag.orderNo = orderNo; BLL.orders otBll = new BLL.orders();
Model.orders orderEntity = otBll.GetModel(orderNo, wid);
if (orderEntity == null)
{
ViewBag.errorInfo = "错误的订单号,不能进行支付!";
return View();
}
if (orderEntity.payment_status != 1 || orderEntity.status != 1)
{
ViewBag.errorInfo = "订单状态错误,不能进行支付!";
return View();
}
BLL.wx_crm_users userBll = new BLL.wx_crm_users();
Model.wx_crm_users user = userBll.GetModel(orderEntity.user_id, wid); if (orderEntity.payment_id == 1)
{
//线下付款
ViewBag.isOfflineOrder = true;
}
else
{
ViewBag.isOfflineOrder = false;
}
ViewBag.IsServiceOrder = false;//服务订单
ViewBag.isFightGroup = false;//团购的订单
ViewBag.Wid = wid; string packageValue = "";
if (orderEntity.payment_id == 3)
{//微信支付
packageValue = WxPayDataV3(wid, orderEntity.order_amount, orderEntity.orderSubject, orderEntity.order_no, orderEntity.id, orderEntity.user_id, user.openid);
} ViewBag.packageValue = packageValue;
}
catch (Exception ex)
{ LogHelper.Error(parameters + ",message:" + ex.Message, ex, wid , fromplat, module, operating);
} return View();
} /// <summary>
/// 微信支付最新接口调用
/// 2018-9-20 搬家
/// </summary>
/// <param name="wid">微账号</param>
/// <param name="ttFee">支付金额(单位元)</param>
/// <param name="busiBody">订单内容</param>
/// <param name="out_trade_no">订单号</param>
/// <param name="code"></param>
protected string WxPayDataV3(int wid, decimal ttFee, string busiBody, string out_trade_no, int order_id,int user_id,string openid)
{
string operating = "微信支付最新接口调用";
string parameters = string.Format("wid:{0},ttFee:{1},busiBody:{2},out_trade_no:{3},order_id:{4},user_id:{5},openid:{6}", wid, ttFee, busiBody, out_trade_no, order_id, user_id, openid); try
{
LogHelper.Info(parameters, 0, fromplat, module, operating); JsApiConfig jsapiConfig = new JsApiConfig(wid, SysModuleNameEnum.微商城); if (jsapiConfig == null)
{
LogHelper.Warn("微信支付没有配置正确(wid=" + wid + ")", user_id, fromplat, module, operating);
return null;
} string packageValue = ""; //先设置基本信息
string MchId = jsapiConfig.MchId;
string partnerKey = jsapiConfig.Key;// 商户支付密钥Key。登录微信商户后台,进入栏目【账户设置】【密码安全】【API 安全】【API 密钥】
string notify_url = jsapiConfig.Notify_url;// MyCommFun.getAppSettingValue("webapi_url") + "/api/Pay/notify_url";//回调函数 string timeStamp = "";
string nonceStr = "";
string paySign = ""; string sp_billno = out_trade_no;
//当前时间 yyyyMMdd
string date = DateTime.Now.ToString("yyyyMMdd"); if (null == sp_billno)
{
//生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一
sp_billno = DateTime.Now.ToString("HHmmss") + TenPayV3Util.BuildRandomStr(28);
} timeStamp = TenPayV3Util.GetTimestamp();
nonceStr = TenPayV3Util.GetNoncestr();
string attach = wid + "|" + order_id +"|" + user_id;
int price = (int)(ttFee * 100);//商品金额,以分为单位(money * 100).ToString()
var xmlDataInfo = new TenPayV3UnifiedorderRequestData(jsapiConfig.AppId, MchId, busiBody, sp_billno, price, Request.UserHostAddress, notify_url, TenPayV3Type.JSAPI, openid, partnerKey, nonceStr, "vshop", null, null, "", attach); LogHelper.Info(parameters + ",xmlDataInfo=" + xmlDataInfo.ToString(), 0, fromplat, module, operating);
var result = TenPayV3.Unifiedorder(xmlDataInfo);//调用统一订单接口 string prepayId = result.prepay_id; LogHelper.Info(parameters + ",预支付的prepayId=" + prepayId, 0, fromplat, module, operating); //设置支付参数
paySign = TenPayV3.GetJsPaySign(jsapiConfig.AppId, timeStamp, nonceStr, string.Format("prepay_id={0}", prepayId), partnerKey); packageValue = "";
packageValue += " \"appId\": \"" + jsapiConfig.AppId + "\", ";
packageValue += " \"timeStamp\": \"" + timeStamp + "\", ";
packageValue += " \"nonceStr\": \"" + nonceStr + "\", ";
packageValue += " \"package\": \"" + string.Format("prepay_id={0}", prepayId) + "\", ";
packageValue += " \"signType\": \"MD5\", ";
packageValue += " \"paySign\": \"" + paySign + "\""; LogHelper.Info(parameters + ",packageValue=" + packageValue, 0, fromplat, module, operating);
return packageValue;
}
catch (Exception ex)
{ LogHelper.Error(parameters + ",message:" + ex.Message, ex, wid, fromplat, module, operating);
throw;
} } }

  将数据给试图里处理,jssdk调起微信支付。试图页里只有一段Js,其他的都不需要放。

        <script type="text/javascript">
var orderNo = "@ViewBag.orderNo";
var IsServiceOrder = "@ViewBag.IsServiceOrder";
var isFightGroup = "@ViewBag.isFightGroup";
var isOfflineOrder = "@ViewBag.isOfflineOrder";
//调用微信JS api 支付
function jsApiCall() {
WeixinJSBridge.invoke('getBrandWCPayRequest', { @Html.Raw(ViewBag.packageValue) }, function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
alert("订单支付成功!点击确认进入我的订单中心"); location.replace("/VShop/Order/OrderDetail/@ViewBag.Wid?orderno=" + orderNo);
}
else {
//alert(res.err_code + res.err_desc + res.err_msg); if (res.err_msg.indexOf("cancel") != -1) {
//主动取消支付
}
else {
alert("支付取消或者失败res.err_msg=" + res.err_msg);
}
location.replace("/VShop/Order/OrderDetail/@ViewBag.Wid?orderno=" + orderNo); }
//alert("订单支付成功!点击确认进入我的订单中心");
});
} function callpay() {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}
else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}
else {
jsApiCall();
}
}
callpay();
</script>

  

有人肯定会问,为啥不把微信支付功能与订单确认页放在同一个页面?或者是微信支付页面是否要显示支付的金额然后再加个确认支付按钮?

沐雪微信平台之所以这么做,原因有几点:1、订单确认页面逻辑相当庞杂,2、而微信支付跟订单其实是两块业务逻辑,3、支付业务可以抽出来作为公共的方法页面;4、随着业务模块增多,支付页面的逻辑也会越来越复杂;5、代码隔离带来无限的好处;6、个人不喜欢一个页面承担太多东西,宁愿牺牲点用户体验,也不喜欢吧代码融合在一起;7、根据以往经验,代码融合在一个页面,一个页面代码越多,出错的概率越是成倍的增长,排查问题的难度也越大,非常不利于代码迭代更新与的长期维护;

支付完成后,就跳转到用户中心的订单详情页面查看信息;一般是间隔2,3秒才跳,等待异步回调处理;

异步回调函数里,一定要验证签名:

asp.net mvc 微信支付代码分析(根据沐雪微信平台3.1商城业务来分析)的更多相关文章

  1. asp微信支付代码证书文件post_url.aspx和post_url.aspx.cs源码下载

    很多朋友在网上找的asp支付代码中都没有这两个证书文件,只能是用别人的,但是如果别人把他的网站这个文件删了,你的支付也就不能用了,今天我就把大家需要的这两个asp微信支付代码证书文件post_url. ...

  2. Asp.net mvc 5 CRUD代码自动生成工具- vs.net 2013 Saffolding功能扩展

    Asp.net mvc 5 CRUD代码自动生成工具 -Visual Studio.net2013 Saffolding功能扩展 上次做过一个<Asp.net webform scaffoldi ...

  3. DELPHI微信支付代码

    DELPHI微信支付代码   不管是微信支付还是支付宝支付, 3个最棘手的问题是:1,如何生成签名2,支付请求如何提交3, 如何验证签名 下面就围绕这二个问题来讲. 我使用的是XE3. 先看微信支付: ...

  4. asp微信支付代码v4.1无需证书版,带回调入库的asp支付源码

    昨天帮一个客户写的,他的程序是老的asp,想实现微信在手机上下单付款,让帮忙给写一份asp微信支付的接口代码,昨天晚上闲着没事,搞了一个晚上才搞好,其实asp支付并不需要安装证书,其实asp支付也很好 ...

  5. ASP.NET MVC Display Mode 移动端视图 配置对微信内置浏览器的识别

    最近在捣鼓一个稍微有点low的商城网站,没有计划做app却要求有个wap版,而前端又没有做成响应式,时间WTF,直接利用了asp.net mvc的Display Mode Provider. 使用方式 ...

  6. JAVA微信支付代码(WeChatPay.java 才是调用类)

    微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html MD5Util.java package weixin; import java.se ...

  7. ASP.NET MVC 简单分页代码

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  8. vue-cli中进行微信支付代码详解

    最近做微信支付,颇经历一番波折,这里总结一下,便于以后少走弯路: 在进行微信支付,除了需要公众号之外,你还需要一个微信商户.根据商户规则进行商户申请 这是公众号的基本开发配置,这里在微信授权的时候就已 ...

  9. 新建 ASP.NET MVC 项目快速代码

    视图模型- PagingInfo 类: public class PagingInfo { public int TotalItems { get; set; } public int ItemsPe ...

随机推荐

  1. linux 学习笔记 软件包管理

    >查询文件所属软件包 #rpm -qf /usr/share/pixmaps/xplns.png 查询某个文件所属软件包 >查询软件包所包含文件列表 #rpm -ql xplus-3.3. ...

  2. linux 学习笔记 ftp

    server with sites set up for download files sometimes provide an anonymous ftp account 数据传输 ftp 192. ...

  3. Java笔记(六)列表和队列

    列表和队列 一)ArrayList 1.基本原理 ArrayList是一个泛型容器.内部会有一个数组elementData,一般会有预留空间 有一个整数记录实际的元素个数. private trans ...

  4. cout endl in c++

    #include<iostream> using namespace std; int main() { cout<<endl; endl(cout); getchar(); ...

  5. maven命令注册jar包到maven仓库

    首先需要具备maven环境 在cmd命令行执行以下命令注册jar包 mvn install:install-file -Dfile=E:\aliyun-java-sdk-dysmsapi-1.0.0. ...

  6. 获取Gitlab项目的Token

    获取Gitlab项目的Token 1.打开所需要Token的项目的主页进入CI/CD setting Setting -> CI/CD -> Genneral pioelines sett ...

  7. eclipse编辑环境下导入springmvc的源码

    如果想要查看@ModelAttribute的源码,只需要,点击ctrl+鼠标左键,就会出现attach--,点击attach--,external,选择类似springframe-web-source ...

  8. vue中引用vux

    官网看不懂,网上搜了下,以备不时之需 这是官网说明文档,看不懂的啊. Vux使用教程: 1,在项目里安装vux cnpm install vux --save 2,在项目里安装vux-loader(这 ...

  9. 【数论】Factors of Factorial @upcexam6503

    问题 G: Factors of Factorial 时间限制: 1 Sec  内存限制: 128 MB提交: 57  解决: 33[提交][状态][讨论版][命题人:admin] 题目描述 You ...

  10. poj3616 Milking Time(状态转移方程,类似LIS)

    https://vjudge.net/problem/POJ-3616 猛刷简单dp的第一天第二题. 这道题乍一看跟背包很像,不同的在于它是一个区间,背包是定点,试了很久想往背包上套,都没成功. 这题 ...