上篇一些需要配置和整体思路 都说清楚了 这篇直接来写代码。
你需要下载微信支付SDK(软件开发工具包) 一些工具类 搬砖时需要用到。
(1)写一个接口Controller 接收响应前端请求的
@RequestMapping("wechat/pay")
public ResultJson
//调用service层的服务
}
(2)创建一个订单 所谓的调用微信的统一下单接口。
URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
请求的参数(此处只显示必填的参数):
公众账号ID appid 微信公共号的ID(在微信公众号平台可以查看)
商户号 mch_id 商户id (在微信商户平台里可以查看)
/* 随机字符串 nonce_str 长度为32位以内。使用随机数生成算法。
这个随机字符串如何生成,这个详细说下
具体是使用UUID生成的
UUID.randomUUID().toString().replaceAll("-","").substring(0,32)。
在微信的SDK中有一个名为WXPayUtil的工具类中有专门生成的nonce_str的方法。
/*签名 sign 使用签名的生成算法计算的。 重点说一下,很多人过不去,就是这个签名错了。
第一步,设所有发送或者接收到的数据为集合M。咱们需要一个Map集合 存放咱们需要的参数。
而且需要对这个Map集合中所有非空的参数进行字典序排序 ,然后URL键值对的格式进行排序key1=value1&key2=value2…)拼接成字符串stringA。
map 中需要存放的数据:文档已经说的很清楚了(所有发送) 就是Map最少要放所有必填的一些参数
paraMap.put("appid", WXAuthUtil.APPID);
paraMap.put("body", "服务费");
paraMap.put("mch_id", WXAuthUtil.MCH_ID);//商户id
paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
paraMap.put("openid", member.getOpenid());
paraMap.put("spbill_create_ip", request.getRemoteAddr());
paraMap.put("trade_type", "JSAPI"); //交易类型(公众号支付)
paraMap.put("notify_url", HIT_DEBIT);// 此路径是微信服务器调用支付结果通知路径 异步回调
paraMap.put("out_trade_no", "15508"+System.currentTimeMillis()+(int)(Math.random() * 10000));
paraMap.put("total_fee", publicMoney); //金额
第二步:有了这个stringA字符串之后,在和key拼接得到一个新的字符串。(key 是你账户密钥:在微信商户平台-》账户设置-》API安全-》密钥设置里),然后对这个新的字符串进行MD5加密运算,再将得到加密后的字符串转换为大写。OK 此刻得到的就是sign。
具体实现 微信的SDK中有一个名为:WXPayUtil的工具类其中有个方法WXPayUtil.generateSignature(paraMap, WXAuthUtil.KEY);
此方法返回一个字符串就是sign 默认加密方式为MD5,OK,到了这一步 咱们所有的参数都有了 该调用接口了。
第三步:调用下单URL
参数为xml字符串 把上面整理出来的参数 转换成xml格式的字符串 微信SDK
String xml = WXPayUtil.GetMapToXML(paraMap);
//发送请求 SDK
xmlStr = HttpKit.post(url, xml);
// 微信把很多东西都给你写好了 只要把开发的思路整理清楚 就ok了
第三步:把返回的xml转换成map
map = WXPayUtil.xmlToMap(xmlStr);
再map中取出这个值 判断是否是SUCCESS
以下字段在return_code 和result_code都为SUCCESS的时候有返回
返回成功 在xml中 也就是转换后的map中 取出prepay_id
if ("SUCCESS".equals(map.get("return_code"))&&"SUCCESS".equals(map.get("result_code"))) {
prepay_id = map.get("prepay_id");
} else {
System.out.println("调用微信支付出错,返回状态码:"+map.get("return_code")+",返回信息:"+map.get("return_msg"));
throw new ServiceException("80017");}
//通过调用下单接口 我们拿到了最重要的一个参数 prepay_id 下来就是整理参数 返回给前端 唤起支付 了
String timeStamp = WXPayUtil.getCurrentTimestamp()+"";//获取当前时间戳(时分秒)
String nonceStr = WXPayUtil.generateNonceStr(); //随机字符串
Map
payMap.put("appId", paraMap.get("appid"));
payMap.put("timeStamp", timeStamp);
payMap.put("nonceStr", nonceStr);
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, WXAuthUtil.KEY);
payMap.put("paySign", paySign);
此paySign 与上面的sign不一样 上面的是访问统一下单接口要用的参数,此paySign要传递给前端的。
好了,现在基本已经搞了 参数都传递给前端了,现在前端都已经唤起了支付,支付页面已经出来了,输完密码后,支付成功,先调用异步支付
回调,然后当你点击完成后,会调用同步支付回调。也就是你前端js方法中写的一些东西 。那怕你写个alert()点击完成也会调用。
下节讲退款。