热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微信支付-案例代码配置

一.案例介绍这里模拟一个实际业务场景,进行介绍微信支付,业务功能包括:登录、注册、充值、查看充值记录。页面图:二.概要设计1.数据库设计这里数

一. 案例介绍

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

  

 

页面图:

        

二. 概要设计

1.数据库设计

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

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

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

  

 

2.微信支付流程

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

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

  流程1:

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

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

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

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

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

  ⑩ 这时候分两种情况

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

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

微信支付业务流程图:        

3.代码配置

(1).参数配置

(2).前端页面代码

 1    $(function () {
2 // 当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
3 document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
4 //公众号支付
5 document.getElementById("pay").Onclick= function () {
6 //1.前端验证
7 var mOney= $('#num').val();
8 if (mOney== "") {
9 alert('请将信息输入完整');
10 return;
11 }
12 mui('#pay').button('loading');
13 //2.进行下单
14 $.ajax({
15 type: 'POST',
16 url: '/WeiXinGz/GetAPI',
17 data: { "money": money },
18 cache: false,
19 dataType: 'json',
20 success: function (jsonData) {
21 if (jsonData.status == "1") {
22 //公众号支付
23 WeixinJSBridge.invoke('getBrandWCPayRequest', jsonData.payData, function (res) {
24 // 使用以下方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
25 //【因此微信团队建议:】当收到ok返回时,向商户后台询问是否收到交易成功的通知,
26 //若收到通知,前端展示交易成功的界面;
27 //若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
28 if (res.err_msg == "get_brand_wcpay_request:ok") {
29 //JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回
30 $.ajax({
31 type: 'POST',
32 url: '/WeiXinGz/QueryOrder',
33 data: {
34 orderId: jsonData.orderId
35 },
36 cache: false,
37 dataType: 'text',
38 success: function (jsonData) {
39 if (jsOnData== "ok") {
40 alert("支付成功", "提示", function () {
41 alert("页面跳转等业务处理");
42 });
43 mui('#pay').button('reset');
44 } else {
45 alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付1!");
46 mui('#pay').button('reset');
47 }
48 },
49 error: function (XMLHttpRequest, textStatus, errorThrown) {
50 alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付2!");
51 mui('#pay').button('reset');
52 }
53 });
54 } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
55 //由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
56 alert("您放弃了支付");
57 mui('#pay').button('reset');
58 } else {
59 //由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
60 alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付3!");
61 mui('#pay').button('reset');
62 }
63 });
64 } else {
65 alert(jsonData.promptInfor);
66 mui('#pay').button('reset');
67 }
68 },
69 error: function (XMLHttpRequest, textStatus, errorThrown) {
70 alert("微信订单提交失败,请稍后重试4!");
71 mui('#pay').button('reset');
72 }
73 });
74
75 }
76 }, false);
77 });

 

(3).统一下单接口

 1    /// 
2 /// 统一下单接口
3 ///

