基于微信我的收款码的支付接口的实现与源码

前言
若是咱们但愿为本身的网站增添微信扫码收款功能,用于收取一些服务费用,为我的网站提供自动化有偿服务的话,那咱们有哪些方案呢?

​首先,咱们先看下效果,如下是服务端的收款二维码的发起示例演示:html

其次,咱们再看看手机端 微信扫码支付的演示:前端

咱们手机端会将收款的消息推送到服务器API。其中接口信息定义大概以下:java

{"title":"微信支付","time":"2020-05-08 23:34:11","money":"0.80","deviceid":"mydevice","content":"[2条]微信支付: 微信支付收款0.80元(朋友到店)"} 

android

以上视频是让你们有个效果感观,下面咱们将详细讲解具体实现原理与细节。git

 

若是您对本专题有兴趣,能够按照下面的思路实现。程序员

同时,您也能够在 文章结尾处 查看获取源码的方法 供用于学习研究用途的 完整源码ZIPgithub

源码ZIP包括:web

1、主源码-服务端Api (基于.net core webapi,用于处理支付逻辑)sql

2、前端基于boostrap的发起二维码扫码界面UIapi

3、Android Apk 源码 (java,用于监控手机消息)

4、apk (编译完成可用的apk, 若是你不熟悉android,能够直接用这个已经编译好的apk )

 

API处理源码示例以下,

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Lyn.Pay.Api.Domain;
using Lyn.Pay.Api.Utils;
using Lyn.Pay.Api.DAL;

namespace Lyn.Pay.Api.Controllers
{
    /// <summary>
    /// 控制器
    /// </summary>
    [Route("v1/[controller]/[action]")]
    public class PayController : Controller
    {
        //https://github.com/stulzq/snowflake-net
        private static Snowflake.Core.IdWorker worker = new Snowflake.Core.IdWorker(1, 1);

        public PayController()
        {

        }

        #region 业务应用
        [HttpPost]
        [AllowAnonymous]
        public JsonResult QueryAlreadyBuy([FromBody]AddOrderVo vo)
        {
            var remoteUserIp = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            var userIp = vo.IP.HasValue() ? vo.IP : remoteUserIp;

            //检查这个IP是否已经购买过此文章了
            var alreadyBuy = Service.QueryAny("SELECT 1 FROM [ORDER]  d WHERE d.TradeProduct = @TradeProduct AND d.IP = @IP AND d.TradeStatus=1 ", new { TradeProduct = vo.ProductName, IP = userIp });
            if (alreadyBuy)
            {
                return Json(Result.Fail(ResultCode.AlreadyBuy));
            }
            else
            {
                return Json(Result.Fail(ResultCode.Fail));
            }
        }

