2016-10-06 19:15:56 qq_34341290 阅读数 3259
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

微信公众平台开放“扫一扫”功能,同时开放相关接口供有权限的品牌所有者调用。接口支持创建、管理并发布品牌所有者的商品信息,品牌所有者可选择商品条码发布。微信同时提供多种事件推送,帮助品牌所有者实现精准运营、数据分析等能力。

扫一扫接口主要调用流程如下: 

 扫一扫主要流程1.png

权限获取

扫一扫功能申请只能在公众平台上完成,功能申请开通后将直接获得接口权限。权限包括:商品经营类目权限、商品条码号段权限。创建商品时只能使用拥有权限的类目。

术语含义说明

术语概念 含义
品牌所有者 也称商户、商家,是指合法拥有品牌的企业。可以申请“扫一扫”功能。
扫码 使用微信“扫一扫”扫描条码。
条码 扫一扫支持录入的条码类型为EAN13和EAN8,国内常见的EAN13条码是以69开头的13位条码,前7~9位数字标记该条码的生产企业,被称为号段;最后一位为校验位,由前面的12位位数字计算得出,码方式可参考国标GB-12094-1998。
号段 条码号段为EAN13码的前7~9位,用于确认厂商信息,保护品牌的相关权益。申请“扫一扫”权限时需提供对应资质。特别地,ENA8码的号段为其本身。
商品主页 通过微信“扫一扫”,在微信客户端内打开,由品牌商定义的商品信息页。
商品详情 通过点击“商品主页”头部区域,在跳转后的页面展示,由品牌商设置的商品详细信息。包括多组商品图片,多组文字描述。
购买区入口 位于商品主页上部,点击后集中展示品牌商设置的“建议零售价”、“微信小店”、“电商链接”以及匹配到的“电商渠道”等入口和其对应价格。
推广服务区 位于商品主页中部,提供多媒体展示、文本介绍、跳转外部链接、关注公众号、领取微信卡券等多种自定义能力。
组件区 包括在“商品主页”打开前展示的弹窗页,以及位于“商品主页”下部的区域。用于快速突出展示该主页的核心信息,如防伪信息等。
相关商品推荐 位于商品主页底部,展示由品牌商设置推荐的其他商品主页。
“商品主页”术语概念对照图:

商品主页示例.jpg

商品创建

获取商户信息

使用该接口,商户可获取账号下的类目与号段等信息。

请求示例

HTTP请求方式:GET
https://api.weixin.qq.com/scan/merchantinfo/get?access_token=TOKEN

请求参数说明

参数 是否必须 说明
access_token 公众号的全局凭据,用于接口调用。

返回示例

正确的JSON返回结果如下:

{
 "errcode": 0,
 "errmsg": "ok",
 "verified_cate_list":[
  {
   "verified_cate_id": 200531967,
   "verified_cate_name": "调味品"
  }
 ],
 "verified_firm_code_list":[8888],
 "brand_tag_list":[
  "小耿哥8",
  "testtag"
 ]
}

返回参数说明

参数 是否必须
errcode 0为调用成功,否则返回相关错误码。
errmsg ok为调用成功,否则返回错误提示。
verified_cate_id_list 商户类目列表,包含类目ID与对应的类目名称。
verified_cate_id 商户类目ID,表示该账户下可用于创建商品的类目ID。
verified_cate_name 商户类目名称,对应类目ID的名称。
verified_firm_code_list 商户号段列表,包含该账户下有资质的条码号段。
brand_tag_list 品牌标签列表,创建商品时传入,商户自定义生成的品牌标识字段。

注意:商户容易忽略verified_cate_id,导致下一步商品创建失败。

创建商品

使用该接口,商户可以创建商品信息,设置商品主页。目前,一个账号最多支持创建10万条商品信息。

请求示例

