微信公众号支付开发全过程 --JAVA
按照惯例,开头总得写点感想
------------------------------------------------------------------
业务流程
这个微信官网说的还是很详细的,还配了图。我还要再说一遍。
用户点击一个支付按钮-->{后台一大推处理}-->用户看到了一个输入密码的界面,包含金额等一些信息-->用户输入密码后出来一个支付成功的页面(这部分流程都是微信自己完成的,我们什么都不用做)-->返回系统自己的页面(总不能让用户一直看着一个支付完成的页面吧。花了钱,正心疼的,赶紧跳转啊~一会后悔了,申请退款怎么整。可怜的工程师还得开发退款功能)
开发流程
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xml> <appid>wxb1427ebebexxxxxx</appid> <body>XXX费用</body> <device_info>WEB</device_info> <mch_id>132186xxxx</mch_id> <nonce_str>6AED000AF86A084F9CB0264161E29DD3</nonce_str> <notify_url>https://api.hljk365.com/api/alipay/mobilePayNotify</notify_url> <openid>oo8WUt0taCqjt552htW1vw-xxxxx</openid> <out_trade_no>1</out_trade_no> <sign>各种排序+key生成的那个sign</sign> <total_fee>1</total_fee> <trade_type>JSAPI</trade_type> </xml>
<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wxb1427ebebexxxxxx]]></appid> <mch_id><![CDATA[132186xxxx]]></mch_id> <device_info><![CDATA[WEB]]></device_info> <nonce_str><![CDATA[Hh4LFHUUvtDYtNdp]]></nonce_str> <sign><![CDATA[079F8A915FD3044F4A17D75F4945E955]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx20160617155030d9e6a0e48b0533061255]]></prepay_id> <trade_type><![CDATA[JSAPI]]></trade_type> </xml>
我们需要的,就是这货
prepay_id
获取到这货之后,第一步骤已经结束了,可以去喝个茶,吃个冰棍,小庆祝一下。
2、H5调起微信支付的内置JS
nonceStr ==反正我用的跟刚才签名是同一个随机字符串。理论上不用应该也没有关系的,勤快的小伙伴可以试试
function onBridgeReady(){ WeixinJSBridge.invoke( ‘getBrandWCPayRequest‘, { "appId" : appId, //公众号名称,由商户传入 "timeStamp":timeStamp, //时间戳,自1970年以来的秒数 "nonceStr" : nonceStr, //随机串 "package" : Package, "signType" :signType, //微信签名方式: "paySign" : paySign //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { window.location.replace("index.html"); } } ); }
上述代码中的,红色部分,修改成你想去的页面即可。是不是好奇replace是什么鬼。移步这里,看一下:http://www.xuebuyuan.com/2140432.html
4,最后一部分啦。fighting
该部分有以下3小步骤
1)解析传过来的流信息,通过重新签名的方式验证流中包含的信息的正确性。就是判断这个信息到底是不是微信发的
2)return_code和result_code都是SUCCESS的话,处理商户自己的业务逻辑。就是订单的支付状态啊等一些信息。
3)告诉微信,我收到你的返回值了。不用在发了。
关于以上三点的解释。微信官方是这么说的
//支付完成后,微信会把相关支付和用户信息发送到商户设定的通知URL,
//验证签名,并回应微信。
//对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,
//微信会通过一定的策略(如30分钟共8次)定期重新发起通知,
//尽可能提高通知的成功率,但微信不保证通知最终能成功。
//商户自行增加处理流程,
//例如:更新订单状态
//例如:数据库操作
//例如:推送支付完成信息
还记得我们在第一步生成预支付id(prepay_id时的那个notify_url吗。如果不记得了,请往上翻。如果当时只是随便写了一个,那么这会需要去改一改了。)
一个能访问的到的action.同样地址需要外网能访问的到。没有试ip好不好使。开发这部分功能的时候,运维同学已经配置了测试域名。好开心啊,终于不用在纠结于一些交互配置了。
和支付宝不同,微信返回的是流。和支付宝不同,微信返回的是流。和支付宝不同,微信返回的是流。重要的事情说三遍
解析之后,得到的格式是这样子的
<xml><appid><![CDATA[wxb1427ebebeeaxxxx]]></appid> <bank_type><![CDATA[CFT]]></bank_type> <cash_fee><![CDATA[1]]></cash_fee> <device_info><![CDATA[WEB]]></device_info> <fee_type><![CDATA[CNY]]></fee_type> <is_subscribe><![CDATA[Y]]></is_subscribe> <mch_id><![CDATA[132186xxxx]]></mch_id> <nonce_str><![CDATA[07FC15C9D169EE48573EDD749D25945D]]></nonce_str> <openid><![CDATA[oo8WUt0taCqjt552htW1vw-xxxxx]]></openid> <out_trade_no><![CDATA[你的订单编号]]></out_trade_no> <result_code><![CDATA[SUCCESS]]></result_code> <return_code><![CDATA[SUCCESS]]></return_code> <sign><![CDATA[E69940B3EDC437CB5A181210D523806E]]></sign> <time_end><![CDATA[20160621134204]]></time_end> <total_fee>1</total_fee> <trade_type><![CDATA[JSAPI]]></trade_type> <transaction_id><![CDATA[400386200120160621763973xxxx]]></transaction_id> </xml>
对以上第一点和第三点做个解释。
再次吐槽一下。微信真的很喜欢用签名啊。整个过程,3遍签名。也是醉了。
1)我们看到上述微信返回的xml中含有很多字段。使用上述xml中,处sign意外的值+key,进行签名。你没有看错。包含result_code和return_code。
微信的官方对于签名有解释。
原谅我真的好久不学语文了。真的没理解这句话,是用微信回调函数中传的参数,进行重新签名。傻傻的,还在想,用第二次签名是的参数进行签名,时间戳怎么办,要不要存在数据库里面。
将获得的签名与xml中的sign对比,如果相同,证明是微信返回的通知。如果不同,你的通知地址可能被黑客破解了。要不要告诉老板呢,告诉老板了,我怎么解决呢。
2)商户逻辑处理,不解释
3)告诉微信,我收到了你的通知,不需要在发送了。
怎么告诉微信呢。我翻遍了微信的文档,也没有找到回复微信通知这个url。
经人知道,再一次的刷新了认知观。用response.
我是这么写的
response.getWriter().write(xml);
这个xml就是微信给你的那个流转化的字符串。
xml中的return_code要是SUCCESS或者FAIL
别问我怎么知道的。官方的demo里面写的
if($notify->checkSign() == FALSE){ $notify->setReturnParameter("return_code","FAIL");//返回状态码 $notify->setReturnParameter("return_msg","签名失败");//返回信息 }else{ $notify->setReturnParameter("return_code","SUCCESS");//设置返回码 } $returnXml = $notify->returnXml();
按照这个写法,返回的数据。在没有收到微信的通知。
--------------------------------------------------------------
微信公众号支付--JSAPI的开发思路和一下参数的具体解释,全部完成了。具体代码。等我从公司项目里面抽出来。在整理。
还有一个坑:我们在第一步的时候,body传的是英文,如果传中文,直接能用的赶紧感谢一下上苍,返回参数错误的,应该是正常吧。
我的对象和xml转化是用的Java的JAXBContext。很好用的赶脚。赶脚比XMLStream好用。具体写法,会在稍后的代码中,写明。
----------------------我的幽默你不懂-------------------------------------
最后一个问题:开头说了要讲一个笑话。
最近在学英语,一天和同学一起走路。旁边的建筑特别密集。此为背景。
他说,他不喜欢这边的建筑,楼与楼之间距离太密了,像集装箱一样。
然后我问,你知道集装箱的英文怎么说嘛。
朋友一脸的表情,看着我,问我,是什么。
说完,我就后悔了,我也不知道。然后我镇定自若的说,docker.
-------------------------我的幽默你不懂------------------------------------------