官方文档点击查看
准备工作:已通过微信认证的公众号,必须通过ICP备案域名(否则会报支付失败)
借鉴了很多大神的文章,在此先谢过了
整个支付流程,看懂就很好写了
详细源码,整合了H5和两种扫码方式点击查看
一、设置支付目录
在微信公众平台设置您的公众号支付支付目录,设置路径见下图。公众号支付在请求支付的时候会校验请求来源是否有在公众平台做了配置,所以必须确保支付目录已经正确的被配置,否则将验证失败,请求支付不成功。
支付授权目录就是指支付方法的请求全路径
二、设置授权域名
开发公众号支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。具体界面如下图所示:
三、授权进入支付页面
授权部分点击参考,我是用的静默授权,拿到openid就好了
授权进入支付页面方法
/** * 授权进入支付页面 * * @param request * @param response * @param url * @return * @throws Exception */ @RequestMapping(value = "prePayPage", method = { RequestMethod.GET }) public String jsPay(HttpServletRequest request, HttpServletResponse response) throws Exception { AuthAccessToken authAccessToken = null; String code = request.getParameter("code");//可用redis保存 if(code==null){ return null; } String state = request.getParameter("state"); if(state.equals(MD5Util.MD5Encode("ceshi", ""))){ AuthTokenParams authTokenParams = new AuthTokenParams(); authTokenParams.setAppid("your appid"); authTokenParams.setSecret(""your secret"); authTokenParams.setCode(code); authAccessToken = oAuthService.getAuthAccessToken(authTokenParams, ACCESS_TOKEN_URL); } if(authAccessToken!=null){ logger.info("正在支付的openid=" + authAccessToken.getOpenid()); } return "system/wxpay/testpay"; }
支付页面的的body
<script type="text/javascript"> var prepay_id ; var paySign ; var appId ; var timeStamp ; var nonceStr ; var packageStr ; var signType ; function pay(){ var url = '${ctx}/wxpay/jspay.shtml'; $.ajax({ type:"post", url:url, dataType:"json", data:{openId:'${openId}'}, success:function(data) { if(data.resultCode == 'SUCCESS'){ appId = data.appId; paySign = data.paySign; timeStamp = data.timeStamp; nonceStr = data.nonceStr; packageStr = data.packageStr; signType = data.signType; callpay(); }else{ alert("统一下单失败"); } } }); } function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":appId, //公众号名称,由商户传入 "paySign":paySign, //微信签名 "timeStamp":timeStamp, //时间戳,自1970年以来的秒数 "nonceStr":nonceStr , //随机串 "package":packageStr, //预支付交易会话标识 "signType":signType //微信签名方式 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { //window.location.replace("index.html"); alert('支付成功'); }else if(res.err_msg == "get_brand_wcpay_request:cancel"){ alert('支付取消'); }else if(res.err_msg == "get_brand_wcpay_request:fail" ){ alert('支付失败'); } //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 } ); } function callpay(){ 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(); } } </script>
四、统一下单并获取prepay_id并返回页面支付参数
统一下单的官方文档点击查看 prepay_id获取到就是成功了一半了
/** * 微信内H5调起支付 * * @param request * @param response * @param openId * @return * @throws Exception */ @ResponseBody @RequestMapping("jspay") public JsPayResult jsPay(HttpServletRequest request, HttpServletResponse response, String openId) throws Exception { JsPayResult result = null; logger.info("****正在支付的openId****" + openId); // 统一下单 String out_trade_no = PayUtil.createOutTradeNo(); int total_fee = 1; // 产品价格1分钱,用于测试 String spbill_create_ip = HttpReqUtil.getRemortIP(request); logger.info("支付IP" + spbill_create_ip); String nonce_str = PayUtil.createNonceStr(); // 随机数据 //参数组装 UnifiedOrderParams unifiedOrderParams = new UnifiedOrderParams(); unifiedOrderParams.setAppid(WeChatConfig.APP_ID);// 必须 unifiedOrderParams.setMch_id(WeChatConfig.MCH_ID);// 必须 unifiedOrderParams.setOut_trade_no(out_trade_no);// 必须 unifiedOrderParams.setBody("支付测试");// 必须 unifiedOrderParams.setTotal_fee(total_fee); // 必须 unifiedOrderParams.setNonce_str(nonce_str); // 必须 unifiedOrderParams.setSpbill_create_ip(spbill_create_ip); // 必须 unifiedOrderParams.setTrade_type("JSAPI"); // 必须 unifiedOrderParams.setOpenid(openId); unifiedOrderParams.setNotify_url(WeChatConfig.NOTIFY_URL);// 异步通知url // 统一下单 请求的Xml(正常的xml格式) String unifiedXmL = wechatPayService.abstractPayToXml(unifiedOrderParams);////签名并入service // 返回<![CDATA[SUCCESS]]>格式的XML String unifiedOrderResultXmL = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.POST_METHOD,WeChatConfig.UNIFIED_ORDER_URL, null, unifiedXmL); // 进行签名校验 if (SignatureUtil.checkIsSignValidFromWeiXin(unifiedOrderResultXmL)) { String timeStamp = PayUtil.createTimeStamp(); //统一下单响应 UnifiedOrderResult unifiedOrderResult = XmlUtil.getObjectFromXML(unifiedOrderResultXmL, UnifiedOrderResult.class); /**** 用map方式进行签名 ****/ // SortedMap<Object, Object> signMap = new TreeMap<Object, // Object>(); // signMap.put("appId", WeiXinConfig.APP_ID); // 必须 // signMap.put("timeStamp", timeStamp); // signMap.put("nonceStr", nonceStr); // signMap.put("signType", "MD5"); // signMap.put("package", "prepay_id=" + prepay_id); // String paySign = SignatureUtil.createSign(signMap, key, SystemConfig.CHARACTER_ENCODING); result = new JsPayResult(); result.setAppId(WeChatConfig.APP_ID); result.setTimeStamp(timeStamp); result.setNonceStr(unifiedOrderResult.getNonce_str());//直接用返回的 /**** prepay_id 2小时内都有效,再次支付方法自己重写 ****/ result.setPackageStr("prepay_id=" + unifiedOrderResult.getPrepay_id()); /**** 用对象进行签名 ****/ String paySign = SignatureUtil.createSign(result, WeChatConfig.API_KEY, SystemConfig.CHARACTER_ENCODING); result.setPaySign(paySign); result.setResultCode("SUCCESS"); } else { logger.info("签名验证错误"); } /**** 返回对象给页面 ****/ return result; }
五、完成支付并通知支付结果
支付通知结果官方文档点击查看
package com.phil.wechatpay.controller; import java.io.BufferedOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.phil.common.result.ResultState; import com.phil.common.util.HttpReqUtil; import com.phil.common.util.SignatureUtil; import com.phil.common.util.XmlUtil; import com.phil.wechatpay.model.resp.PayNotifyResult; /** * 微信支付结果通知(统一下单参数的notify_url) * @author phil * @date 2017年6月27日 * */ @Controller @RequestMapping("/wxpay/") public class WechatPayNotifyController { static final Logger logger = Logger.getLogger(WechatPayNotifyController.class); @ResponseBody @RequestMapping("notify") public ResultState notify(HttpServletRequest request, HttpServletResponse response) throws Exception { ResultState resultState = new ResultState(); logger.info("开始处理支付返回的请求"); String resXml = ""; // 反馈给微信服务器 String notifyXml = HttpReqUtil.inputStreamToStrFromByte(request.getInputStream());// 微信支付系统发送的数据(<![CDATA[product_001]]>格式) logger.debug("微信支付系统发送的数据"+notifyXml); // 验证签名 if (SignatureUtil.checkIsSignValidFromWeiXin(notifyXml)) { PayNotifyResult notify = XmlUtil.getObjectFromXML(notifyXml, PayNotifyResult.class); logger.debug("支付结果" + notify.toString()); if ("SUCCESS".equals(notify.getResult_code())) { resultState.setErrcode(0);// 表示成功,可以不写,int默认是0 resultState.setErrmsg(notify.getResult_code()); /**** 业务逻辑 保存openid之类的****/ // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { resultState.setErrcode(-1);// 支付失败 resultState.setErrmsg(notify.getErr_code_des()); logger.info("支付失败,错误信息:" + notify.getErr_code_des()); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[" + notify.getErr_code_des() + "]]></return_msg>" + "</xml> "; } } else { resultState.setErrcode(-1);// 支付失败 resultState.setErrmsg("签名验证错误"); logger.info("签名验证错误"); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> "; } BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); return resultState; } }
ResultState.java
package com.phil.common.result; import java.io.Serializable; /** * 微信API返回状态 * * @author phil * @date 2017年7月2日 * */ public class ResultState implements Serializable { /** * */ private static final long serialVersionUID = 1692432930341768342L; //@SerializedName("errcode") private int errcode; // 状态 //@SerializedName("errmsg") private String errmsg; //信息 public int getErrcode() { return errcode; } public void setErrcode(int errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } }
相关推荐
微信支付类-含公众号支付和刷卡支付实例微信支付类-含公众号支付和刷卡支付实例微信支付类-含公众号支付和刷卡支付实例微信支付类-含公众号支付和刷卡支付实例微信支付类-含公众号支付和刷卡支付实例微信支付类-含...
本demo 实现微信自定义菜单,自定义信息回复等功能,以及微信扫码支付,公众号支付,资源不易,欢迎反馈
java 微信公众号支付完整版 demo(自己刚做完,拿过来就能用的)
微信外浏览器h5支付,微信公众号支付,别人已经封装好的jar还不错,经过测试可以使用,需要注意的地方看我博客
基于java的srping boot实现支付宝快捷支付+wap支付+微信扫码支付+公众号支付+源码,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 基于java的srping boot实现...
微信公众号支付,所有支付所需的工具类,商品名称中文乱码处理,微信openid,js签名
微信公众号支付是基于微信公众号而开发的支付接口,在已有的公众号里可以添加 ASP 的公众号支付,微信中生成订单后,直接调出微信钱包支付,非常方便,同样支持自动更新订单状态。 H5 支付是手机浏览器使用的接口,...
最近在做微信公众号支付,看文档做的,感觉踩了不少坑,为了避免后人采坑,所以写下此demo----微信支付功能实现(微信公众号支付)
微信公众号支付Java实现Demo
微信公众平台的开发教程,用Java写的,挺有借鉴的意义
以订单推送为例,主要为大家详细介绍了java实现微信公众号发送模版消息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
微信公众平台JSSDK开发实战公众号与HTML5混合模式揭秘
ASP微信公众号支付V3版源码 1.纯ASP代码。 2.专业级仿微信UI,美观清爽。 3.可选无数据库版、Access版、MySQL版。 4.最新微信支付V3版。