HTTP请求方式:POST
https://api.weixin.qq.com/scan/product/create?access_token=tT8VqJWVX4C-WvIG41tyelMclMZsAPFbLxbECsJvIghceqQCMB83hI5bxcInUR-amUrVsKq4bcBmF9PgooNrFA 
POST数据格式:JSON
POST数据例子:
{
 "keystandard": "ean13",
 "keystr": "6900000000000",
 "brand_info":{
  "base_info":{
   "title": "扫一扫动态主页demo",
"thumb_url":"http://mmbiz.qpic.cn/mmbiz/AhrnkhhK7rWevHib2pmq1phtply6JicADNrX6Yrvd7LzKERyic3kn3VdSsmFr5F5ibXzj9Al65yWFudmjqcWic1Qe9g/0",
   "brand_tag": "小耿哥8",
   "category_id": 0,
   "store_mgr_type": "auto",
   "store_vendorid_list":[],
   "color": "auto",
  },
  "detail_info":{
   "banner_list":[
{"link":"http://mmbiz.qpic.cn/mmbiz/AhrnkhhK7rWevHib2pmq1phtply6JicADNic0LvlkCw7s6mZpicib7ict5MhoiaL3gPrYXpibnibOpViaYJFpic12nx4bNZcQ/0"},
{"link":"http://mmbiz.qpic.cn/mmbiz/AhrnkhhK7rWevHib2pmq1phtply6JicADNbTfwJmlVXp9k1A80UCFL1a9icwdthmSLh0RuJ5iaKcZBwdXbOicktkwPQ/0"},
{"link":"http://mmbiz.qpic.cn/mmbiz/AhrnkhhK7rWevHib2pmq1phtply6JicADNW4FD74oXjEyqHicE9U3H0nTCdLHibo7rRia2TFBQ6tx2Pvic92ica8Wns4Q/0"}
   ],
   "detail_list":[
    {
     "title": "产品名称",
     "desc": "微信相框moment"
    },
    {
     "title": "设计团队",
     "desc": "微信团队"
    },
    {
     "title": "设计初衷",
     "desc": "做一个简单纯粹的电子相框"
    },
    {
     "title": "产品诉求",
     "desc": "以相框为纽带,增加子女与父母长辈的沟通,用照片通过微信传递感情交流"
    }
   ]
  },
  "action_info":{
   "action_list":[
    {
     "type": "price",
     "retail_price":"12.00"
    },
    {
     "type": "link",
     "name": "banner",
     "link": "http://mp.weixin.qq.com",
"image":"http://mmbiz.qpic.cn/mmbiz/AhrnkhhK7rWevHib2pmq1phtply6JicADNgjXTKn0j4TlfXjUOPYBDicVOmG0sdNfUOg9Lzia2g9cbjyTXmOiaB6L1g/0",
     "showtype": "banner"
    },
    {
     "type": "link",
     "name": "自定义活动1",
     "link": "http://p.url.cn/wxscan.php",
    },
    {
     "type": "link",
     "name": "自定义活动2",
     "link": "http://p.url.cn/wxscan.php",
    },
    {
     "type": "user"
    },
    {
     "type": "text",
     "text": "此处可根据品牌商需要,用于简单描述商品或活动。"
    }
   ]
  },
  "module_info":{
   "module_list":[
    {
     "type": "anti_fake",
     "native_show": "fales",
     "anti_fake_url": "weixin.qq.com"
    }
   ]
  }
 }
}

请求参数说明

POST的主要结构为brand_info,包含商品基本信息base_info、商品详情信息detail_info、推广服务信息action_info和组件信息module_info四部分

商品主页示例2.png
参数 是否必须 说明
access_token 公众号的全局凭据,用于接口调用。
keystandard 商品编码标准,暂时只支持ean13和ean8两种标准。
keystr 商品编码内容。直接填写商品条码,如“6900000000000”;注意:编码标准是ean13时,编码内容必须在商户的号段之下,否则会报错。
base_info 商品的基本信息。
detail_info 商品的详细描述信息。
action_info 商品的推广服务区信息。
module_info 商品的组件信息。

base_info部分

