一. 案例介绍

这里模拟一个实际业务场景,进行介绍微信支付,业务功能包括:登录、注册、充值、查看充值记录。

  

页面图:

       

二. 概要设计

1.数据库设计

  这里数据库包括两张表:用户表和订单表。

  用户表: 主键id、用户名、密码、openid、注册时间

  订单表: 主键id、用户id,商品名称、订单状态(0代表下单了未支付,1代表支付成功)、商品价钱、下单时间

  

2.微信支付流程

  这里结合该案例,来说明微信支付流程。

  该流程中涉及到4种角色,分别是微信用户、微信客户端、商户系统(自己的系统)、微信支付系统。

  流程1:

  ①用户登录微信客户端系统→②进入主页→③去支付→④生成商户系统订单→⑤调用微信统一下单API,在微信支付系统里生成预支付订单,并返回预支付订单信息→

  ⑥商户系统拿到返回的预支付订单信息,进行签名,便按照一定的格式返给微信客户端(JSAPI页面)→⑦微信客户端JSAPI页面拿到参数,请求支付,输入密码,进行支付→

  ⑧这时会进行2个并行处理→异步通知商户支付结果,商户系统接到通知后,需要修改订单的业务逻辑(该案例修改订单状态0改为1),商户系统需要告知微信系统处理结果

  →给微信客户端发送支付结果,并发微信消息提示 

  ⑨微信客户端跳转到商户H5页面,查询商户后台支付结果

  ⑩ 这时候分两种情况

    A. 商户后台系统,已经接到通知,进行了业务修改,直接返回成功。

    B. 商户后台系统,没有接到通知,这时去查询微信支付系统,如果微信支付系统成功,说明确实付款成功,只是因为网络延迟造成商户后台暂时没有接到通知,如果查询后发现未付款成功,则返回付款失败。

微信支付业务流程图:
       

3.代码配置

(1).参数配置

(2).前端页面代码

    $(function () {
// 当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
//公众号支付
document.getElementById("pay").onclick = function () {
//1.前端验证
var money = $('#num').val();
if (money == "") {
alert('请将信息输入完整');
return;
}
mui('#pay').button('loading');
//2.进行下单
$.ajax({
type: 'POST',
url: '/WeiXinGz/GetAPI',
data: { "money": money },
cache: false,
dataType: 'json',
success: function (jsonData) {
if (jsonData.status == "") {
//公众号支付
WeixinJSBridge.invoke('getBrandWCPayRequest', jsonData.payData, function (res) {
// 使用以下方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
//【因此微信团队建议:】当收到ok返回时,向商户后台询问是否收到交易成功的通知,
//若收到通知,前端展示交易成功的界面;
//若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
if (res.err_msg == "get_brand_wcpay_request:ok") {
//JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回
$.ajax({
type: 'POST',
url: '/WeiXinGz/QueryOrder',
data: {
orderId: jsonData.orderId
},
cache: false,
dataType: 'text',
success: function (jsonData) {
if (jsonData == "ok") {
alert("支付成功", "提示", function () {
alert("页面跳转等业务处理");
});
mui('#pay').button('reset');
} else {
alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付1!");
mui('#pay').button('reset');
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付2!");
mui('#pay').button('reset');
}
});
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
//由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
alert("您放弃了支付");
mui('#pay').button('reset');
} else {
//由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付3!");
mui('#pay').button('reset');
}
});
} else {
alert(jsonData.promptInfor);
mui('#pay').button('reset');
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("微信订单提交失败,请稍后重试4!");
mui('#pay').button('reset');
}
}); }
}, false);
});

(3).统一下单接口

    /// <summary>
