经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
微信公众号H5支付-JAVA版
来源:cnblogs  作者:凡无邪  时间:2018/11/1 9:43:16  对本文有异议

微信开发之微信公众号H5支付-JAVA版

  引子

  从事JAVA开发一年多了,一直都在看博客园,CSDN的博客,从很多前人哪里学习了很多,突然觉得自己也要尽一份力,写点博客自己给自己做做记录,也给要开发微信人提提醒少遇点坑。

  很多人开发微信的时候,总是在抱怨微信的开发文档很坑,里面的参数和使用方式很含糊,其实有时候自己想想,如果自己去研发API的时候,是否能够做的比微信更好呢?,大师都有一颗虔诚学徒的心,希望这篇文档能给予从事微信公众号H5支付焦头烂额的朋友,一点帮助。

  一、前言

  先给大家提提从事微信开发,需要做的一些准备条件:1、去微信公共平台和微信商户平台注册一个账号,这里需要给微信交纳300块RMB成为一个开发者拥有开发资质 ,微信公共平台网址 、微信商户平台网址 2、申请一个服务号详细流程我就不提醒了,服务号是需要企业认证的(如果没有企业资格,又想练练手的朋友可以去申请一个微信公众号测试号,进行一些简单的开发,微信测试号网址) 。3、注意看文档,切记重要的事情说三遍!!!,做操作之前仔细理解文档里面的内容,参数里面的关系,请求的格式之类的,这种错误是最难发现的,微信公共号开发文档网址 ,微信支付文档

  二、思路

 进行开发之前,先把思路理清楚了解,了解微信支付的类型,这里类型有很多,我们需要的是公众号支付,通过官网文档了解,这里需要注册一个微信商户,这个我就不解释了,按照官网的指示撸就行了,这里展示一个官网的业务流程图。

  支付业务流程图

  没有理解到的多看看流程图少吃很多亏,也可以带入自己的业务模式,来考虑怎么设计业务。

  这里我们了解到,使用微信统一下单支付接口,前提是需要用户的openid,这里又要涉及到微信的授权登录了,以后我会在微信开发的文章里面,更新微信授权的文章

 好了我们这里提到微信支付流程第一步,统一下单支付接口,这里贴上必填的参数:

字段名 变量名 示例值 类型 描述
公众账号ID appid wxd678efh567hg6787 String(32) 微信支付分配的公众账号ID(企业号corpid即为此appId)
商户号 mch_id 1230000109 String(32) 微信支付分配的商户号
随机字符串 nonce_str 5K8264ILTKCH16CQ2502SI8ZNMTM67VS String(32) 随机字符串,长度要求在32位以内。推荐随机数生成算法
签名 sign C380BEC2BFD727A4B6845133519F3AD6 String(32) 通过签名算法计算得出的签名值,详见签名生成算法
商品描述 body 腾讯充值中心-QQ会员充值 String(128) 商品简单描述,该字段请按照规范传递,具体请见参数规定
商户订单号 out_trade_no 20150806125346 String(32) 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一。详见商户订单号
标价金额 total_fee 88 Int 订单总金额,单位为分,详见支付金额
终端IP spbill_create_ip 123.12.12.123 String(16) APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP
通知地址 notify_url http://www.weixin.qq.com/wxpay/pay.php String(256) 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数
交易类型 trade_type JSAPI String(16)

JSAPI 公众号支付

NATIVE 扫码支付

APP APP支付

说明详见参数规定

 

  里面要注意:签名算法,不建议自己手写,可以用微信的支付工具类(微信官方工具类,里面有很多的函数,例如生成sign,map组装xml等实用功能,减少开发量),里面有方法可以填入参数就可以生成sign

三、场景代码 