参数 是否必须 说明
title 商品名称,建议不超过15个字,超过部分在客户端上以省略号显示。
thumb_url 商品缩略图,推荐尺寸为180px*180px,大小不超过50k,支持jpg、png、gif、jpeg格式。
brand_tag 品牌字段,如“宝洁海飞丝”、“宝洁飘柔”。
category_id 商品类目ID,通过“获取商户信息”接口获取。
store_mgr_type 是否展示有该商品的电商渠道,识别条件是编码内容。auto为自动,由微信识别展示渠道;custom为自定义,商户可指定store_vendorid_list内的渠道出现。
store_vendorid_list 电商渠道,如果store_mgr_type为custom,则可从以下电商渠道进行选择:2为亚马逊,3为当当网,4为京东,9为一号店,11为聚美优品,19为酒仙网
color 主页头部背景色。设置“auto”或不填则自动取色;也支持传入十六进制颜色码自定义背景色。比如,“FFFFFF”代表纯白色。注意:颜色码不识别大小写,也不需要传入“#”

detail_info部分

参数 是否必须 说明
banner_list 商品详情页中可设置多张图片。
link 商品详情页顶端横幅图片,640px*320px,单张≤200k,支持jpg、png、gif、jpeg格式,最多可上传6张。
detail_list 商品详情页中可设置多组商品属性。
title 商品详情页中商品属性名称,≤6个汉字。
desc 商品详情页中商品属性内容,≤80个汉字。

action_info部分

参数 是否必须 说明
action_list 商品主页中可设置多个服务栏。
type 服务栏的类型,Media,视频播放;Text,文字介绍;Link,图片跳转;Link,普通链接;User,公众号;Card,微信卡券;Price,建议零售价;Product,微信小店;Store,电商链接;recommend,商品推荐。

类型:视频播放

参数 是否必须 说明
type 服务栏类型,视频类型的参数值为"media"。
link 对应的视频链接,仅支持在v.qq.com上传的视频内容,格式请按JSON示例拼接。
image 对应视频的封面,推荐尺寸690px*320px,大小不超过200k,支持jpg、png、gif、jpeg格式。

类型:文字介绍

参数 是否必须 示例值 说明
type text 服务栏类型。
name 商品介绍 对应文字介绍的标题。
text 此处可根据品牌商需要,用于简单描述商品或活动。 对应文字介绍的内容。

类型:图片跳转

参数 是否必须 说明
type 服务栏类型,图片跳转类型的参数值为"link"。
link 对应图片跳转后的网页链接。
image 对应跳转入口的图片链接,请参考JSON示例。
showtype 值为banner,设置图片跳转类型的服务栏时必填。

类型:普通链接

参数 是否必须 示例值 说明
type link 服务栏类型。
name 查看官网 链接入口的名称,不超过12个汉字。
link http://www.qq.com 对应跳转后的网页链接。
digest 点击查看 服务栏右侧的引导语,不超过5个汉字。

类型:公众号

参数 是否必须 示例值 说明
type user 服务栏类型。

类型:微信卡券

参数 是否必须 示例值 说明
type card 服务栏类型。
cardid pbLatjlZyVY2XCKfIDULuD_J_PKI 卡券必须为非自定义code(概念说明见微信卡券接口文档)。
digest 全场通用 服务栏右侧的引导语,不超过5个汉字。

类型:建议零售价

参数 是否必须 示例值 说明
type price 服务栏类型。
retail_price 12.00 表示商品的建议零售价,以“元”为单位。

类型:微信小店

参数 是否必须 示例值 说明
type product 服务栏类型。
name 官网商城 微信小店入口的名称。
productid pLHCTjvXB6vIqUYUn51AWsK-sKA8 对应小店商品的id,需保证有效。
digest 限时折扣 服务栏右侧的引导语,不超过5个汉字。

类型:电商链接