4 /// 钱数
5 ///
6 public ActionResult GetAPI(string money)
7 {
8 try
9 {
10 //一.系统本身自有的业务处理
11 //1.必要信息的初始化
12 string userId = Session["userId"].ToString(); //用户主键
13 UserInfor userInfor = db.Set().Where(a => a.id == userId).FirstOrDefault();
14 string orderId = GenerateOrderNum(); //生成订单号
15 string totalFee = money;//设置默认商品费用为【1分】
16 string nOnceStr= TenPayV3Util.GetNoncestr(); //获取 随机字符串
17 string openid = userInfor.openId;
18 //2.自己商户系统下单
19 OrderInfor orderInfor = new OrderInfor();
20 orderInfor.id = orderId;
21 orderInfor.uid = userInfor.id;
22 orderInfor.goodName = "测试商品";
23 orderInfor.goodPrice = totalFee;
24 orderInfor.addTime = DateTime.Now;
25 orderInfor.status = "0"; //已经下单,但未付款
26 db.Set().Add(orderInfor);
27 db.SaveChanges();
28
29
30 //二.微信系统下单
31 //1.创建支付应答对象并初始化
32 RequestHandler packageReqHandler = new RequestHandler(null);
33 packageReqHandler.Init();
34 //1.1设置统一下单的参数
35 packageReqHandler.SetParameter("appid", ConfigHelp.AppSettings("AppId")); //公众账号ID
36 packageReqHandler.SetParameter("mch_id", ConfigHelp.AppSettings("MchId")); //商户号
37 packageReqHandler.SetParameter("nonce_str", nonceStr); //随机字符串
38 packageReqHandler.SetParameter("body", "科技-服务"); //商品描述
39 packageReqHandler.SetParameter("out_trade_no", orderId); //商户订单号
40 packageReqHandler.SetParameter("total_fee", totalFee); //商品金额,以分为单位
41 packageReqHandler.SetParameter("spbill_create_ip", Request.UserHostAddress); //终端IP
42 packageReqHandler.SetParameter("notify_url", ConfigHelp.AppSettings("notify_url")); //微信支付异步通知回调地址
43 packageReqHandler.SetParameter("trade_type", "JSAPI"); //交易类型 代表公众号支付
44 packageReqHandler.SetParameter("openid", openid); //用户标识
45 string sign = packageReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //预支付签名
46 packageReqHandler.SetParameter("sign", sign);
47 //1.2 下单数据格式转换
48 string data = packageReqHandler.ParseXML();
49 //1.3 进行下单
50 string result = TenPayV3.Unifiedorder(data);
51 //2.对下单返回结果进行分析
52 XDocument res = XDocument.Parse(result);
53 //2.1 对返回结果进行判断
54
55 //2.2 成功的情况下获取必要的参数
56 string prepayId = res.Element("xml").Element("prepay_id").Value; //获取预支付订单编号prepayId
57 //3. 获取支付参数并签名
58 string timeStamp = TenPayV3Util.GetTimestamp(); //获取时间戳
59 //设置支付参数
60 RequestHandler paySignReqHandler = new RequestHandler(null);
61 paySignReqHandler.SetParameter("appId", ConfigHelp.AppSettings("AppId"));
62 paySignReqHandler.SetParameter("timeStamp", TenPayV3Util.GetTimestamp());
63 paySignReqHandler.SetParameter("nonceStr", nonceStr);
64 paySignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepayId));
65 paySignReqHandler.SetParameter("signType", "MD5"); //签名【MD5】
66 string paySign = paySignReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //JSAPI支付签名
67 var payData = new
68 {
69 appId = ConfigHelp.AppSettings("AppId"),
70 timeStamp = timeStamp,
71 nOnceStr= nonceStr,
72 package = string.Format("prepay_id={0}", prepayId),
73 signType = "MD5",
74 paySign = paySign,
75 };
76 return Json(new
77 {
78 status = "1",
79 promptInfor = "微信下单成功",
80 payData = payData,
81 orderId = orderId
82 });
83 }
84 catch (Exception ex)
85 {
86 string a = ex.Message;
87
88 return Json(new
89 {
90 status = "0",
91 promptInfor = a
92 });
93 }
94 }

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

 1   public ActionResult PayNotifyUrl()
