java微信公众号支付
来源:互联网 发布:php查询系统源码 编辑:程序博客网 时间:2024/06/04 20:13
用最近在学习使用java开发微信公众号,在学习过程中踩了很多坑,确实费了不少劲,先来分享一下微信公众号的支付流程,已提供给朦朦胧胧的小伙伴们看看,顺便给自己整理了一下以便后续使用,这是博主第一次写博客,有毛病的地方还望指出来,谢谢!
本此开发使用的框架为springboot,开发分为三个步骤。
在开发前强烈推荐各位客官先看看开发文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
一 定 要 看!!!
一、准备阶段
具备条件:已认证微信号,且通过微信支付认证,这个可以看微信文档,会有详细的解析,这里就不再重复了。
开发前,我们先登录自己的服务号,点击微信支付——>开发配置(目前开发配置已经迁移到商户平台了)
先进入商户平台—->产品中心—->开发配置
最下面有这个支付配置框,请配置好小伙伴们想使用的支付授权目录
配置API密匙,在商户平台中账户中心—->API安全
接下来要从公众号—->基本配置,拿到微信支付中所需要使用的参数AppId、AppSecret
二、前端页面
下面是我在做支付测试时使用的测试页面,为了方便,只做了一个支付按钮并且有点奇怪,直接上代码吧!
<html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <a href="javascript:void(0);" onclick="pay();" class="button">支付</a> </body></html>
//这儿是相关的JS代码<script type="text/javascript" src="../js/jquery-1.10.2.min.js"></script> <script type="application/javascript"> var appid; var nonceStr; var myPackage = "prepay_id="; var tmp ; var sign; function pay() { $.ajax({ url: "/web/wxpay/"+1000, async: false, dataType: "json", success: function(resp) { appid=resp.appId; nonceStr=resp.nonceStr; tmp=resp.timeStamp; myPackage=myPackage+resp.pg; sign=resp.paySign; alert(appid); alert(nonceStr); alert(tmp); callpay(); } }); } function onBridgeReady() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId": appid, //公众号名称,由商户传入 "timeStamp": tmp, //时间戳,自1970年以来的秒数 "nonceStr": nonceStr, //随机串 "package": myPackage, "signType": "MD5", //微信签名方式: "paySign": sign //微信签名 }, function(res) { if (res.err_msg == "get_brand_wcpay_request:ok") { alert('支付成功'); } else if (res.err_msg == "get_brand_wcpay_request:cancel") { alert('支付过程中用户取消'); } else if (res.err_msg == "get_brand_wcpay_request:fail") { alert('支付失败'); } else { alert('未知异常'); } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 } ); } function callpay() { if (typeof WeixinJSBridge == "undefined") { alert("WeixinJSBridge"); if (document.addEventListener) { alert("addEventListener"); document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } } else { onBridgeReady(); } } </script>
页面结果:
哈哈哈,当然不是这个按钮啦,这是项目中的按钮,别介意,作用还是差不多的!!
三、后端实现
首先,需要下载微信公众平台上提供的SDK,然后将SDK打成jar包,并在pom.xml添加依赖。
这是博主使用来统一下单的类
import java.math.BigDecimal;import java.util.HashMap;import java.util.Map;import java.util.Random;import javax.servlet.http.HttpServletRequest;import org.apache.commons.codec.digest.DigestUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import com.alibaba.fastjson.JSON;import com.github.wxpay.sdk.WXPay;import com.github.wxpay.sdk.WXPayUtil;import com.zt.dao.PrintDao;import com.zt.dao.UserDao;import com.zt.domain.User;public class MyWXPay { public String strJson; public Map<String, String> resp = new HashMap<String, String>(); public Map<String, String> payMap = new HashMap<String, String>(); public String str=getOutTradeNo(); public MyWXPay(HttpServletRequest request,String openid,BigDecimal money,long useIntegral) throws Exception {// WXPayUtil wxPayUtile=new WXPayUtil(); MyConfig config = new MyConfig(); WXPay wxpay = new WXPay(config); //这里生产预支付订单签名 Map<String, String> data = new HashMap<String, String>(); String theMoney =String.valueOf(money.multiply(new BigDecimal(100)).intValue()) ;//微信支付 total_fee不能出现小数 必须转换为分以整数形式传递数据 String timeStampStr=String.valueOf(System.currentTimeMillis()); String timeStamp=timeStampStr.substring(0, 10); data.put("appid","");//填写AppId data.put("mch_id","");//填写商户号 data.put("body", "");//商品描述 data.put("out_trade_no", str);//商户订单号,博主是用随机生成的方式生成 data.put("device_info", "WEB");//设备号 data.put("fee_type", "CNY");//人名币类型 data.put("total_fee", theMoney);//支付金额 data.put("openid", openid);//支付者的openId data.put("timeStamp", timeStamp);//时间戳 data.put("spbill_create_ip", request.getRemoteAddr());//终端IP data.put("notify_url", "http://wechat.gdssn.top/web/notify");//通知地址 data.put("nonce_str", str);//随机字符串 data.put("trade_type", "JSAPI"); // 此处指定为公众号支付 //这里生成支付订单 try { resp = wxpay.unifiedOrder(data); String timeStampStr2=String.valueOf(System.currentTimeMillis()); String timeStamp2=timeStampStr2.substring(0, 10); payMap.put("appId", config.getAppID()); payMap.put("timeStamp", timeStamp2); payMap.put("nonceStr", getOutTradeNo()); payMap.put("signType", "MD5"); payMap.put("package", "prepay_id=" + resp.get("prepay_id")); String paySign = WXPayUtil.generateSignature(payMap, config.getKey()); payMap.put("pg", resp.get("prepay_id")); payMap.put("paySign", paySign); strJson = JSON.toJSONString(payMap); System.out.println("resp="+resp); System.out.println("strJson="+strJson); } catch (Exception e) { e.printStackTrace(); } } //生成随机的32位字符串,用于商户订单号,随机字符串 public static String getOutTradeNo() { String base = "abcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < 32; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } }
这是博主自己重写的配置参数的类,上面的类中的AppId、mchId等等参数是从这里获取的
import com.github.wxpay.sdk.WXPayConfig;import java.io.*;public class MyConfig implements WXPayConfig{ public String keyPath =""; public String mchId=""; public String ApiSecret=""; public String appId=""; private byte[] certData; public MyConfig() throws Exception { File file = new File(keyPath); InputStream certStream = new FileInputStream(file); this.certData = new byte[(int) file.length()]; certStream.read(this.certData); certStream.close(); } public String getAppID() { return appId; } public String getMchID() { return mchId; } public String getKey() { return ApiSecret; } public InputStream getCertStream() { ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData); return certBis; } public int getHttpConnectTimeoutMs() { return 8000; } public int getHttpReadTimeoutMs() { return 10000; }}
最后是编写微信支付的接口
String result;//返回给微信的回调数据 MyWXPayRefund myWXPayRefund; @RequestMapping("/wxpay/{money:.+}") //{money:.+} 这种写法可以接收小数点! public void WxPay(@PathVariable(name = "money", required = false)String money,HttpServletRequest request,HttpServletResponse response,ModelMap model){ String openId=request.getSession().getAttribute("openid").toString(); MyWXPay myWxPay; BigDecimal theMoneyBD=new BigDecimal(money); BigDecimal theIntegral=new BigDecimal(0); theMoneyBD=theMoneyBD.setScale(2, BigDecimal.ROUND_UNNECESSARY ); try { myWxPay = new MyWXPay(request,openId,theMoneyBD.subtract(theIntegral)); CommonUtils.writeJson(myWxPay.payMap, response); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @RequestMapping("/notify") public String notify(@RequestBody String notifyData) {// String notifyData = "...."; // 支付结果通知的xml格式数据 try{ MyConfig config = new MyConfig(); WXPay wxpay = new WXPay(config); Map<String,String> resultData=new HashMap<>(); Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); // 转换成map if (wxpay.isPayResultNotifySignatureValid(notifyMap)) { LOGGER.info("签名正确!"); // 签名正确 // 进行处理。 // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功 } else { resultData.put("return_code", "FAIL"); resultData.put("return_msg", "签名失败"); result = WXPayUtil.mapToXml(resultData); // 签名错误,如果数据里没有sign字段,也认为是签名错误 } if(notifyMap.get("result_code").equals("SUCCESS")){ myWXPayRefund=new MyWXPayRefund(notifyMap); if(myWXPayRefund.resp.get("isSuccess") != null&&myWXPayRefund.resp.get("isSuccess").equals("true")){ LOGGER.info("交易状态成功!return_code= "+notifyMap.get("result_code")); resultData.put("return_code", "SUCCESS"); resultData.put("return_msg", "OK"); result = WXPayUtil.mapToXml(resultData); return result; }else{ LOGGER.info("交易状态失败!return_code= "+notifyMap.get("result_code")); resultData.put("return_code", "fail"); resultData.put("return_msg", "交易失败"); result = WXPayUtil.mapToXml(resultData); } } if(!notifyMap.get("result_code").equals("SUCCESS")){ LOGGER.info("交易状态失败!return_code= "+notifyMap.get("result_code")); resultData.put("return_code", "fail"); resultData.put("return_msg", "参数格式校验错误"); result = WXPayUtil.mapToXml(resultData); } LOGGER.info("返回给微信后台的result= "+result); }catch(Exception e){ e.printStackTrace(); } return result; }
点击按钮结果:
到这里就结束啦,如有疑问或有不对的地方请留言,博主会进行解答与改正,谢谢!!
- Java微信公众号支付
- 微信公众号支付Java DEMO
- 微信公众号支付开发 --Java
- java开发微信公众号支付
- java微信公众号支付案例
- java微信公众号支付
- java微信公众号支付接口
- java开发微信公众号支付
- java微信公众号支付授权
- java微信公众号支付
- java微信公众号支付案例
- 微信支付-公众号支付-JSAPI调用(Java)
- 微信支付-公众号支付(java实现)
- 微信支付-公众号支付(java实现)
- Java微信支付全教程demo【公众号支付】
- 微信支付-公众号支付(java实现)
- 微信公众号支付
- 微信公众号支付
- C# Automapper使用例
- 算法:互斥集合
- 完成一个 " 打开QQ,进入QQ空间,然后退出 " 的case
- Web前端开发神器-WebStorm
- mvn入门及使用myeclipse构建maven项目
- java微信公众号支付
- 查询MySQL数据库出现中文乱码
- ios解决屏幕适配,字体适配,一个小工具就够了!
- POJ 2739 Sum of Consecutive Prime Numbers
- android组件化开发
- Android 6.0 权限
- 链表拼接
- C和指针14章 预处理器笔记
- Spring中ClassPathXmlApplicationContext和ApplicationContext 的简单使用