微信支付开发java开发_java微信开发之微信支付

**写在前面:

本人一直“奉行授人以鱼不如授人以渔”,本文主要是起一个引导的作用,注意一些很坑的地方。

微信支付,本人菜鸟花了2天时间弄出来,也算是有点成就感,所以特此做个记录

**

分割线—————————————————————————

正文开始:

先来看看微信官方流程图:

0818b9ca8b590ca3270a3433284dd417.png

总结起来就是四个步骤:

点击支付按钮

微信拉起支付,输入密码

完成支付

通知微信服务器

下面就是我做测试支付的图:

点击支付按钮(后台一大堆业务逻辑处理,后面会讲):

0818b9ca8b590ca3270a3433284dd417.png

微信拉起支付(这个调用微信自动完成的):

0818b9ca8b590ca3270a3433284dd417.png

完成支付,通知微信(这个需要我们自己完成业务逻辑,后面会讲到)

0818b9ca8b590ca3270a3433284dd417.png

流程就是这样,其实总结出来,我们需要做的就是2步:

流程图中

4:统一下单

5:调用统一下单api

6:生成下单签名

(4 5 6)可以并为一步

11:告知微信通知处理结果

先放下prepay_id,我们来说说如何获取open_id(因为没有open_id,我们也没法去获取prepay_id)

获取这个分为4步:

用户同意授权,获取code

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE

我来解释下后面附带参数的意思:

appid: 用户唯一凭证,就是微信公众号的应用id

redirect_uri: 这个就是回调url,注意这个url 会附带着 code过去,就是第一步中的code。

scope: 有两种 snsapi_base 和 snsapi_userinfo 具体请参照文档

state: 随意填写

其他参数 照写

通过code换取网页授权access_token

请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

参数说明:

appid:这个参数使用都是一样的

secret: 这个参数在位置支付基本配置中可以查看

code: 第一步获取的code

grant_type:不变

请求这个就能返回如下json

{

"access_token":"ACCESS_TOKEN",

"expires_in":7200,

"refresh_token":"REFRESH_TOKEN",

"openid":"OPENID",

"scope":"SCOPE"}

解析上述json字符就可以获取到openid了。各位客官,可以喝杯茶休息休息啦!

接着来:有了openid,开始获取prepay_id

继续文档:

查阅文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3

获取到统一下单接口:

统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder

我们把那些必须的参数一一列出来,并给大家做出解释:

appid:公众号id

mch_id: 商户号

nonce_str: 随机字符串,长度32以内

sign :签名,最坑的地方,玩微信支付不遇到这个签名错误,都不好意思说自己开发过支付

body:商品描述

out_trade_no: 商户订单号 和随机字符串一样,长度32以内。

total_fee:总价,单位 分

spbill_create_ip : 终端IP

notify_url:回调url 这个就是我们总结出来2步中11的那个步骤,通知微信的处理结果的作用。

trade_type:交易类型,我们是公众号,传 JSAPI 就好了

openid 这里注意,网页支付一定要传这个,我当时就忘记传了,一直导致签名错误。

最后把这些东西组装成xml就好了:

给大家贴代码吧:

String openid = open_id;

String appid = APP_ID;

String mch_id = MCH_ID;

String nonce_str = RandomStringGenerator.getRandomStringByLength(32);

String bodyDesc = body;

String out_trade_no = RandomStringGenerator.getRandomNumber(18);

String total_fee = totalFee;

String spbill_create_ip = spbillCreateIp;

String notify_url = notifyUrl;

String trade_type = "JSAPI";

Map map = new HashMap();

map.put("openid", openid);

map.put("appid", appid);

map.put("mch_id", mch_id);

map.put("nonce_str", nonce_str);

map.put("body", bodyDesc);

map.put("out_trade_no", out_trade_no);

map.put("total_fee", total_fee);

map.put("spbill_create_ip", spbill_create_ip);

map.put("notify_url", notify_url);

map.put("trade_type", trade_type);

public static String getSign(Map map){

ArrayList list = new ArrayList();

for(Map.Entry entry:map.entrySet()){

if(entry.getValue()!=""){

list.add(entry.getKey() + "=" + entry.getValue() + "&");

}

}

int size = list.size();

String [] arrayToSort = list.toArray(new String[size]);

Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);