2 {
3 //获取当前http请求
4 HttpContext httpCOntext= System.Web.HttpContext.Current;
5 ResponseHandler notifyDataHandler = new ResponseHandler(httpContext);
6 //返回状态码【SUCCESS/FAIL】此字段是通信标识
7 string return_code = notifyDataHandler.GetParameter("return_code");
8 //返回信息【如非空,为错误原因】
9 string return_msg = notifyDataHandler.GetParameter("return_msg");
10 //表示通信成功
11 if (return_code == "SUCCESS")
12 {
13 //获取业务结果【交易是否成功(SUCCESS/FAIL)】
14 string result_code = notifyDataHandler.GetParameter("result_code");
15 //表示业务结果成功
16 if (result_code == "SUCCESS")
17 {
18 //设置签名密钥
19 notifyDataHandler.SetKey(ConfigHelp.AppSettings("key"));
20 //验证请求是否从微信发过来(安全)【验证签名】
21 if (notifyDataHandler.IsTenpaySign())
22 {
23 //获取订单编号
24 string out_trade_no = notifyDataHandler.GetParameter("out_trade_no");
25 //检查是否返回商户订单号
26 if (!string.IsNullOrEmpty(out_trade_no))
27 {
28 try
29 {
30 OrderInfor orderInfor = db.Set().Where(a => a.id == out_trade_no).FirstOrDefault();
31 if (orderInfor != null)
32 {
33 //这里需要根据订单号更改系统的业务
34 //这里模拟测试记录订单号
35 orderInfor.status = "1"; //表示付款成功,成功回调
36 db.Entry(orderInfor).State = EntityState.Modified;
37 db.SaveChanges();
38
39 return_code = "SUCCESS";
40 return_msg = "OK";
41 }
42 else
43 {
44 return_code = "FAIL";
45 return_msg = "商户系统中不存在该订单";
46 }
47 }
48 catch (Exception ex)
49 {
50 //系统异常
51 return_code = "FAIL";
52 return_msg = ex.Message;
53 }
54 }
55 else
56 {
57 //支付结果中商户订单号不存在
58 return_code = "FAIL";
59 return_msg = "支付结果中商户订单号不存在";
60 }
61 }
62 else
63 {
64 //签名失败
65 return_code = "FAIL";
66 return_msg = "签名失败";
67 }
68 }
69 else
70 {
71 //交易失败
72 return_code = "FAIL";
73 return_msg = "交易失败";
74 }
75 }
76 //商户处理后同步返回给微信参数
77 string xml = string.Format(@"", return_code, return_msg);
78 //返回处理结果
79 return Content(xml, "text/xml");
80 }

(5).JSAPI接口请求

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

4 /// 订单编号id
5 ///
6 //[WeixinInternalRequest("无法访问!")]
7 public ActionResult QueryOrder(string orderId)
8 {
9 try
10 {
11 //一.先查商户后台的订单状态,判断微信端是否异步通知商户后台了!!!
12 OrderInfor orderInfor = db.Set().Where(a => a.id == orderId).FirstOrDefault();
13 //判断订单状态
14 if (orderInfor.status == "1")
15 {
16 //表示查询成功
17 return Content("ok");
18 }
19 else if (orderInfor == null || orderInfor.status != "1")
20 {
21 //二.进行调用下面的微信查询api进行查询
22 //生成随机字符串
23 string nOnceStr= TenPayV3Util.GetNoncestr();
24 RequestHandler packageReqHandler = new RequestHandler(null);
25 //设置package订单参数
26 packageReqHandler.SetParameter("appid", ConfigHelp.AppSettings("AppId")); //公众账号ID
27 packageReqHandler.SetParameter("mch_id", ConfigHelp.AppSettings("MchId")); //商户号
28 packageReqHandler.SetParameter("out_trade_no", orderId); //填入商家订单号
29 packageReqHandler.SetParameter("nonce_str", nonceStr); //随机字符串
30 string sign = packageReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key"));//参数进行签名
31 packageReqHandler.SetParameter("sign", sign); //参数中添加签名字符串
32 string data = packageReqHandler.ParseXML(); //将传的参数转化为XML格式字符串
33 var result = TenPayV3.OrderQuery(data); //调用订单查询接口
34 var res = XDocument.Parse(result);
35 //返回状态码【SUCCESS/FAIL】此字段是通信标识
36 string return_code = res.Element("xml").Element("return_code").Value;
37 if (return_code == "SUCCESS")
38 {
39 //获取业务结果【交易是否成功(SUCCESS/FAIL)】
40 string result_code = res.Element("xml").Element("result_code").Value;
41 if (result_code == "SUCCESS")
42 {
43 //交易状态
44 /**SUCCESS—支付成功
45 *REFUND—转入退款
46 *NOTPAY—未支付
47 *CLOSED—已关闭
48 *REVOKED—已撤销(刷卡支付)
49 *USERPAYING--用户支付中
50 *PAYERROR--支付失败(其他原因,如银行返回失败)
51 */
52 string trade_state = res.Element("xml").Element("trade_state").Value;
53 if (return_code == "SUCCESS")
54 {
55 return Content("ok");
56 }
57 }
58 }
59
60 }
61 //未查询到该订单或者该订单交易状态不相符
62 return Content("error");
63 }
64 catch (Exception ex)
65 {
66 //抛异常信息,返回异常消息
67 return Content(ex.Message);
68 }
69 }

 