参数 是否必须 示例值 说明
type store 服务栏类型。
name 京东商城 电商入口的名称。
link http://m.jd.com/product/14091549.html 对应电商的链接,建议是可以直接购买该商品的页面。
sale_price 12.50 对应商品的价格,单位元。

类型:商品推荐

参数 是否必须 说明
type 服务栏类型,商品推荐的值为recommende。
recommend_type 表示商品推荐的方式,目前只支持指定,值为appointed。
recommend_list 表示指定要推荐的商品列表
keystandard 表示被推荐的商品编码格式。
keystr 表示被推荐商品的编码内容。

“商品推荐”的JSON示例:

{
 "type": "recommend",
 "recommend": {
  "recommend_type": "appointed",
  "recommend_list": [
   {
    "keystandard": "ean13",
    "keystr": "6900000000001"
   },
   {
    "keystandard": "ean13",
    "keystr": "6900873042720"
   }
  ]
 }
}

module_info部分

参数 是否必须 说明
module_list 未来可设置多个组件,目前仅支持防伪组件。
type 组件的类型,目前仅包括防伪组件anti_fake。
native_show 设置为true时,防伪结果使用微信提供的弹窗页面展示,商户仅需调用“商品管理”部分的组件消息接口回传产品真假信息。设置为false时,无防伪弹窗效果。
anti_fake_url 商户提供的防伪查询链接,当native_show设置为false时必填。

注意:

1、推广服务区action_info部分,入口数量规则如下:

1)至少设置一个推广类型;

2)文字介绍、公众号和微信卡券三种推广类型,每种类型最多只能分别设置1个;

3)普通链接、公众号、微信卡券三种类型合计最多设置3个;

4)图片跳转链接和视频播放只能二选一展示;

2、商品主页中必须存在至少一个价格信息,价格的展示渠道有四种:

1)在base_info中定义store_mgr_type和store_vendorid_list字段。如果商品在设置的电商渠道有销售,则会有售卖入口在【购买区】展示。例如:“洋河-天之蓝 480ml”在“京东商城”有销售,假设京东商城又在该商品设置的电商渠道列表中,则会有“京东商城”的售卖入口出现。

2)在微信小店(Product)类型中设置productid,购买区将出现对应商品的微信小店售卖入口。

3)在电商链接(Store)类型中设置目标地址链接(link),购买区将出现所配置的外部商城售卖入口。

4)在建议零售价(Price)类型中设置retail_price字段。如果商品没有设置前文所述的任何一种购买渠道,也会有该商品建议零售价展示。

返回示例

正确的JSON返回结果如下:

{
 "errcode": 0,
 "errmsg": "ok",
 "pid": "5g0B4A90aqc"
}

返回参数说明

参数 说明
errcode 0为调用成功,否则返回相关错误码。
errmsg ok为调用成功,否则返回错误提示。
pid 转译后的商品id,在微信系统内唯一区分一个商品。





2017-05-31 15:15:37 csdn_Info 阅读数 3695
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

微信支付文档

1、生成二维码
2、二维码回调
3、支付成功回调
4、监听是否成功
4、错误解决方案

官方上说的这里就不提了。
官方文档地址

简单理解的流程
1、开发者设置微信参数生成二维码
2、微信公众平台设置 支付回调URL (eg:http://xxx.com/wxpay/return_url.aspx
i.必须外网能够访问,并且有域名和后缀 .xxx,并且回调页面只能直接继承

System.Web.UI.Page

不能间接继承:eg: child:parent,System.Web.UI.Page

3、用户扫描二维码后,微信会请求设置的支付回调地址并传回一个XML文件流数据,其中数据包含了生成二维码时传的参数
4、在支付回调地址中获取微信传回的XML 文件流,并调用微信的 统一下单接口,设置统一下单接口需要的参数,发送给微信服务器。
i.统一下单接口为:https://api.mch.weixin.qq.com/pay/unifiedorder
5、微信服务器进行处理,生成预支付交易,并返回XML文件流,其中包含交易会话标识(prepay_id)
6、开发者获取到XML 后,将此XML 发送到微信服务器()
7、微信支付系统根据交易会话标识,发起用户端授权支付流程
8、用户在微信客户端输入密码,确认支付后,微信客户端提交支付授权
9、微信支付系统验证后扣款,完成支付交易
10、微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
11、微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况
i.异步回调地址notify_url

ASP.NET 扫码支付模式一,代码
1、生成二维码
a)使用 ThoughtWorks.QRCode 程序集