StringBuilder sb = new StringBuilder();

for(int i = 0; i < size; i ++) {

sb.append(arrayToSort[i]);

}

String result = sb.toString();

result += "key=" + key;

Log.error(SignUtil.class, "getSign", result);

result = MD5.MD5Encode(result).toUpperCase();

return result;

}

注意这里用了一个key,这个key非常非常重要,key设置路径:微信商户平台(pay.weixin.qq.com)–>账户设置–>API安全–>密钥设置

这个key必须参与签名。

把上面参数封装成PrePay对象

public class XmlUtil {

public static String toXml(PrePay pay){

XStream stream = new XStream(new Xpp3Driver(new NoNameCoder()));

stream.alias("xml", pay.getClass());

return stream.toXML(pay);

}

最终得到的上传的参数是这样的:以下包含信息参数全用xxxxxx代替

xxxxxxxx

xxxxxxxx

xxxxxxxx

xxxxxxxx

xxxxxxxx

1

xxxxxxx

xxxxxxxxxxx

JSAPI

xxxxxxxxxxx

大家擦亮亮眼睛,仔细看 prepay_id 好啦!!!解析xml获取prepay_id就算完事了,各位看官又到了喝茶的时间了,请各位前去喝茶。

好啦!差不多回来,开始最重要的一步,去前台调用支付:

以下就是微信需要我们传入的参数了:

appId :这个不解释了,全局都是同一个

timeStamp: 这个时间戳自己传过来就好了

nonceStr : 这个随机字符 自己传过来好了

package : 注意注意注意 这里 prepay_id= 一定要加这个

signType : MD5

paySign :这里把上面的参数按照获取prepay_id 一样的流程去签名就好了!

function onBridgeReady(){

WeixinJSBridge.invoke(

'getBrandWCPayRequest', {

"appId":"wx2421b1c4370ec43b", //公众号名称,由商户传入

"timeStamp":"1395712654", //时间戳,自1970年以来的秒数

"nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串

"package":"prepay_id=u802345jgfjsdfgsdg888",

"signType":"MD5", //微信签名方式:

"paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名

},

function(res){

if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。

}

);

}

if (typeof WeixinJSBridge == "undefined"){

if( document.addEventListener ){

document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);

}else if (document.attachEvent){

document.attachEvent('WeixinJSBridgeReady', onBridgeReady);

document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);

}

}else{

onBridgeReady();

}

至此微信支付结束。。。

认为结束了???太年轻,微信还要我们对处理结果进行确认呢!!不然之前那个notify_url 不是很鸡肋,白传了么!!看文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7

微信返回的是流对象,我们转成map就可以了:

public static Map requestToXml(HttpServletRequest request) throws DocumentException, IOException{

SAXReader reader = new SAXReader();

Document doc = reader.read(request.getInputStream());

Element root = doc.getRootElement();

Map map = new HashMap();

List elements = root.elements();

for(Element e:elements){

map.put(e.getName(), e.getData());

}

return map;

}

这里就获取到了微信传给我们的支付包含的所有数据:我这里把他放到map里面了。

(本人做法不推荐,只是用于测试:)

public static String replyWx(HttpServletRequest request) throws DocumentException,

IOException {

Map map = XmlUtil.requestToXml(request);

String xml = "";

if (map != null

&& "SUCCESS"

.equalsIgnoreCase(map.get("return_code").toString())) {

Map replyMap = new HashMap();

replyMap.put("return_code", "SUCCESS");

replyMap.put("return_msg", "OK");

xml = XmlUtil.mapToXml(replyMap);

} else {

Map replyMap = new HashMap();

replyMap.put("return_code", "FAIL");

replyMap.put("return_msg", "签名失败");

xml = XmlUtil.mapToXml(replyMap);

}

return xml;

}

这里我只是简单的返回成功和失败,大家做的时候一定一定要根据微信推荐的做法来,我推荐一个思路吧,先把sign取出来,然后置sign为空,让剩下的参数去签名,得到的签名和sign对比,如果一致,通过,如果不一致,那么sign被篡改,返回失败。 最后把这个xml返回给wx就好了!! 至此,支付结束,谢谢大家拜读!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值