微信支付,需要通过微信支付验证
目前,支付仅限服务号,
做微信支付开发,主要看开发文档
统一下单,
订单查询
退款等
1.发起支付,都是通过h5发起的,首先获取prepay_id
发起支付,需要统一下单的prepay_id
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>(); parameters.put("appid", ConfigUtil.APPID); parameters.put("mch_id", ConfigUtil.MCH_ID); parameters.put("nonce_str", PayCommonUtil.CreateNoncestr()); parameters.put("body", bodyorder); parameters.put("out_trade_no", outTradeNo);// 用户订单号 parameters.put("total_fee", totalfee);// 标价金额(分) // parameters.put("spbill_create_ip",IpAddressUtil.getIpAddr(request)); parameters.put("spbill_create_ip", "192.168.1.1");// 电脑测试 // parameters.put("spbill_create_ip",NetworkUtil.getIpAddress(request)); parameters.put("notify_url", ConfigUtil.NOTIFY_URL); parameters.put("trade_type", "JSAPI"); parameters.put("openid", openId); String sign = PayCommonUtil.createSign("UTF-8", parameters); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String result = CommonUtil.httpsRequestR2s(ConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML); System.out.println("第一弹数据" + result + "ip地址" + NetworkUtil.getIpAddress(request));
数据为
第一弹数据 <xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx06e68e38fcef451d]]></appid> <mch_id><![CDATA[1427607202]]></mch_id> <nonce_str><![CDATA[vOK9ll6ZylQAOiRV]]></nonce_str> <sign><![CDATA[4D7F2D8D55377493503F8BB9E2F94C8B]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx20170105120958d7d94506790707606719]]></prepay_id> <trade_type><![CDATA[JSAPI]]></trade_type> </xml>
2.拿到prepay_id后,就可以发起支付
支付,需要设置测试路径和真实路径,
发起支付,将参数转为json,在放到respond里,然后h5页面从request里取
SortedMap<Object, Object> params = new TreeMap<Object, Object>(); params.put("appId", ConfigUtil.APPID); params.put("timeStamp", Long.toString(new Date().getTime())); params.put("nonceStr", PayCommonUtil.CreateNoncestr()); System.out.println("订单id" + map.get("prepay_id")); params.put("package", "prepay_id=" + map.get("prepay_id")); params.put("signType", ConfigUtil.SIGN_TYPE); String paySign = PayCommonUtil.createSign("UTF-8", params); // params.put("packageValue", "prepay_id="+map.get("prepay_id")); // //这里用packageValue是预防package是关键字在js获取值出错 params.put("paySign", paySign); // paySign的生成规则和Sign的生成规则一致 String json = JSONObject.fromObject(params).toString(); System.out.println("第二弹数据" + json); try { response.setContentType("text/html" + ";charset=UTF-8"); response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.getWriter().write(json); response.getWriter().flush(); } catch (IOException e) { e.printStackTrace(); } }
上传,支付的html页面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>微信支付</title> </head> <body> <!-- <form action="weiChatPayServlet" method="post" > <input type="button" value="确认支付" name="ajaxLoadId" id="test1"/> </form> --> <div> <p> 苏牌皮草</p> <p> 库存18件</p> <p> 原价:8888元</p> <p> 现价:5000</p> <p> <button id="test"> 我要购买</button></p> </div> <script src="js/jquery.min.js"></script> <script src="js/jweixin-1.0.0.js"></script> <script src="js/bootstrap.min.js"></script> <script type="text/javascript"> function checkWeiXinVersion(){ var wechatInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i) ; if( !wechatInfo ) { alert("本活动仅支持微信") ; } else if ( wechatInfo[1] < "5.0" ) { alert("本活动仅支持微信5.0以上版本") ; } } function onBridgeReady(obj){ WeixinJSBridge.invoke('getBrandWCPayRequest',{ "appId":obj.appId, //公众号名称,由商户传入 "timeStamp":obj.timeStamp, //时间戳,自 1970 年以来的秒数 "nonceStr":obj.nonceStr, //随机串 "package" : obj.package, //<span style="font-family:微软雅黑;">商品包信息</span> "signType" : obj.signType, //微信签名方式: "paySign" : obj.paySign //微信签名 },function(res){ alert(res.err_msg); if(res.err_msg == "get_brand_wcpay_request:ok" ) { window.location.href="http://weixin.xiaowanban.com/WXZ/weichatPay.html"; alert("f成功"); }else{ alert("fail"); window.location.href="http://weixin.xiaowanban.com/WXZ/signup.html"; //<span style="font-family:微软雅黑;">当失败后,继续跳转该支付页面让用户可以继续付款,贴别注意不能直接调转jsp,</span><span style="font-size:10.5pt">不然会报</span><span style="font-size:12.0pt"> system:access_denied。</span> } }); } var basePath ="weiChatPayServlet"; $("#test").one("click",function(){ $.ajax({ type:"POST", url:basePath //<span style="font-family:微软雅黑;">ajax调用微信统一接口获取prepayId</span> }).done(function(data){ alert("数据"+data); console.log("数据为"+data); var obj = eval('(' + data + ')'); //var obj =eval("("+data+")");//转换为json对象 /* if(parseInt(obj.agent)<5){ alert("您的微信版本低于5.0无法使用微信支付"); return; } */ /* //配置微信 wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: obj.appId, // 必填,公众号的唯一标识 timestamp:obj.timeStamp , // 必填,生成签名的时间戳 nonceStr: obj.nonceStr, // 必填,生成签名的随机串 signature: obj.signature,// 必填,签名,见附录1 jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });*/ checkWeiXinVersion(); 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(obj); } }); }); </script> </body> </html>
支付后,可以登录商户平台查看支付状态
3.支付后要查询自己的订单
在支付时,我会默认存一下,商家生成的订单(商户订单号),一个openid下n那个订单,
商户订单号,要求唯一性,为了测试,我获取的时间戳,但是商用,最好用每秒100000次不同的订单号,自己可以搜
我拿到自己的数据库的商户号后,就去掉订单查询
private String checkOrder(String outTradeNo){ SortedMap<Object,Object> parameters = new TreeMap<Object,Object>(); parameters.put("appid", ConfigUtil.APPID); parameters.put("mch_id", ConfigUtil.MCH_ID); parameters.put("nonce_str", PayCommonUtil.CreateNoncestr()); parameters.put("out_trade_no", outTradeNo);//用户订单号 parameters.put("sign_type", ConfigUtil.SIGN_TYPE); String sign = PayCommonUtil.createSign("UTF-8", parameters); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String result=null ; Map<String, String> map = null; result =CommonUtil.httpsRequestR2s(ConfigUtil.CHECK_ORDER_URL, "POST", requestXML); try { map = XMLUtil.doXMLParse(result); } catch (JDOMException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (map!=null) { String returnCode= map.get("return_code"); String resultCode= map.get("result_code"); if (returnCode.equals("SUCCESS")&&resultCode.equals("SUCCESS")){ // System.out.println("returnCode结果为"+returnCode+"resultCode结果"+resultCode); // System.out.println("支付状态"+map.get("trade_state")); return map.get("trade_state"); }else { return "noArrivePay";//为发起支付,没有到输入密码处直接退出 } }else{ return null; } }
直要查到为支付成功,就修改数据库,支付状态
4.微信支付退款,直接看pai,涉及到证书的
测试退款时,也可以自己登陆商户平台退款;
退款的servlet主要代码
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>(); parameters.put("appid", ConfigUtil.APPID); parameters.put("mch_id", ConfigUtil.MCH_ID); parameters.put("nonce_str", PayCommonUtil.CreateNoncestr()); parameters.put("out_trade_no", outTradeNo);// 用户订单号 parameters.put("out_refund_no", outRefundno);// 商户退款单号 parameters.put("total_fee", totalFee);// 订单金额 parameters.put("refund_fee", refundFee);// 退款金额 parameters.put("op_user_id", ConfigUtil.MCH_ID);// 操作员id parameters.put("sign_type", ConfigUtil.SIGN_TYPE); String sign = PayCommonUtil.createSign("UTF-8", parameters); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String result = null; Map<String, String> map = null; result = CommonUtil.httpsRequestR2s(ConfigUtil.REFUND_URL, "POST", requestXML); try { map = XMLUtil.doXMLParse(result); } catch (JDOMException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 退款微信证书相关 KeyStore keyStore = null; FileInputStream instream=null; try { keyStore = KeyStore.getInstance("PKCS12"); instream = new FileInputStream(new File("D:/10016225.p12")); keyStore.load(instream, "10016225".toCharArray()); } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (CertificateException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { instream.close(); } // Trust own CA and all self-signed certs SSLContext sslcontext=null; try { sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "10016225".toCharArray()).build(); } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnrecoverableKeyException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); try { HttpGet httpget = new HttpGet("https://api.mch.weixin.qq.com/secapi/pay/refund"); System.out.println("executing request" + httpget.getRequestLine()); CloseableHttpResponse responseSJT = httpclient.execute(httpget); try { HttpEntity entity = responseSJT.getEntity(); System.out.println("----------------------------------------"); System.out.println(responseSJT.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent())); String text; while ((text = bufferedReader.readLine()) != null) { System.out.println(text); } } EntityUtils.consume(entity); } finally { responseSJT.close(); } } finally { httpclient.close(); } }
退款成功图片
退款成功的数据
退款成功返回 executing requestPOST https://api.mch.weixin.qq.com/secapi/pay/refund HTTP/1.1 ---------------------------------------- HTTP/1.1 200 OK Response content length: 850 <xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx06e68e38fcef451d]]></appid> <mch_id><![CDATA[1427607202]]></mch_id> <nonce_str><![CDATA[tR8oByXN60Xc1C9M]]></nonce_str> <sign><![CDATA[4F9FD6304C7CF37F0DD9B194AA7C6B8A]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <transaction_id><![CDATA[4007112001201701115967786227]]></transaction_id> <out_trade_no><![CDATA[1484126688291]]></out_trade_no> <out_refund_no><![CDATA[20170113161502599000]]></out_refund_no> <refund_id><![CDATA[2007112001201701130741391621]]></refund_id> <refund_channel><![CDATA[]]></refund_channel> <refund_fee>100</refund_fee> <coupon_refund_fee>0</coupon_refund_fee> <total_fee>100</total_fee> <cash_fee>100</cash_fee> <coupon_refund_count>0</coupon_refund_count> <cash_refund_fee>100</cash_refund_fee> </xml>
5.说一下,支付的api准备配置
5.1微信支付需要验证
5.2微信支付,设置秘钥
设置秘钥时,会提醒你,是否安装证书,就是微信验证,发给你的邮件里附件里的cert
6.微信授权,获取openid,网页授权的东西,是最基本的,也要知道
网页授权,获取用户信息