// 微信提供的类
WxPayData data = new WxPayData();
data.SetValue("appid", WxPayConfig.APPID);//公众帐号id
data.SetValue("mch_id", WxPayConfig.MCHID);//商户号
data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
data.SetValue("product_id", tempPrId.ToString());//商品ID
data.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
data.SetValue("sign", data.MakeSign());//签名
string str = ToUrlParams(data.GetValues());//转换为URL串
string url = "weixin://wxpay/bizpayurl?" + str;// url
//日志
Log.Info(this.GetType().ToString(), "Get native pay mode 1 url : " + url);
// 生成二维码
CreateQrcode(url);
**// 生成二维码函数**
private void CreateQrcode(string nr)
{
        Bitmap bt;
        string enCodeString = nr;
        QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
        qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
        qrCodeEncoder.QRCodeScale = 4;
        qrCodeEncoder.QRCodeVersion = 0;// 超出索引,修改为0
        qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
        bt = qrCodeEncoder.Encode(enCodeString);
        Random dom = new Random();
        int randomnum = dom.Next(0, 999);
        string filename = DateTime.Now.ToString("yyyymmddhhmmssfff") + randomnum;
        string path = Server.MapPath("~/Images/wxpaycode/") + filename + ".jpg";
        // 此处是在服务器上部署时出现 GDI+ XXX的错误而添加的,本地没错误。(效果嘛....呵呵。可以考虑注释掉此段代码)
        Bitmap bmp = new Bitmap(bt);
        bt.Dispose();// 
        bmp.Save(path);
        this.ImageCode.ImageUrl = "~/Images/wxpaycode/" + filename + ".jpg";
}

2、支付回调地址(用户扫码后的回调地址操作)

// 微信返回的是xml 格式的数据,eg:

<xml>
<appid><![CDATA[wx5e9360a3f46f64cd]]></appid>
<openid><![CDATA[o_pncsidC-pRRfCP4zj98h6slREw]]></openid>
<mch_id><![CDATA[1322117501]]></mch_id>
<is_subscribe><![CDATA[Y]]></is_subscribe>
<nonce_str><![CDATA[y4dGR6JxuybgUWUo]]></nonce_str>
<product_id><![CDATA[001]]></product_id>
<sign><![CDATA[89951BAE8796DE7D32E9741E42C35FB4]]></sign>
</xml>

// 2.1获取用户扫描二维码后,微信返回的信息

//接收并读取POST过来的XML文件流
StreamReader reader = new StreamReader(Request.InputStream);
String xmlData = reader.ReadToEnd();
WxPayData obj = new WxPayData();
SortedDictionary<string, object> dic = obj.FromXml(xmlData);
//此处获取产品id
int rankid = Convert.ToInt32(dic["product_id"].ToString());
Rank rankobj = new Rank();
RankEntity entity = rankobj.Select(rankid);
if (entity != null)
{
    //dic["openid"]
    //统一下单接口
    WxPayData wxdata = new WxPayData();// 微信提供的类
    wxdata.SetValue("appid", WxPayConfig.APPID);//公众帐号id
    wxdata.SetValue("mch_id", WxPayConfig.MCHID);//商户号
    wxdata.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
    wxdata.SetValue("product_id", dic["product_id"]);//商品ID
    wxdata.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
    wxdata.SetValue("body", "测试");// 商品描述
    wxdata.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//订单号
    wxdata.SetValue("total_fee", entity.Price * 100);//金额*100为真正金额,测试使用 1 为 1 分钱
    wxdata.SetValue("spbill_create_ip", ValidateHelper.GetHostAddress());//终端IP
    wxdata.SetValue("notify_url", WxPayConfig.NOTIFY_URL);//支付回调地址
    wxdata.SetValue("trade_type", "NATIVE");//交易类型(--原生扫码支付)
    wxdata.SetValue("openid", dic["openid"]);// 用户标识,当(trade_type=JSAPI)时,为必填参数
    // 附加数据(订单号,金额,rank id(级别ID)),类似于支付宝的公共回传参数
    wxdata.SetValue("attach", wxdata.GetValue("out_trade_no") + "_" + wxdata.GetValue("total_fee") + "_" + rankid);
    Log.Info(this.GetType().ToString(), "wxdata:wxdata=true");
    WxPayData returnData = WxPayApi.UnifiedOrder(wxdata);// 请求微信微信服务器统一下单接口,生成预处理订单(微信demo 类方法)
    Response.Write(returnData.ToXml());// 回发给微信
    Response.End();
}