        /// <summary>
        /// 产生新支付订单
        /// </summary>
        /// <param name="vo">订单</param>
        /// <returns>列表数据</returns>
        [HttpPost]
        [AllowAnonymous]
        public JsonResult AddOrder([FromBody]AddOrderVo vo)
        {
            var remoteUserIp = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            var userIp = vo.IP.HasValue() ? vo.IP : remoteUserIp;

            //检查这个IP是否已经购买过此文章了
            var alreadyBuy = Service.QueryAny("SELECT 1 FROM [ORDER]  d WHERE d.TradeProduct = @TradeProduct AND d.IP = @IP AND d.TradeStatus=1 ", new { TradeProduct = vo.ProductName, IP = userIp });
            if (alreadyBuy)
            {
                return Json(Result.Fail(ResultCode.AlreadyBuy));
            }

            var money = 0;
            var sqlGetValidMoney = @"
                                    SELECT  TOP 1 * FROM Product p WHERE (p.[NAME]=@ProductName  OR p.[NAME]='Gobal') AND  NOT EXISTS(
                                        SELECT 1 FROM [ORDER] d WHERE (d.TradeProduct = p.[NAME] OR p.[NAME]='Gobal') AND d.TradeMoney = p.Money AND d.TradeStatus=0
                                    )  ORDER BY p.IsGobal ASC , p.Money ASC
                                    ";
            var r = new Order();
            //先将过时的更新为过时状态
            Service.Execute("UPDATE [ORDER] SET TradeStatus=3,ModifyTime=GETDATE() WHERE TradeStatus=0 AND datediff(ss,CreateTime,GETDATE())>120", null);

            var p = Service.QuerySingle<Product>(sqlGetValidMoney, new { ProductName = vo.ProductName });
            if (p != null)
            {

                r.Id = worker.NextId();
                long.TryParse(r.Id.ToString().Substring(1), out long shortid);
                r.Id = shortid;

                r.TradeNo = r.Id.ToString();// vo.TradeNo;
                r.TradeProduct = vo.ProductName;
                r.TradeMoney = p.Money;
                r.TradeStatus = 0;
                r.Remark = remoteUserIp;
                r.IP = userIp;
                r.City = vo.City;
                r.CreateTime = DateTime.Now;
                Service.Execute("INSERT INTO [ORDER](Id,TradeNo,TradeProduct,TradeMoney,Remark,IP,City,TradeStatus,CreateTime)VALUES(@Id,@TradeNo,@TradeProduct,@TradeMoney,@Remark,@IP,@City,@TradeStatus,@CreateTime)"
                    , new { Id = r.Id, TradeNo = r.TradeNo, TradeProduct = r.TradeProduct, TradeMoney = r.TradeMoney, Remark = r.Remark, IP = r.IP, City = r.City, TradeStatus = r.TradeStatus, CreateTime = r.CreateTime });
                money = p.Money;
            }

            if (money > 0)
            {
                return Json(Result.Success(new { TradeNo = r.Id, Money = money , MoneyYuan = money/100.0, PayQRCode = $"/PayQRCode/{money}.jpg" }));
            }
            else
            {
                return Json(Result.Fail(ResultCode.Fail));
            }
        }

        /// <summary>
        /// 产生新支付订单
        /// </summary>
        /// <param name="vo">订单</param>
        /// <returns>列表数据</returns>
        [HttpPost]
        [AllowAnonymous]
        public JsonResult DiscardOrder([FromBody]DiscardOrderVo vo)
        {
            //先将过时的更新为过时状态
            Service.Execute("UPDATE [ORDER] SET TradeStatus=3,ModifyTime=GETDATE() WHERE TradeStatus=0 AND datediff(ss,CreateTime,GETDATE())>120", null);

            var d = Service.QuerySingle<Order>("SELECT * FROM [ORDER] WHERE TradeNo = @TradeNo", new { TradeNo = vo.TradeNo });
            if (d != null && d.TradeStatus == 0)
            {
                Service.Execute("UPDATE [ORDER] SET TradeStatus=2,ModifyTime=GETDATE() WHERE TradeStatus=0 AND  TradeNo = @TradeNo", new { TradeNo = vo.TradeNo });
                return Json(Result.Success());
            }
            return Json(Result.Fail());
        }

        /// <summary>
        /// 查询订单
        /// </summary>
        /// <param name="vo">订单</param>
        /// <returns>列表数据</returns>
        [HttpPost]
        [AllowAnonymous]
        public JsonResult QueryOrder([FromBody]DiscardOrderVo vo)
        {
            var d = Service.QuerySingle<Order>("SELECT * FROM [ORDER] WHERE TradeNo = @TradeNo", new { TradeNo = vo.TradeNo });
            if (d != null && d.TradeStatus == 1)
            {
                return Json(Result.Success());
            }
            return Json(Result.Fail());
        }