贴上我自己的代码:

  

  1. // 统一下单URL
  2. String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  3. IWXPayConfig config = new IWXPayConfig();
  4. Map<String, String> data = new HashMap<String, String>();
  5. data.put("appid", config.getAppID());//微信支付分配的公众账号ID(企业号corpid即为此appId)
  6. data.put("mch_id", config.getMchID());//微信支付分配的商户号
  7. String str = WXPayUtil.generateNonceStr();
  8. data.put("nonce_str", str); // 通过微信工具类生成 随机字符串
  9. data.put("body", "超级商品");//商品描述
  10. data.put("out_trade_no", order.getOrderSn()); // 订单唯一编号, 不允许重复
  11. data.put("total_fee", new BigDecimal(100).multiply(order.getAmount()).setScale(0,BigDecimal.ROUND_DOWN).toString()); // 订单金额, 单位分
  12. data.put("spbill_create_ip", GetIp.getTrueIpAddr(request)); // 下单ip
  13. data.put("openid", order.getOpenId()); // 微信公众号统一标示openid
  14. data.put("notify_url", "URL这里填写,你的回调域名"); // 订单结果通知, 微信主动回调此接口
  15. data.put("trade_type", "JSAPI"); // 固定填写
  16. // 生成带有 sign 的 XML 格式字符串
  17. String xmlparam = WXPayUtil.generateSignedXml(data, config.getKey());
  18. // 发送请求
  19. String resultStr = HttpRequest.sendPost(unifiedorder_url, xmlparam);
  20. logger.info("返回消息" + resultStr);

通过post请求微信会回调一个json回调信息,如果里面return_code 回复为SUCCESS而且result_code 也为SUCCESS的话,恭喜你就成功了一半了。这个时候可以放松一下泡杯茶。

  下一步,根据官方提示,需要把返回的json回调信息的,参数取出来进行二次封装,组装进map,然后返回前端发起支付请求(这里有一个坑,页面实际的支付路径等于微信商户平台的设置支付目录的下一级,切记!!!微信错误提示不足,导致我这里卡了一下午)

这里贴上我的代码:

  1. // 时间戳
  2. String timeStamp = new Long(WXPayUtil.getCurrentTimestamp()).toString();
  3. // 创建返回值
  4. //组装二次签名
  5. Map<String, String> resultMap = new HashMap<String, String>();
  6. resultMap.put("appId", wxResultMap.get("appid"));
  7. resultMap.put("timeStamp", timeStamp);
  8. resultMap.put("nonceStr", str);
  9. resultMap.put("package", "prepay_id=" + wxResultMap.get("prepay_id"));
  10. resultMap.put("signType", "MD5");
  11. // 生成签名
  12. String paySign = WXPayUtil.generateSignature(resultMap, config.getKey());
  13. resultMap.put("paySign", paySign);
  14. return MsgJson.getmsg(false, resultMap, "签名生成成功");