3、支付成功异步回调(用户支付成功后的回调地址操作)

//接收并读取POST过来的XML文件流
StreamReader reader = new StreamReader(Request.InputStream);
String xmlData = reader.ReadToEnd();
WxPayData obj = new WxPayData();
SortedDictionary<string, object> dic = obj.FromXml(xmlData);
Log.Info(this.GetType().ToString(), "return_code:back=" + dic["return_code"]);//日志
Log.Info(this.GetType().ToString(), "公共回传参数:attach=" + dic["attach"]);

if (Equals(dic["return_code"].ToString(), "SUCCESS") && Equals(dic["result_code"].ToString(), "SUCCESS"))
{
    // 判断SUCCESS 后,可以修改数据信息
    string[] parmaArr = dic["attach"].ToString().Split('_');
    int uid = ValidateHelper.GetNullableInt(Session["uid"] ?? "0");
    // 支付记录
    PayRecord pr = new PayRecord();
    PayRecordEntity pre = new PayRecordEntity();
    pre.UserId = uid;
    pre.PayOrder = parmaArr[0];// 订单号
    pre.RankId = Convert.ToInt32(parmaArr[2]);
    pre.PayType = 2;// 微信
    pre.PayDate = DateTime.Now;
    pre.PayAmount = Convert.ToDecimal(parmaArr[1]);
    int res = pr.Save(pre);
    if (res > 0)
    {
        // 用户信息更改
        User user = new User();
        UserEntity ue = user.Select(uid);
        ue.RankId = ue.RankId > pre.RankId ? ue.RankId : pre.RankId;
        int ures = user.Save(ue);
        if (ures > 0)
        {
            Response.Redirect("../index.aspx");
        }
    }
}

4、二维码页面监听是否完成(根据需求)
利用 jquery 定时请求一个地址,这个地址内查询数据库的订单状态。
如果订单状态更改为成功,则二维码页面提示支付成功并跳转。

    <script type="text/javascript">
        setInterval("CheckStatus()", 3000);
        function CheckStatus() {
            $.post("../Handler/GetDataHandler.ashx", { status: $("#HiddenField1").val(), flag: 19 }, function (data) {
                if (data) {
                    var json = JSON.parse(data);
                    layer.msg(json.result, {
                        icon: 1,
                        time: 2000
                    }, function () {
                        window.location.href = json.url;
                    });
                }
            });
        }
    </script>

// 出现的错误和解决方案
1、原生支付URL参数错误
解决方案:检查生成二维码的参数,校验签名是否正确(微信提供的sign签名算法生成的签名不正确(我是测试了不正确,然后我自己写的MD5加密的sign))
微信提供的签名校验工具地址:

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=20_1

2、获取商户订单信息超时或者商户返回的httpcode非200
在用户扫码二维码后,在二维码回调页面获取微信数据的同时也需要将数据再重新回发给微信(见:2.1)

2017-06-30 01:44:24 phil_jing 阅读数 4531
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

官方文档