/// 统一下单接口
/// </summary>
/// <param name="money">钱数</param>
/// <returns></returns>
public ActionResult GetAPI(string money)
{
try
{
//一.系统本身自有的业务处理
//1.必要信息的初始化
string userId = Session["userId"].ToString(); //用户主键
UserInfor userInfor = db.Set<UserInfor>().Where(a => a.id == userId).FirstOrDefault();
string orderId = GenerateOrderNum(); //生成订单号
string totalFee = money;//设置默认商品费用为【1分】
string nonceStr = TenPayV3Util.GetNoncestr(); //获取 随机字符串
string openid = userInfor.openId;
//2.自己商户系统下单
OrderInfor orderInfor = new OrderInfor();
orderInfor.id = orderId;
orderInfor.uid = userInfor.id;
orderInfor.goodName = "测试商品";
orderInfor.goodPrice = totalFee;
orderInfor.addTime = DateTime.Now;
orderInfor.status = ""; //已经下单,但未付款
db.Set<OrderInfor>().Add(orderInfor);
db.SaveChanges(); //二.微信系统下单
//1.创建支付应答对象并初始化
RequestHandler packageReqHandler = new RequestHandler(null);
packageReqHandler.Init();
//1.1设置统一下单的参数
packageReqHandler.SetParameter("appid", ConfigHelp.AppSettings("AppId")); //公众账号ID
packageReqHandler.SetParameter("mch_id", ConfigHelp.AppSettings("MchId")); //商户号
packageReqHandler.SetParameter("nonce_str", nonceStr); //随机字符串
packageReqHandler.SetParameter("body", "科技-服务"); //商品描述
packageReqHandler.SetParameter("out_trade_no", orderId); //商户订单号
packageReqHandler.SetParameter("total_fee", totalFee); //商品金额,以分为单位
packageReqHandler.SetParameter("spbill_create_ip", Request.UserHostAddress); //终端IP
packageReqHandler.SetParameter("notify_url", ConfigHelp.AppSettings("notify_url")); //微信支付异步通知回调地址
packageReqHandler.SetParameter("trade_type", "JSAPI"); //交易类型 代表公众号支付
packageReqHandler.SetParameter("openid", openid); //用户标识
string sign = packageReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //预支付签名
packageReqHandler.SetParameter("sign", sign);
//1.2 下单数据格式转换
string data = packageReqHandler.ParseXML();
//1.3 进行下单
string result = TenPayV3.Unifiedorder(data);
//2.对下单返回结果进行分析
XDocument res = XDocument.Parse(result);
//2.1 对返回结果进行判断 //2.2 成功的情况下获取必要的参数
string prepayId = res.Element("xml").Element("prepay_id").Value; //获取预支付订单编号prepayId
//3. 获取支付参数并签名
string timeStamp = TenPayV3Util.GetTimestamp(); //获取时间戳
//设置支付参数
RequestHandler paySignReqHandler = new RequestHandler(null);
paySignReqHandler.SetParameter("appId", ConfigHelp.AppSettings("AppId"));
paySignReqHandler.SetParameter("timeStamp", TenPayV3Util.GetTimestamp());
paySignReqHandler.SetParameter("nonceStr", nonceStr);
paySignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepayId));
paySignReqHandler.SetParameter("signType", "MD5"); //签名【MD5】
string paySign = paySignReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //JSAPI支付签名
var payData = new
{
appId = ConfigHelp.AppSettings("AppId"),
timeStamp = timeStamp,
nonceStr = nonceStr,
package = string.Format("prepay_id={0}", prepayId),
signType = "MD5",
paySign = paySign,
};
return Json(new
{
status = "",
promptInfor = "微信下单成功",
payData = payData,
orderId = orderId
});
}
catch (Exception ex)
{
string a = ex.Message; return Json(new
{
status = "",
promptInfor = a
});
}
}

(4).微信异步通知接口

   public ActionResult PayNotifyUrl()
{
//获取当前http请求
HttpContext httpContext = System.Web.HttpContext.Current;
ResponseHandler notifyDataHandler = new ResponseHandler(httpContext);
//返回状态码【SUCCESS/FAIL】此字段是通信标识
string return_code = notifyDataHandler.GetParameter("return_code");
//返回信息【如非空,为错误原因】
string return_msg = notifyDataHandler.GetParameter("return_msg");
//表示通信成功
if (return_code == "SUCCESS")
{
//获取业务结果【交易是否成功(SUCCESS/FAIL)】
string result_code = notifyDataHandler.GetParameter("result_code");
//表示业务结果成功
if (result_code == "SUCCESS")
{
//设置签名密钥
notifyDataHandler.SetKey(ConfigHelp.AppSettings("key"));
//验证请求是否从微信发过来(安全)【验证签名】
if (notifyDataHandler.IsTenpaySign())
{
//获取订单编号
string out_trade_no = notifyDataHandler.GetParameter("out_trade_no");
//检查是否返回商户订单号
if (!string.IsNullOrEmpty(out_trade_no))
{
try
{
OrderInfor orderInfor = db.Set<OrderInfor>().Where(a => a.id == out_trade_no).FirstOrDefault();
if (orderInfor != null)
{
//这里需要根据订单号更改系统的业务
//这里模拟测试记录订单号
orderInfor.status = ""; //表示付款成功,成功回调
db.Entry(orderInfor).State = EntityState.Modified;
db.SaveChanges(); return_code = "SUCCESS";
return_msg = "OK";
}
else
{
return_code = "FAIL";
return_msg = "商户系统中不存在该订单";
}
}
catch (Exception ex)
{
//系统异常
return_code = "FAIL";
return_msg = ex.Message;
}
}
else
{
//支付结果中商户订单号不存在
return_code = "FAIL";
return_msg = "支付结果中商户订单号不存在";
}
}
else
{
//签名失败
return_code = "FAIL";
return_msg = "签名失败";
}
}
else
{
//交易失败
return_code = "FAIL";
return_msg = "交易失败";
}
}
//商户处理后同步返回给微信参数
string xml = string.Format(@"<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>", return_code, return_msg);
//返回处理结果
return Content(xml, "text/xml");
}

