博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微信公众号H5支付遇到的那些坑
阅读量:4692 次
发布时间:2019-06-09

本文共 8418 字,大约阅读时间需要 28 分钟。

简史

官方文档说的很清楚,商户已有H5商城网站,用户通过消息或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程。

当然,最近微信支付平台也加入了纯H5支付,也就是说用户可以在微信以外的手机浏览器请求微信支付的场景唤起微信支付。

当然,今天的主角是微信公众号支付,其实也不一定非在公众号中打开,只要在微信中打开就可以使用。

实现

项目使用的springboot微服务来实现,以下都是简单的伪代码实现,具体逻辑见。

Main

其实就是一个初始化下单操作,前台业务逻辑在这就不展示了,这个就是接收前台参数的方法:

@RequestMapping("/pay")public String  pay(Product product,ModelMap map) {    logger.info("H5支付(需要公众号内支付)");    String url =  weixinPayService.weixinPayMobile(product);        return "redirect:"+url;}

  

  

产品实体Bean:

/** * 产品订单信息 * 创建者 科帮网 * 创建时间    2017年7月27日 */@Data                @NoArgsConstructor     @AllArgsConstructorpublic class Product implements Serializable {    private static final long serialVersionUID = 1L;    private String productId;// 商品ID    private String subject;//订单名称     private String body;// 商品描述    private String totalFee;// 总金额(单位是分)    private String outTradeNo;// 订单号(唯一)    private String spbillCreateIp;// 发起人IP地址    private String attach;// 附件数据主要用于商户携带订单的自定义数据    private Short payType;// 支付类型(1:支付宝 2:微信 3:银联)    private Short payWay;// 支付方式 (1:PC,平板 2:手机)    private String frontUrl;// 前台回调地址  非扫码支付使用}

  

  

由于整合了Dubbo,使用PRC的方式调用,这里定义一个service:

@Overridepublic String weixinPayMobile(Product product) {    StringBuffer url = new StringBuffer();    String totalFee = product.getTotalFee();    //redirect_uri 需要在微信支付端添加认证网址    totalFee =  CommonUtil.subZeroAndDot(totalFee);    url.append("http://open.weixin.qq.com/connect/oauth2/authorize?");    url.append("appid="+ConfigUtil.APP_ID);    url.append("&redirect_uri="+server_url+"weixinMobile/dopay?");//注意 此处 get请求 拼接相关参数 用于redirect_uri获取    url.append("outTradeNo="+product.getOutTradeNo()+"&totalFee="+totalFee);    url.append("&response_type=code&scope=snsapi_base&state=");    url.append("#wechat_redirect");    return  url.toString();}

  

 

Topay

大家有没有注意到redirect_uri参数中,我们定义了我们自己系统中的url请求,如下:

@RequestMapping(value = "dopay")    public String dopay(HttpServletRequest request, HttpServletResponse response) throws Exception {    //此处为weixinPayMobile方法中拼接的参数        String orderNo = request.getParameter("outTradeNo");        String totalFee = request.getParameter("totalFee");        //获取code 这个在微信支付调用时会自动加上这个参数无须设置        String code = request.getParameter("code");        //获取用户openID(JSAPI支付必须传openid)        String openId = MobileUtil.getOpenId(code);        String notify_url =server_url+"/weixinMobile/WXPayBack";//回调接口        String trade_type = "JSAPI";// 交易类型H5支付        SortedMap
packageParams = new TreeMap
(); ConfigUtil.commonParams(packageParams); packageParams.put("body","报告");// 商品描述 packageParams.put("out_trade_no", orderNo);// 商户订单号 packageParams.put("total_fee", totalFee);// 总金额 packageParams.put("spbill_create_ip", AddressUtils.getIpAddr(request));// 发起人IP地址 packageParams.put("notify_url", notify_url);// 回调地址 packageParams.put("trade_type", trade_type);// 交易类型 packageParams.put("openid", openId);//用户openID String sign = PayCommonUtil.createSign("UTF-8", packageParams,ConfigUtil.API_KEY); packageParams.put("sign", sign);// 签名 String requestXML = PayCommonUtil.getRequestXml(packageParams); String resXml = HttpUtil.postData(ConfigUtil.UNIFIED_ORDER_URL, requestXML); Map map = XMLUtil.doXMLParse(resXml); String returnCode = (String) map.get("return_code"); String returnMsg = (String) map.get("return_msg"); StringBuffer url = new StringBuffer(); if("SUCCESS".equals(returnCode)){ String resultCode = (String) map.get("result_code"); String errCodeDes = (String) map.get("err_code_des"); if("SUCCESS".equals(resultCode)){ //获取预支付交易会话标识 String prepay_id = (String) map.get("prepay_id"); String prepay_id2 = "prepay_id=" + prepay_id; String packages = prepay_id2; SortedMap
finalpackage = new TreeMap
(); String timestamp = DateUtil.getTimestamp(); String nonceStr = packageParams.get("nonce_str").toString(); finalpackage.put("appId", ConfigUtil.APP_ID); finalpackage.put("timeStamp", timestamp); finalpackage.put("nonceStr", nonceStr); finalpackage.put("package", packages); finalpackage.put("signType", "MD5"); //这里很重要 参数一定要正确 狗日的腾讯 参数到这里就成大写了 //可能报错信息(支付验证签名失败 get_brand_wcpay_request:fail) sign = PayCommonUtil.createSign("UTF-8", finalpackage,ConfigUtil.API_KEY); url.append("redirect:/weixinMobile/payPage?"); url.append("timeStamp="+timestamp+"&nonceStr=" + nonceStr + "&package=" + packages); url.append("&signType=MD5" + "&paySign=" + sign+"&appid="+ ConfigUtil.APP_ID); url.append("&orderNo="+orderNo+"&totalFee="+totalFee); }else{ logger.info("订单号:{}错误信息:{}",orderNo,errCodeDes); url.append("redirect:/weixinMobile/error?code=0&orderNo="+orderNo);//该订单已支付 } }else{ logger.info("订单号:{}错误信息:{}",orderNo,returnMsg); url.append("redirect:/weixinMobile/error?code=1&orderNo="+orderNo);//系统错误 } return url.toString(); }

  

  

其实,以上代码就是一个认证(获取openid)、下单的过程,最终获取相关参数再重定向到pay页面,也就是我们定义的 redirect:/weixinMobile/payPage。

//公众号H5支付主页@RequestMapping(value = "payPage")    public String pay(HttpServletRequest request, HttpServletResponse response) throws Exception {    return "weixin/pay";}

  

然后转发到pay.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";//相关参数String appId = request.getParameter("appid");String timeStamp = request.getParameter("timeStamp");String nonceStr = request.getParameter("nonceStr");String packageValue = request.getParameter("package");String paySign = request.getParameter("paySign");String orderNo = request.getParameter("orderNo");String totalFee  = request.getParameter("totalFee");%>微信支付

收款方
科帮网
商 品
充值帮币
立即支付

  

  

Notify

其实,这就是一个回调通知,用户支付成功以后,微信会通知我们后台支付状态,然后我们根据订单信息完成下一步业务逻辑。

@RequestMapping(value = "WXPayBack")    public void WXPayBack(HttpServletRequest request, HttpServletResponse response){        String resXml = "";        try {            //解析XML            Map
map = MobileUtil.parseXml(request); String return_code = map.get("return_code");//状态 String out_trade_no = map.get("out_trade_no");//订单号 if (return_code.equals("SUCCESS")) { if (out_trade_no != null) { //处理订单逻辑 logger.info("微信手机支付回调成功订单号:{}",out_trade_no); resXml = "
" + "
" + "
" + "
"; } }else{ logger.info("微信手机支付回调失败订单号:{}",out_trade_no); resXml = "
" + "
" + "
" + "
"; } } catch (Exception e) { logger.error("手机支付回调通知失败",e); resXml = "
" + "
" + "
" + "
"; } try { // ------------------------------ // 处理业务完毕 // ------------------------------ BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } }

  

其实,当你完成集成测试的那一刻,也就没啥子坑了,相关的注意事项都在代码中有体现。

详细代码见:

转载于:https://www.cnblogs.com/smallSevens/p/7406746.html

你可能感兴趣的文章
Android 动画特效
查看>>
14. 类似正则表达式的字符处理问题
查看>>
bzoj1874: [BeiJing2009 WinterCamp]取石子游戏(博弈论+SG函数入门)
查看>>
使用apache自带日志分割模块rotatelogs,分割日志
查看>>
Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————V4L2捕捉画面
查看>>
MySQL Database on Azure 支持 5.7 版本啦!
查看>>
补交进度条
查看>>
Kylin简介
查看>>
js正则表达式中=s.g表示什么意思
查看>>
caffe深度学习网络(.prototxt)在线可视化工具:Netscope Editor
查看>>
.net获取当前网址url(各种参数值)
查看>>
如何配置Log4net-Step by step
查看>>
VBA中find使用解释
查看>>
YSLOW 中文文摘
查看>>
python笔记(1)-关于我们应不应该继续学习
查看>>
python 读写XML
查看>>
假装成黑客
查看>>
python socket 实现的简单http服务器
查看>>
初学Java
查看>>
Spring框架的核心功能之AOP技术
查看>>