        [HttpPost]
        [AllowAnonymous]
        public JsonResult PayNotify([FromBody]PayNotifyVo vo)
        {
            if (vo.title.IndexOf("微信支付")>=0 && vo.money.HasValue())
            {
                //{"title":"微信支付","time":"2019-06-19 21:45:23","money":"0.10","encrypt":"0","deviceid":"ffffffff-c818-83fb-ffff-ffffbbd87511","content":"微信支付收款0.10元(朋友到店)"}
                var moneyFen = Convert.ToInt32(decimal.Parse(vo.money) * 100);
                Service.Execute("UPDATE [ORDER] SET TradeStatus=1,ModifyTime=GETDATE() WHERE TradeStatus=0 AND  TradeMoney = @TradeMoney", new { TradeMoney = moneyFen });
            }
            if (vo.title.IndexOf("微信收款助手")>=0)
            {
                //{ "title":"微信收款助手","time":"2019-06-20 22:24:54","money":"null","deviceid":"ffffffff-c818-83fb-ffff-ffffbbd87511","content":"[店员消息]收款到帐0.01元"}
                var content = vo.content;
                var money = content.Substring(content.IndexOf("收款到帐"), content.IndexOf("元") - content.IndexOf("收款到帐")).Replace("收款到帐", "");

                var moneyFen = Convert.ToInt32(decimal.Parse(money) * 100);
                Service.Execute("UPDATE [ORDER] SET TradeStatus=1,ModifyTime=GETDATE() WHERE TradeStatus=0 AND  TradeMoney = @TradeMoney", new { TradeMoney = moneyFen });
            }

            return Json(Result.Success());
        }

        #endregion
    }
}

 

下图是支付回调的发起与结果的接收示例:

细节原理请仔细往下看.....

 

做为一名程序员,咱们或多或少都但愿创建本身的我的技术网站、技术博客等等,用于记录本身的汗水点滴。

同时,若是咱们但愿为本身的网站增添微信扫码收款功能,用于收取一些服务费用,为我的网站提供自动化有偿服务的话,那咱们有哪些方案呢?

 

1、注册公司,在微信公众平台申请支付权限

2、经过微信我的收款码实现我的收款接口

 

本文咱们分析第二种方法,经过微信我的收款码实现我的收款接口。

这种方法的实现成本很是低,但也只是适用于一些我的网站,小并发量的收款服务,固然了,若是你的网站有大量用户向你支付,你还不主动去申请注册公司么。

 

言归正传,哪么怎么实现收款接口呢?

首先,咱们看一个演示示例: 

可复制连接打开体验 http://letyouknow.net/serverfarm/serverfarm-tutorial3.html

此示例是技术文章内容付费示例,用户试读部分后,点击 展开阅读更多 而且扫码支付成功后,展现所有内容。

 

首先,咱们须要制做出一套专业的UI,用于展现收款码

1、当咱们点击展开阅读更多按钮后,咱们须要显示一获取二维码的示意图

 

2、根据预设的资费状况,从后台拉取对应的我的收款二维码,并设置收款码有效期,此示例默认2分钟。

3、设置超时失效机制,引导从新发起支付

 

4、预设我的收款二维码 

      咱们须要将同一个金额照不一样的收款备注或不一样的金额尾数设置多个,而后保存到服务端,由前端UI的产品拉取对应的金额的二维码图片,显示给用户

 

5、微信收款通知 回调服务器API

        咱们能够用android apk 用于监控收款通知,并实时回调咱们的服务器,修改用户订单的支付状态。

        咱们将apk安装在手机上后,当有用户扫码付款后,咱们的微信APP便收到收款通知,同时,咱们回调服务器。

 

 

此方案特性:

这种实现办法适合小额,支付频率不高的场景。好比针对 1元这个金额生成了100个有不一样收款备注信息的二维码,那么也就是说5分钟内最多只能有100我的同时支付,1分钟内20个同时支付。对于一些小网站能够知足需求。

 

此方案的核心是设计思想,另外就是咱们如何实时获取到收款通知。咱们用android apk 用于监控收款通知,并实时回调咱们的服务器,修改用户订单的支付状态。有关实时获取收款通知的实现方法,咱们后续将另起一个篇章重点介绍。

 

6、接口定义示例

{"title":"微信支付","time":"2020-05-08 23:34:11","money":"0.80","deviceid":"mydevice","content":"[2条]微信支付: 微信支付收款0.80元(朋友到店)"} 

 

7、api源码的说明

       下载源码后,用vs2017or2019打开项目,F5运行便可,
  http://localhost:54914/Demo.html

  

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Lyn.Pay.Api.Domain;
using Lyn.Pay.Api.Utils;
using Lyn.Pay.Api.DAL;