(5).JSAPI接口请求

  //公众号支付
WeixinJSBridge.invoke('getBrandWCPayRequest', jsonData.payData, function (res) {
// 使用以下方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
//【因此微信团队建议:】当收到ok返回时,向商户后台询问是否收到交易成功的通知,
//若收到通知,前端展示交易成功的界面;
//若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
if (res.err_msg == "get_brand_wcpay_request:ok") {
//JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回
$.ajax({
type: 'POST',
url: '/WeiXinGz/QueryOrder',
data: {
orderId: jsonData.orderId
},
cache: false,
dataType: 'text',
success: function (jsonData) {
if (jsonData == "ok") {
alert("支付成功", "提示", function () {
alert("页面跳转等业务处理");
});
mui('#pay').button('reset');
} else {
alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付1!");
mui('#pay').button('reset');
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付2!");
mui('#pay').button('reset');
}
});
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
//由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
alert("您放弃了支付");
mui('#pay').button('reset');
} else {
//由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付3!");
mui('#pay').button('reset');
}
});
 
(6).微信订单查询接口

  /// <summary>
/// 微信订单查询接口
/// </summary>
/// <param name="orderId">订单编号id</param>
/// <returns></returns>
//[WeixinInternalRequest("无法访问!")]
public ActionResult QueryOrder(string orderId)
{
try
{
//一.先查商户后台的订单状态,判断微信端是否异步通知商户后台了!!!
OrderInfor orderInfor = db.Set<OrderInfor>().Where(a => a.id == orderId).FirstOrDefault();
//判断订单状态
if (orderInfor.status == "")
{
//表示查询成功
return Content("ok");
}
else if (orderInfor == null || orderInfor.status != "")
{
//二.进行调用下面的微信查询api进行查询
//生成随机字符串
string nonceStr = TenPayV3Util.GetNoncestr();
RequestHandler packageReqHandler = new RequestHandler(null);
//设置package订单参数
packageReqHandler.SetParameter("appid", ConfigHelp.AppSettings("AppId")); //公众账号ID
packageReqHandler.SetParameter("mch_id", ConfigHelp.AppSettings("MchId")); //商户号
packageReqHandler.SetParameter("out_trade_no", orderId); //填入商家订单号
packageReqHandler.SetParameter("nonce_str", nonceStr); //随机字符串
string sign = packageReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key"));//参数进行签名
packageReqHandler.SetParameter("sign", sign); //参数中添加签名字符串
string data = packageReqHandler.ParseXML(); //将传的参数转化为XML格式字符串
var result = TenPayV3.OrderQuery(data); //调用订单查询接口
var res = XDocument.Parse(result);
//返回状态码【SUCCESS/FAIL】此字段是通信标识
string return_code = res.Element("xml").Element("return_code").Value;
if (return_code == "SUCCESS")
{
//获取业务结果【交易是否成功(SUCCESS/FAIL)】
string result_code = res.Element("xml").Element("result_code").Value;
if (result_code == "SUCCESS")
{
//交易状态
/**SUCCESS—支付成功
*REFUND—转入退款
*NOTPAY—未支付
*CLOSED—已关闭
*REVOKED—已撤销(刷卡支付)
*USERPAYING--用户支付中
*PAYERROR--支付失败(其他原因,如银行返回失败)
*/
string trade_state = res.Element("xml").Element("trade_state").Value;
if (return_code == "SUCCESS")
{
return Content("ok");
}
}
} }
//未查询到该订单或者该订单交易状态不相符
return Content("error");
}
catch (Exception ex)
{
//抛异常信息,返回异常消息
return Content(ex.Message);
}
}

上述代码中,用到的openid,需要事先获取

 亲测好用,如有问题,可联系QQ 604649488
 
 
 
 
 
 
 
 

.Net版微信支付的更多相关文章

  1. 非微信内如何调起wap版微信支付

    微信支付一直没有出wap版,wap版想用微信支付,只有在微信内调用才可以.今天偶然发现,中国电信一个wap站点, 不在微信内也能调起微信支付,而且官方还提供了一个demo. WAP怎么调起客户端? 在 ...

  2. java版微信支付/查询/撤销

    最近公司接入微信刷卡支付,网上根本没见到很直接的教程(可能眼拙),一直摸滚打爬,加班加点才走通,忍不了必须写一写 微信 刷卡支付/查询/撤销... 必须要有公众号然后去申请,申请自己去看文档,这里主要 ...

  3. 微信支付(.NET版)

    前段时间做了网页版微信支付,遇到很多问题,不过最终还是解决了,现在在这里记录下开发流程以及说明,给其他人一些参考. 一.准备工作     首先肯定得先要开通微信支付功能,之前开通微信支付需要三万的押金 ...

  4. 到处都是坑的微信支付V3

    业务需要一个在微信上能付款的功能,于是乎想到了最普遍的支付宝,坑爹的是T与A是水火不容啊,默默的还是接微信支付吧,没想到从此掉进了连环坑…… 网上写微信支付接口的还是很多,PHP官方有(鄙视源码作者, ...

  5. ecshop微信支付(0923更新)商户支付密钥key的生成与设置

    ECSHOP 微信支付(0923更新)商户支付密钥key的生成与设置 说明:新版微信支付,用户必须授权登录才能支付.需要商家自己设置商户号支付密钥. 申请微信支付手机版部分时需要填写的配置接口地址: ...

  6. JS-SDK微信支付开发攻略

    一.吐槽篇 一个字——坑!两个字——很坑!三个字——非常坑!首先,微信支付接口作为微信开发接口的一部分,竟然有一本书那么厚的官方文档,共36页,更重要的是,这36页还不能把开发的流程说清楚,描述过于分 ...

  7. 在Web应用中接入微信支付的流程之极简清晰版

    在Web应用中接入微信支付的流程之极简清晰版 背景: 在Web应用中接入微信支付,我以为只是调用几个API稍作调试即可. 没想到微信的API和官方文档里隐坑无数,致我抱着怀疑人生的心情悲愤踩遍了丫们布 ...

  8. 微信支付开发(1) JS API支付V3版(转)

    http://www.cnblogs.com/txw1958/p/wxpayv3-jsapi.html 本文介绍微信支付下的jsapi实现流程 前言 微信支付现在分为v2版和v3版,2014年9月10 ...

  9. 在Web应用中接入微信支付的流程之极简清晰版 (转)

    在Web应用中接入微信支付的流程之极简清晰版 背景: 在Web应用中接入微信支付,我以为只是调用几个API稍作调试即可. 没想到微信的API和官方文档里隐坑无数,致我抱着怀疑人生的心情悲愤踩遍了丫们布 ...

随机推荐

  1. MT【260】单调函数

    设$f(x)$是定义在$(0,+\infty)$上的单调函数,且对定义域内的任意实数$x$,都有$f(f(x)-\log_2 x)=3$, 求$f(x)-f^{'}(x)=2$的解所在的区间.____ ...

  2. RequestContextHolder 很方便的获取 request

    在 Spring boot web 中我们可以通过 RequestContextHolder 很方便的获取 request. ServletRequestAttributes requestAttri ...

  3. Java 强制类型转换(类转换注意事项)

    将一个类型强制转换成另一个类型的过程被称为类型转换.例如: double x =3.14; int y = (int)x; 将表达式x的值转换成整数类型,舍弃小数部分. 有时候也可能是类的对象引用的转 ...

  4. pytest_01_安装和入门

    目录 pytest 安装与入门 1.pip install -U pytest 2.创建一个test01.py的文件 3.在该目录下执行pytest(venv) 4.执行多个,新建一个py文件 tes ...

  5. CF983A Finite or not?(数学)

    题意:给出分母,分子和进制,要求判断该数是否为有限小数. Solution 表示并不知道怎么判断. 度娘:“一个分数在最简分数的情况下,如果它的分母只含有2和5两个质因数,这个分数就能化成有限小数.” ...

  6. RSA签名验证

    /// <summary> /// 验证签名 /// </summary> /// <param name="content">待签名字符串&l ...

  7. XTest

    腾讯优测是一个移动云测试平台,为应用.游戏.H5混合应用的研发团队提供产品质量检测与问题解决服务. 这是腾讯内部针对微信内的H5,做了一套专门的UI自动化框架.而且都是用真机来跑这些框架,在真机上模拟 ...

  8. bcftools将vcf生成bgzip和index格式

    利用bcftools软件将vcf格式生成gz格式和index格式,需要用到“-Oz”和“index”命令,具体如下: /bcftools-1.8/bin/bcftools view ExAC.vcf ...

  9. 实现迁徙学习-《Tensorflow 实战Google深度学习框架》代码详解

    为了实现迁徙学习,首先是数据集的下载 #利用curl下载数据集 curl -o flower_photos.tgz http://download.tensorflow.org/example_ima ...

  10. var foo = function bar() {}