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

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

一、思考: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. webstorm离线装载Material Theme UI

    首先说说需求,由于直接用webstorm听说VS挺火的,但是初恋的感觉是其他任何编辑器无法替代的 瞎说了一些话,新公司内网开发,用的是vscode,但是我还是喜欢用webstorm,连不上网,所以不能 ...

  2. UVA 12108 Extraordinarily Tired Students

    思路: ①用结构体stu,属性有清醒时间,睡眠时间,开始处于的时间,状态(醒着还是睡着), 还有计数器. ②二维数组存表格. ③在确定接下来要进入的状态之后,就一次把表格里持续状态的数据都修改掉,比如 ...

  3. 拓扑排序 --- AtCode - 3596

    题目链接: https://cn.vjudge.net/problem/1137733/origin 拓扑排序的基本思想: https://blog.csdn.net/qq_41713256/arti ...

  4. Eclipse纯净版安装web插件

    打开 Help -> Install New Software. 在Install界面板中,点击Add按钮输入:然后在输入http://download.eclipse.org/releases ...

  5. JavaScript基础笔记(二)变量、作用域和内存问题

    变量.作用域和内存问题 一.基本类型和引用类型的值 基本类型值:简单的数据段 引用类型值:由多个值构成的对象 基本类型是按值访问的,引用类型是按引用访问的. 不能给基本类型的值添加属性,尽管不会报错. ...

  6. linux 文件打包压缩成.tar.gz

    tar czvf beian.drcluod.cn.20180509.tar.gz ./beian.drcloud.cn/*

  7. Java基础-对象的内存分配与初始化(一定要明白的干货)

    首先,什么是类的加载?类的加载由类加载器执行.该步骤将查找字节码(classpath指定目录),并从这些字节码中创建一个Class对象.Java虚拟机为每种类型管理一个独一无二的Class对象.也就是 ...

  8. (转)java创建对象的步骤

    关于对象的创建过程一般是从new指令(我说的是JVM的层面)开始的(具体请看图1),JVM首先对符号引用进行解析,如果找不到对应的符号引用,那么这个类还没有被加载,因此JVM便会进行类加载过程.符号引 ...

  9. redis(三)

    string string是redis最基本的类型 最大能存储512MB数据 string类型是二进制安全的,即可以为任何数据,比如数字.图片.序列化对象等 命令 设置 设置键值 set key va ...

  10. Expedition [POJ2431] [贪心]

    题目大意: 有n个加油站,每个加油站的加油的油量有限,距离终点都有一个距离. 一个卡车的油箱无限,每走一个单元要消耗一单元的油,问卡车到达终点的最少加多少次油. 分析: 我们希望的是走到没油的时候就尽 ...