namespace Lyn.Pay.Api.Controllers
{
    /// <summary>
    /// 控制器
    /// </summary>
    [Route("v1/[controller]/[action]")]
    public class PayController : Controller
    {
        //https://github.com/stulzq/snowflake-net
        private static Snowflake.Core.IdWorker worker = new Snowflake.Core.IdWorker(1, 1);

        public PayController()
        {

        }

        #region 业务应用
        [HttpPost]
        [AllowAnonymous]
        public JsonResult QueryAlreadyBuy([FromBody]AddOrderVo vo)
        {
            var remoteUserIp = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            var userIp = vo.IP.HasValue() ? vo.IP : remoteUserIp;

            //检查这个IP是否已经购买过此文章了
            var alreadyBuy = Service.QueryAny("SELECT 1 FROM [ORDER]  d WHERE d.TradeProduct = @TradeProduct AND d.IP = @IP AND d.TradeStatus=1 ", new { TradeProduct = vo.ProductName, IP = userIp });
            if (alreadyBuy)
            {
                return Json(Result.Fail(ResultCode.AlreadyBuy));
            }
            else
            {
                return Json(Result.Fail(ResultCode.Fail));
            }
        }

        /// <summary>
        /// 产生新支付订单
        /// </summary>
        /// <param name="vo">订单</param>
        /// <returns>列表数据</returns>
        [HttpPost]
        [AllowAnonymous]
        public JsonResult AddOrder([FromBody]AddOrderVo vo)
        {
            var remoteUserIp = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            var userIp = vo.IP.HasValue() ? vo.IP : remoteUserIp;

            //检查这个IP是否已经购买过此文章了
            var alreadyBuy = Service.QueryAny("SELECT 1 FROM [ORDER]  d WHERE d.TradeProduct = @TradeProduct AND d.IP = @IP AND d.TradeStatus=1 ", new { TradeProduct = vo.ProductName, IP = userIp });
            if (alreadyBuy)
            {
                return Json(Result.Fail(ResultCode.AlreadyBuy));
            }

            var money = 0;
            var sqlGetValidMoney = @"
                                    SELECT  TOP 1 * FROM Product p WHERE (p.[NAME]=@ProductName  OR p.[NAME]='Gobal') AND  NOT EXISTS(
                                        SELECT 1 FROM [ORDER] d WHERE (d.TradeProduct = p.[NAME] OR p.[NAME]='Gobal') AND d.TradeMoney = p.Money AND d.TradeStatus=0
                                    )  ORDER BY p.IsGobal ASC , p.Money ASC
                                    ";
            var r = new Order();
            //先将过时的更新为过时状态
            Service.Execute("UPDATE [ORDER] SET TradeStatus=3,ModifyTime=GETDATE() WHERE TradeStatus=0 AND datediff(ss,CreateTime,GETDATE())>120", null);

            var p = Service.QuerySingle<Product>(sqlGetValidMoney, new { ProductName = vo.ProductName });
            if (p != null)
            {

                r.Id = worker.NextId();
                long.TryParse(r.Id.ToString().Substring(1), out long shortid);
                r.Id = shortid;

                r.TradeNo = r.Id.ToString();// vo.TradeNo;
                r.TradeProduct = vo.ProductName;
                r.TradeMoney = p.Money;
                r.TradeStatus = 0;
                r.Remark = remoteUserIp;
                r.IP = userIp;
                r.City = vo.City;
                r.CreateTime = DateTime.Now;
                Service.Execute("INSERT INTO [ORDER](Id,TradeNo,TradeProduct,TradeMoney,Remark,IP,City,TradeStatus,CreateTime)VALUES(@Id,@TradeNo,@TradeProduct,@TradeMoney,@Remark,@IP,@City,@TradeStatus,@CreateTime)"
                    , new { Id = r.Id, TradeNo = r.TradeNo, TradeProduct = r.TradeProduct, TradeMoney = r.TradeMoney, Remark = r.Remark, IP = r.IP, City = r.City, TradeStatus = r.TradeStatus, CreateTime = r.CreateTime });
                money = p.Money;
            }

            if (money > 0)
            {
                return Json(Result.Success(new { TradeNo = r.Id, Money = money , MoneyYuan = money/100.0, PayQRCode = $"/PayQRCode/{money}.jpg" }));
            }
            else
            {
                return Json(Result.Fail(ResultCode.Fail));
            }
        }