注意一般出现错误的地方都是参数错误,如果前端执行报错请检查参数,是否有填写错,大小写是否有问题。

  贴上前端代码:

  1. $.ajax({
  2. type:"post",
  3. url: "/weixin/pay",
  4. dataType:"json",
  5. ontentType : "application/x-www-form-urlencoded",
  6. data:{orderId:'${orderId}'},
  7. success:function(result) {
  8. console.log(result);
  9. var data = result;
  10. //var data = JSON.parse(result);
  11. if(data.status == '200'){
  12. appId = data.data.appId;
  13. paySign = data.data.paySign;
  14. timeStamp = data.data.timeStamp;
  15. nonceStr = data.data.nonceStr;
  16. packageStr = data.data.package;
  17. signType = data.data.signType;
  18. callpay();
  19. }else{
  20. alert("统一下单失败");
  21. }
  22. }
  23. });
  24. }
  25. function onBridgeReady(){
  26. WeixinJSBridge.invoke(
  27. 'getBrandWCPayRequest', {
  28. "appId":appId, //公众号名称,由商户传入
  29. "timeStamp":timeStamp, //时间戳,自1970年以来的秒数
  30. "nonceStr":nonceStr , //随机串
  31. "package":packageStr, //预支付交易会话标识
  32. "signType":signType, //微信签名方式
  33. "paySign":paySign //微信签名
  34. },
  35. function(res){
  36. if(res.err_msg == "get_brand_wcpay_request:ok" ) {
  37. alert('支付成功');
  38. window.location.replace("/eby/index");
  39. }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
  40. alert('支付取消');
  41. }else if(res.err_msg == "get_brand_wcpay_request:fail" ){
  42. alert('支付失败');
  43. } //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
  44. }
  45. );
  46. }
  47. function callpay(){
  48. if (typeof WeixinJSBridge == "undefined"){
  49. if( document.addEventListener ){
  50. document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
  51. }else if (document.attachEvent){
  52. document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
  53. document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
  54. }
  55. }else{
  56. onBridgeReady();
  57. }

前端做完,这一步顺利调出来微信支付的弹框

 

 这里就基本大功告成了,还有差一步处理支付的回调,根据微信官方提示前端返回的支付成功是不靠谱的,需要微信异步回调来验证,一共有8次注意通知的延迟重复性,通过生成sign比对成功后才可以确保这次支付成功了,下面贴上我的处理回调代码:

 

  1. HashMap map = new HashMap();
  2. IWXPayConfig config = new IWXPayConfig();
  3. try {
  4. InputStream inStream = request.getInputStream();
  5. ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
  6. byte[] buffer = new byte[1024];
  7. int len = 0;
  8. while ((len = inStream.read(buffer)) != -1) {
  9. outSteam.write(buffer, 0, len);
  10. }
  11. outSteam.close();
  12. inStream.close();
  13. String resultStr = new String(outSteam.toByteArray(), "utf-8");
  14. Map<String, String> resultMap = WXPayUtil.xmlToMap(resultStr);//将xml转成排序之后的map
  15. logger.info("微信支付回调地址请求参数=requst:{}", resultMap.toString());
  16. String result_code = resultMap.get("result_code");//业务结果
  17. String is_subscribe = resultMap.get("is_subscribe");//是否关注了微信公众号
  18. String out_trade_no = resultMap.get("out_trade_no");//订单号
  19. String transaction_id = resultMap.get("transaction_id");//微信支付订单号 类似于支付宝的交易号
  20. String sign = resultMap.get("sign");//签名
  21. String total_fee = resultMap.get("total_fee");//订单总金额 单位为 分
  22. String openid = resultMap.get("openid");//用户在商户appid下的唯一标识
  23. String time_end = resultMap.get("time_end");
  24. String bank_type = resultMap.get("bank_type");
  25. //签名验证
  26. resultMap.remove("sign");
  27. String signStr = WXPayUtil.generateSignature(resultMap,config.getKey());
  28. logger.warn("验证= signStr:{},sign:{}", signStr, sign);
  29. if (!signStr.equals(sign)) {
  30. logger.warn("微信支付回调地址请求参数签名验证失败= signStr:{},sign:{}", signStr, sign);
  31. map.put("return_code", "FAIL");
  32. map.put("return_msg", "sign不正确");
  33. return WXPayUtil.mapToXml(map);
  34. }
  35. if (result_code.equals("SUCCESS")) {
  36. logger.info("支付成功= 订单号:{},交易号:{}", out_trade_no, transaction_id);
  37. BigDecimal bigDecimal_total_fee = new BigDecimal(total_fee);
  38. BigDecimal bigDecimal = bigDecimal_total_fee.divide(new BigDecimal(100));
  39. // 支付成功处理业务逻辑
  40. }
  41. //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
  42. map.put("return_code","SUCCESS");
  43. map.put("return_msg","OK");

四、总结

总结的来说,微信支付坑还是不少尤其是是地址和参数,多注意一些还是可以避免的,其他的注意点在我在场景代码里面提出来了,第一次写文章如果有不好的地方,希望大家指出来,希望这篇文章能帮到大家。

文章纯手写,转载请带上作者。

  

  

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号