准备工作:已通过微信认证的公众号,域名可以不通过ICP备案
借鉴了很多大神的文章,在此先谢过了
大体过程:根据固定金额和商品的ID先生成订单,再生成二维码,客户扫一扫付款
模式二支付的流程如下图,可以说是最简单的支付方式了

原生支付模式二时序图

业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。

一、生成微信支付二维码

订单可以在订单表中新建一条数据,然后用id作为product_id

 /**
     * 扫码模式二
     *
     * @param params
     * @throws Exception
     */
    @RequestMapping("M2")
    public Map<String, Object> paytwo(HttpServletRequest request, UnifiedOrderParams params) throws Exception {
        Map<String, Object> data = new HashMap<>();
        // 商户后台系统根据用户选购的商品生成订单。
        String out_trade_no = PayHelper.createNonceStr();
        String product_id = DateUtils.getCurrentTime();// 根据自己的逻辑生成
        // int total_fee = 1; // 1分作测试
        // String attach = "支付测试";
        // String body = "微信支付-支付测试";
        String nonce_str = PayHelper.createNonceStr();
        String spbill_create_ip = HttpUtil.getRemortIP(request); // 获取IP
        UnifiedOrderParams unifiedOrderParams = new UnifiedOrderParams();
        unifiedOrderParams.setAppid(wechatAccountConfig.getAppid());// 必须
        unifiedOrderParams.setMch_id(PayConstant.MCH_ID);// 必须
        unifiedOrderParams.setOut_trade_no(out_trade_no);
        unifiedOrderParams.setBody(params.getBody());
        unifiedOrderParams.setAttach(params.getAttach());
        unifiedOrderParams.setProduct_id(product_id);// 必须
        unifiedOrderParams.setTotal_fee(params.getTotal_fee());// 必须
        unifiedOrderParams.setNonce_str(nonce_str); // 必须
        unifiedOrderParams.setSpbill_create_ip(spbill_create_ip); // 必须
        unifiedOrderParams.setTrade_type("NATIVE");// 必须
        unifiedOrderParams.setNotify_url(wechatPayConfig.getNotifyUrl()); // 异步通知URL
        // 统一下单 请求的Xml(除detail外不需要<![CDATA[product_001]]>格式)
        String unifiedXmL = PayHelper.toPayXml(unifiedOrderParams); // 签名并入util
        // log.debug("统一下单 请求的Xml"+unifiedXmL);
        // 统一下单 返回的xml(<![CDATA[product_001]]>格式)
        String unifiedResultXmL = HttpUtil.doPost(
                wechatPayConfig.getUnifiedOrderUrl(), null, unifiedXmL);
        // log.debug("统一下单 返回的xml("+unifiedResultXmL);
        // 统一下单返回 验证签名
        if (SignatureUtil.checkValidPaySign(unifiedResultXmL, null)) {
            UnifiedOrderResult unifiedOrderResult = XmlUtil.fromXml(unifiedResultXmL,
                    UnifiedOrderResult.class);
            if (Objects.equals("SUCCESS", unifiedOrderResult.getReturn_code())
                    && Objects.equals("SUCCESS", unifiedOrderResult.getResult_code())) {
                /**** 根据unifiedOrderResult.getCode_url()生成有效期为2小时的二维码 ****/


                /**** 根据product_id再次支付方法自己写 ****/
            }
        } else {
            log.debug("签名验证错误");
        }
        return data;
    }

 

二、完成支付并通知支付结果

package com.phil.wechat.pay.controller;

import com.phil.modules.result.ResultState;
import com.phil.modules.util.SignatureUtil;
import com.phil.modules.util.XmlUtil;
import com.phil.wechat.pay.model.response.PayNotifyResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.util.Objects;

/**
 * 微信支付结果通知(统一下单参数的notify_url)
 *
 * @author phil
 * @date 2017年6月27日
 */
@RestController
@RequestMapping("api/wxpay")
@Slf4j
public class WechatPayNotifyController {