上述代码中,用到的openid,可以继续阅读上一篇文章 微信公众平台-信息的获取


推荐阅读
  • 深入理解Lucene搜索机制
    本文旨在帮助读者全面掌握Lucene搜索的编写步骤、核心API及其应用。通过详细解析Lucene的基本查询和查询解析器的使用方法,结合架构图和代码示例,带领读者深入了解Lucene搜索的工作流程。 ... [详细]
  • 本文探讨了使用C#在SQL Server和Access数据库中批量插入多条数据的性能差异。通过具体代码示例,详细分析了两种数据库的执行效率,并提供了优化建议。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 本文介绍如何在 C++ 中使用链表结构存储和管理数据。通过具体示例,展示了静态链表的基本操作,包括节点的创建、链接及遍历。 ... [详细]
  • 解决FCKeditor应用主题后上传问题及优化配置
    本文介绍了在Freetextbox收费后选择FCKeditor作为替代方案时遇到的上传问题及其解决方案。通过调整配置文件和调试工具,最终解决了上传失败的问题,并对相关配置进行了优化。 ... [详细]
  • 本问题探讨了在特定条件下排列儿童队伍的方法数量。题目要求计算满足条件的队伍排列总数,并使用递推算法和大数处理技术来解决这一问题。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 如何清除Chrome浏览器地址栏的特定历史记录
    在使用Chrome浏览器时,你可能会发现地址栏保存了大量浏览记录。有时你可能希望删除某些特定的历史记录而不影响其他数据。本文将详细介绍如何单独删除地址栏中的特定记录以及批量清除所有历史记录的方法。 ... [详细]
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
  • 解决TensorFlow CPU版本安装中的依赖问题
    本文记录了在安装CPU版本的TensorFlow过程中遇到的依赖问题及解决方案,特别是numpy版本不匹配和动态链接库(DLL)错误。通过详细的步骤说明和专业建议,帮助读者顺利安装并使用TensorFlow。 ... [详细]
  • 探索新一代API文档工具,告别Swagger的繁琐
    对于后端开发者而言,编写和维护API文档既繁琐又不可或缺。本文将介绍一款全新的API文档工具,帮助团队更高效地协作,简化API文档生成流程。 ... [详细]
  • 如何将本地Docker镜像推送到阿里云容器镜像服务
    本文详细介绍将本地Docker镜像上传至阿里云容器镜像服务的步骤,包括登录、查看镜像列表、推送镜像以及确认上传结果。通过本文,您将掌握如何高效地管理Docker镜像并将其存储在阿里云的镜像仓库中。 ... [详细]
  • 查找最小值的操作是很简单的,只需要从根节点递归的遍历到左子树节点即可。当遍历到节点的左孩子为NULL时,则这个节点就是树的最小值。上面的树中,从根节点20开始,递归遍历左子 ... [详细]
  • 异常要理解Java异常处理是如何工作的,需要掌握一下三种异常类型:检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常ÿ ... [详细]
  • Appium + Java 自动化测试中处理页面空白区域点击问题
    在进行移动应用自动化测试时,有时会遇到某些页面没有返回按钮,只能通过点击空白区域返回的情况。本文将探讨如何在Appium + Java环境中有效解决此类问题,并提供详细的解决方案。 ... [详细]
author-avatar
狂浪的眼神
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有