        /// <summary>
        /// 产生新支付订单
        /// </summary>
        /// <param name="vo">订单</param>
        /// <returns>列表数据</returns>
        [HttpPost]
        [AllowAnonymous]
        public JsonResult DiscardOrder([FromBody]DiscardOrderVo vo)
        {
            //先将过时的更新为过时状态
            Service.Execute("UPDATE [ORDER] SET TradeStatus=3,ModifyTime=GETDATE() WHERE TradeStatus=0 AND datediff(ss,CreateTime,GETDATE())>120", null);

            var d = Service.QuerySingle<Order>("SELECT * FROM [ORDER] WHERE TradeNo = @TradeNo", new { TradeNo = vo.TradeNo });
            if (d != null && d.TradeStatus == 0)
            {
                Service.Execute("UPDATE [ORDER] SET TradeStatus=2,ModifyTime=GETDATE() WHERE TradeStatus=0 AND  TradeNo = @TradeNo", new { TradeNo = vo.TradeNo });
                return Json(Result.Success());
            }
            return Json(Result.Fail());
        }

        /// <summary>
        /// 查询订单
        /// </summary>
        /// <param name="vo">订单</param>
        /// <returns>列表数据</returns>
        [HttpPost]
        [AllowAnonymous]
        public JsonResult QueryOrder([FromBody]DiscardOrderVo vo)
        {
            var d = Service.QuerySingle<Order>("SELECT * FROM [ORDER] WHERE TradeNo = @TradeNo", new { TradeNo = vo.TradeNo });
            if (d != null && d.TradeStatus == 1)
            {
                return Json(Result.Success());
            }
            return Json(Result.Fail());
        }


        [HttpPost]
        [AllowAnonymous]
        public JsonResult PayNotify([FromBody]PayNotifyVo vo)
        {
            if (vo.title.IndexOf("微信支付")>=0 && vo.money.HasValue())
            {
                //{"title":"微信支付","time":"2019-06-19 21:45:23","money":"0.10","encrypt":"0","deviceid":"ffffffff-c818-83fb-ffff-ffffbbd87511","content":"微信支付收款0.10元(朋友到店)"}
                var moneyFen = Convert.ToInt32(decimal.Parse(vo.money) * 100);
                Service.Execute("UPDATE [ORDER] SET TradeStatus=1,ModifyTime=GETDATE() WHERE TradeStatus=0 AND  TradeMoney = @TradeMoney", new { TradeMoney = moneyFen });
            }
            if (vo.title.IndexOf("微信收款助手")>=0)
            {
                //{ "title":"微信收款助手","time":"2019-06-20 22:24:54","money":"null","deviceid":"ffffffff-c818-83fb-ffff-ffffbbd87511","content":"[店员消息]收款到帐0.01元"}
                var content = vo.content;
                var money = content.Substring(content.IndexOf("收款到帐"), content.IndexOf("元") - content.IndexOf("收款到帐")).Replace("收款到帐", "");

                var moneyFen = Convert.ToInt32(decimal.Parse(money) * 100);
                Service.Execute("UPDATE [ORDER] SET TradeStatus=1,ModifyTime=GETDATE() WHERE TradeStatus=0 AND  TradeMoney = @TradeMoney", new { TradeMoney = moneyFen });
            }

            return Json(Result.Success());
        }

        #endregion
    }
}

  

8、源码ZIP仅供用于学习与研究用途

1、主源码-服务端Api (基于.net core webapi,用于处理支付逻辑)

2、前端基于boostrap的发起二维码扫码界面UI

3、Android Apk 源码 (java,用于监控手机消息)

4、apk (编译完成可用的apk, 若是你不熟悉android,能够直接用这个已经编译好的apk )

 

9、如何获取源码?

      扫码关注的dotNet框架学苑公众号,直接在公众号文章中付费阅读对应的文章,文章尾部有源码压缩包。 

 

相关文章
相关标签/搜索