    @RequestMapping("notify")
    public ResultState notice(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ResultState resultState = new ResultState();
        log.debug("开始处理支付返回的请求");
        String resXml = ""; // 反馈给微信服务器
        String notifyXml = IOUtils.toString(request.getInputStream());// 微信支付系统发送的数据(<![CDATA[product_001]]>格式)
        log.debug("微信支付系统发送的数据" + notifyXml);
        // 验证签名
        if (SignatureUtil.checkValidPaySign(notifyXml, null)) {
            PayNotifyResult notify = XmlUtil.fromXml(notifyXml, PayNotifyResult.class);
            log.debug("支付结果 {}", notify.toString());
            if (Objects.equals("SUCCESS", notify.getResult_code())) {
                resultState.setErrcode(0);// 表示成功
                resultState.setErrmsg(notify.getResult_code());
                /**** 业务逻辑 保存openid之类的 ****/
                // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                resultState.setErrcode(-1);// 支付失败
                resultState.setErrmsg(notify.getErr_code_des());
                log.debug("支付失败,错误信息:" + notify.getErr_code_des());
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA["
                        + notify.getErr_code_des() + "]]></return_msg>" + "</xml> ";
            }
        } else {
            resultState.setErrcode(-1);// 支付失败
            resultState.setErrmsg("签名验证错误");
            log.debug("签名验证错误");
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> ";
        }
        try (BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream())) {
            out.write(resXml.getBytes());out.flush();
        } catch (Exception e) {

            log.error(e.getMessage());
        }
        return resultState;
    }
}

可以说这是最简单的支付方式了

具体源码:https://github.com/philjing/my_wechat/tree/master/src/main/java/com/phil/wechat/pay

扫一扫加群

 

2017-12-27 15:11:46 yu18352566889 阅读数 1351
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

开发过3个微信公众号,但是一直没接触到扫码支付这一块

第一步:微信统一下单接口,获取到二维码的字符串,这里简称 '二维码凭证' (根据文档调试接口,注意部分参数即可)

第二步:将二维码显示到前台

    方案一:一个快捷的方式  http://qr.liantu.com/api.php?text='二维码凭证'

    方案二:C# webform 及其他语言可以看靠官方提供的Demo 官方demo

    方案三:C# MVC 

       [HttpGet]
        public ActionResult AjaxGetQrCode(string codeurl)
        {
            //初始化二维码生成工具  QRCodeEncoder 官方提供的dll,可以官方demo里寻找
            QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
            qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
            qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
            qrCodeEncoder.QRCodeVersion = 0;
            qrCodeEncoder.QRCodeScale = 4;

            //将字符串生成二维码图片
            Bitmap image = qrCodeEncoder.Encode(codeurl, Encoding.Default);

            ////保存为PNG到内存流  
            MemoryStream ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);

            //byte[] bytes = new byte[ms.Length];
            //ms.Read(bytes,0, bytes.Length);

            Graphics g = Graphics.FromImage(image);
            g.Clear(Color.White);
            g.FillRectangle(Brushes.Red, 2, 2, 65, 31);
            g.DrawString("", new Font("黑体", 15f), Brushes.Yellow, new PointF(5f, 5f));
 
            g.Dispose();
            image.Dispose();


            return File(ms.ToArray(), "image/jpeg");
        }


之前看到一些版本,是将二维码保存成图片到本地,通过路径来显示,个人不建议这样处理,可能是业务需要。





      


2018-06-20 16:01:22 m0_37388989 阅读数 88
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒
第一课:绑定域名
第二课:获取jsapi_ticket
第三课:获取timestamp,nonceStr,signature参数
第四课:页面接入微信jsapi
第五课:判断客户端是否支持指定的js接口
第六课:上传下载图片功能
第七课:获取网络状态接口
第八课:地理位置接口
第九课:显示隐藏右上角菜单
第十课:jsapi实现微信扫一扫接口功能
第十一课:跳转微信商品页接
没有更多推荐了,返回首页