微信扫码支付 模式一 (JSAPI)
来源:互联网 发布:linux 杀dhcp进程 编辑:程序博客网 时间:2024/05/16 07:23
这个微信支付是静态二维码支付,就是店面贴着一个二维码,让消费者自己扫自己输入金额,自己发起支付的支付方式。
要准备的东西比较麻烦:
1、到微信公众号平台设置Oauth2的网页验证域名(用于获取code,code用于拿到发起支付的openId),格式是www.xxxx.com/file1/file2/,不需要https:// 要精确到发起支付页面的当前路径
2、配置Oauth2网页验证域名的时候,需要下载一个txt,放到发起支付页面的统计目录
3、到微信公众号平台还是商户平台设置支付授权地址(用于发起支付),不会设置可以发邮件到微信工作人员邮箱,申请处理,邮箱要自己挖(这个地址需要有https://)
4、拿到微信号的appid、mch_id、appscret、key、退款证书、sub_mch_id(服务商需要为子商户开这个,而前五个都是用服务商自己的就可以了)
5、对于境内微信商户,Oauth2的网页验证域名和支付授权地址必须是通过了国内的ICP备案,不然不能用,对于境外微信商户则没有这个要求
以上四个东西都拿到做好了 就可以开始了 (开发文档无敌坑)
一、首先写个通过Oauth的验证的页面(注意redirect_url需要urlencode)
jsapi1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ page language="java" import="java.net.*,java.io.*,java.text.*,java.util.*,com.demo.*,com.demo.dao.*,com.demo.utils.*,java.sql.*" %><%@ page language="java" import="java.net.URLDecoder" %><%@ page language="java" import="org.json.JSONObject" %><%request.setCharacterEncoding("UTF-8");String currCode = request.getParameter("currCode");String oauth2_url = "";String wechat_appid = "数据库读取出来比较好";String wechat_appsecret = "数据库读取出来比较好";String currCode = "RMB";String state = currCode+"|"+wechat_appid+"|end";if(wechat_appid==""){ System.out.println("no wechat appid");}else{ System.out.println("WECHATappid:"+wechat_appid);}String redirect_url = "https://www.myserver.com/jsapi2.jsp";redirect_url = URLEncoder.encode(redirect_url, "UTF-8");oauth2_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+wechat_appid+"&redirect_uri="+redirect_url+"&response_type=code&scope=snsapi_base&state="+state+"#wechat_redirect";%><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title><fmt:message key="pg.eng.payment.payWECHATONL.text.title"/></title></head><body><!-- this page will direct to wechat authorize url and then wechat will redirect to redirect_url with code and state --><script language="JavaScript" type="text/javascript"> window.location.href="<%=oauth2_url%>"; </script></body></html>
二、然后微信会根据上一个页面的redirect_url跳转到对应页面并给出一个openId,在这个页面可以完成输入金额的操作(注意要验证是否微信浏览器打开这个页面,js里面那个is_weixin();方法)
jsapi2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ page language="java" import="java.net.*,java.io.*,java.text.*,java.util.*,com.demo.*,com.demo.dao.*,com.demo.utils.*,java.sql.*" %><%@ page language="java" import="java.net.URLDecoder" %><%@ page language="java" import="org.json.JSONObject" %><%request.setCharacterEncoding("UTF-8");String openId = "";String code = request.getParameter("code");String state = request.getParameter("state");System.out.println("code:"+code+",state:"+state);String[] statespilt = state.split("\\|");String currCode = statespilt[0];String wechat_appid = statespilt[1];String wechat_appsecret = "用wechat_appid查数据库读取出来比较好";String notify_url = "回调地址";System.out.println("wechat_appid:"+wechat_appid+",wechat_appsecret:"+wechat_appsecret);String access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+wechat_appid+"&secret="+wechat_appsecret+"&code="+code+"&grant_type=authorization_code";System.out.println("access_token_url:"+access_token_url);String accesscode_rs = "";accesscode_rs = HttpUtil.postData("",access_token_url);System.out.println("accesscode_rs"+accesscode_rs);JSONObject json;json = new JSONObject(accesscode_rs);System.out.println("OTTO-------set JSONObject");openId = json.getString("openid");System.out.println("OTTO-------openid:"+openId);%><!-- ******************************** input page start *************************************** --><html> <head> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Expires" content="0"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Style-Type" content="text/css"> <script language="JavaScript" type="text/javascript"> window.onload=function(){ is_weixin(); } function is_weixin(){ var ua = navigator.userAgent.toLowerCase(); if(ua.match(/MicroMessenger/i)=="micromessenger") { } else { window.location.href="remind.jsp"; return; } } </script> <title> input page </title> </head> <body> <form action="jsapi3.jsp" method="POST" > <input type="text" id="amount" name="amount" placeholder="input amount"> <input type="submit" id="submit" name="submit" value="submit"> <input type="hidden" id="currCode" name="currCode" value="<%=currCode %>"> <input type="hidden" id="notify_url" name="notify_url" value="<%=notify_url %>"> <input type="hidden" id="wechat_appid" name="wechat_appid" value="<%=wechat_appid %>"> </form> </body></html>
三、根据上一个页面获取到的openId和金额、货币种类等参数调用统一订单API,然后获得一个prepay_id,用这个prepay_id放到发起支付的js里面,微信客户端就能跳出输入密码确认支付的框了,调用微信浏览器里面的js方法来发起支付(注意发起支付的js方法,只有在微信浏览器里面才生效)
jsapi3.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ page language="java" import="java.net.*,java.io.*,java.text.*,java.util.*,com.demo.*,com.demo.dao.*,com.demo.utils.*,java.sql.*" %><%@ page language="java" import="java.net.URLDecoder" %><%@ page language="java" import="org.json.JSONObject" %><%request.setCharacterEncoding("UTF-8");String wechat_appid = request.getParameter("wechat_appid")==null?"":request.getParameter("wechat_appid") ;String openid = request.getParameter("openid")==null?"":request.getParameter("openid") ;String amount = request.getParameter("amount")==null?"0":request.getParameter("amount") ;String currCode = request.getParameter("currCode")==null?"":request.getParameter("currCode") ;String notify_url = request.getParameter("notify_url")==null?"":request.getParameter("notify_url") ;String result = "";String out_trade_no="";double orderAmt = Double.parseDouble(amount)*100;System.out.println("orderAmt:"+orderAmt);//-----------------------------//设置支付参数//-----------------------------String sign = "";String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";String trade_type = "JSAPI";String spbill_create_ip = request.getRemoteAddr();String nonce_str = "";String notify_url = notify_url;String body = out_trade_no;String appid = wechat_appid;String sub_mch_id = "用wechat_appid查数据库读取出来比较好";String mch_id = "用wechat_appid查数据库读取出来比较好";System.out.println("wechat_appid:"+wechat_appid+",appid:"+appid);String currTime = Method.getCurrTime();String time_start = currTime.substring(8, currTime.length());String strRandom = Method.buildRandom(4) + "";nonce_str = time_start + strRandom; // Generating random numberString total_fee = String.valueOf((int)orderAmt);String fee_type = CurrCode.getName(request.getParameter("currCode"));String key = "用wechat_appid查数据库读取出来比较好 微信提供的key";if("RMB".equals(fee_type)) fee_type = "CNY";System.out.println("datas:"+"\n"+"key:"+key+"\n"+"appid:"+appid+"\n"+"mch_id:"+mch_id+"\n"+"sub_mch_id:"+sub_mch_id+"\n"+"out_trade_no:"+out_trade_no+"\n"+"fee_type:"+fee_type+"\n"+"total_fee:"+total_fee+"\n"+"body:"+body+"\n"+"spbill_create_ip:"+spbill_create_ip+"\n"+"trade_type:"+trade_type+"\n"+"notify_url:"+notify_url+"\n"+"nonce_str:"+nonce_str);Map<Object, String> map = new TreeMap<Object, String>();map.put("appid", appid);//服務商appidmap.put("sub_mch_id", sub_mch_id);//商戶號map.put("mch_id", mch_id);//服務商號map.put("nonce_str", nonce_str);//隨機字符串map.put("body", body);//商品描述,用orderIdmap.put("out_trade_no", out_trade_no);//商家訂單號map.put("fee_type", fee_type);//幣種map.put("total_fee", total_fee);//商品金額,以分為單位map.put("spbill_create_ip", spbill_create_ip);//用戶公網ipmap.put("notify_url", notify_url);//微信反饋的接收urlmap.put("trade_type", trade_type);//公众号支付用JSAPImap.put("openid", openid);sign = Method.createSign("UTF-8", map,key);map.put("sign", sign);String requestXML = Method.getRequestXml(map);Map map1 = null;try{ String resXml = ServerPost.postByExternalServerPost(requestXML,UFDODER_URL,"UTF-8"); resXml = resXml.substring(1); System.out.println("resXml:"+resXml); map1 = XMLUtil.doXMLParse(resXml);}catch (ConnectException ce){ System.out.println("连接超时:"+ce.getMessage());}catch (Exception e){ System.out.println("https请求异常:"+e.getMessage());}if(map1==null){ System.out.println("map null"); result = "appId:"+appid+",timeStamp: ,nonceStr: ,package:prepay_id= ,signType: ,paySign: ";}else{ if(!map1.containsKey("prepay_id")||!map1.containsKey("appid")||map1.get("prepay_id")==""){ System.out.println("prepayid error or appid error"); result = "appId:"+appid+",timeStamp: ,nonceStr: ,package:prepay_id= ,signType: ,paySign: "; }else{ String prepay_timeStamp = Method.getCurrTime(); String prepay_time = currTime.substring(8, currTime.length()); String prepay_strRandom = Method.buildRandom(4) + ""; String prepay_nonce_str = nonce_str; String prepay_id = map1.get("prepay_id").toString(); String prepay_SignType = "MD5"; Map<Object, String> prepay_map = new TreeMap<Object, String>(); prepay_map.put("appId", appid); prepay_map.put("timeStamp", prepay_timeStamp); prepay_map.put("nonceStr", prepay_nonce_str); prepay_map.put("package", ("prepay_id="+prepay_id)); prepay_map.put("signType", prepay_SignType); String paySign = Method.createSign("UTF-8", prepay_map,key); result = "\"appId\":\""+appid+"\",\"timeStamp\":\""+prepay_timeStamp+"\",\"nonceStr\":\""+prepay_nonce_str+"\",\"package\":\"prepay_id="+prepay_id+"\",\"signType\":\""+prepay_SignType+"\",\"paySign\":\""+paySign+"\""; } System.out.println("result:"+result);}%><%if(!("appId:"+appid+",timeStamp: ,nonceStr: ,package:prepay_id= ,signType: ,paySign: ").equals(result)){ %><!-- ********************************* payment page ***************************************** --><html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title> <fmt:message key="pg.eng.payment.payWECHATONLResult.text.title"/> </title> <link rel="stylesheet" type="text/css" media="all" href="../../css/common.css"> <meta name="viewport" content="width=device-width"> </script> <script src="../../js/jquery-1.4.2.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ callpay(); }); </script> <script> function close_cancel() { //根据appid,mch_id,out_trade_no,sub_mch_id调用关闭订单接口 关闭订单 } </script> <script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest',{ <%=result%> }, function(res){ WeixinJSBridge.log(res.err_msg); if(res.err_msg == "get_brand_wcpay_request:cancel"){ close_cancel(); }else if(res.err_msg == "get_brand_wcpay_request:fail"){ close_cancel(); } } ); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } </script> <script type="text/javascript"> var start = setInterval(function(){order_status()},1000); function order_status() { //查询自己数据库 根据状态对page_SorF赋值 然后提交表单 /* $.ajax({ type: "POST", url: "../../WECHATONLINEorderStatusCheck", dataType: "text", cache: false, data: { out_trade_no : '<%=out_trade_no%>' }, success: function(data) { if(data!=null){ var result = eval("(" + data + ")"); var s_result = result.status_result; if("Accepted"==s_result){ clearInterval(start); $("#page_SorF").val("successpage"); $("#PayWeChatForm").submit(); }else if("Rejected"==s_result){ clearInterval(start); $("#page_SorF").val("failpage"); $("#PayWeChatForm").submit(); }else{} }else{ } } }); */ } </script> </head> <body> <div id="wrap"> <form name="PayWeChatForm" id="PayWeChatForm" method="post" action="jsapiResult.jsp"> 货币种类:<%=currCode %> 金额: <%=amount %> <input type="hidden" id="amount" name="amount" value="<%=amount%>" > <input type="hidden" id="currCode" name="currCode" value="<%=request.getParameter("currCode")%>" > <input type="hidden" id="page_SorF" name="page_SorF" value="" > </form> </div> </body></html><!-- ********************************* payment page ***************************************** --><%}else{ %> <html> <head></head> <body> <div>Message error</div> </body> </html> <% }%>
四、写回调(微信会通过回调把交易结果返回到Notify_url所在的地方)
Notify.jsp
<%@ page language="java" import="java.util.*,com.demo.*,com.demo.utils.*" pageEncoding="UTF-8"%><%out.println("success");%><%//for getting wechat respon--------start String appid = ""; String mch_id = ""; String sub_mch_id = ""; String trade_type = ""; String bank_type = ""; String total_fee = ""; String fee_type = ""; String cash_fee = ""; String cash_fee_type = ""; String transaction_id = ""; String out_trade_no = ""; String bankTxTime = ""; String rate = ""; String return_code = ""; String result_code = ""; //读取参数 InputStream inputStream ; StringBuffer sb = new StringBuffer(); inputStream = request.getInputStream(); String s ; BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); while ((s = in.readLine()) != null){ sb.append(s); } in.close(); inputStream.close(); //解析xml成map Map<String, String> m = new HashMap<String, String>(); m = XMLUtil.doXMLParse(sb.toString()); //过滤空 设置 TreeMap Map<Object,String> packageParams = new TreeMap<Object,String>(); Iterator it = m.keySet().iterator(); while (it.hasNext()) { String parameter = (String) it.next(); String parameterValue = m.get(parameter); String v = ""; if(null != parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter, v); } //------------------------------ //处理业务开始 //------------------------------ String resXml = ""; if("SUCCESS".equals((String)packageParams.get("result_code"))){ // 这里是支付成功 appid = (String)packageParams.get("appid"); mch_id = (String)packageParams.get("mch_id"); sub_mch_id = (String)packageParams.get("sub_mch_id"); trade_type = (String)packageParams.get("trade_type"); bank_type = (String)packageParams.get("bank_type"); total_fee = (String)packageParams.get("total_fee"); fee_type = (String)packageParams.get("fee_type"); cash_fee = (String)packageParams.get("cash_fee"); cash_fee_type = (String)packageParams.get("cash_fee_type"); transaction_id = (String)packageParams.get("transaction_id"); out_trade_no = (String)packageParams.get("out_trade_no"); bankTxTime = (String)packageParams.get("time_end"); rate = (String)packageParams.get("rate"); return_code = (String)packageParams.get("return_code"); result_code = (String)packageParams.get("result_code"); System.out.println("Notify:"+"\n"+"appid:"+appid+"\n"+"mch_id:"+mch_id+"\n"+"sub_mch_id:"+sub_mch_id+"\n"+"trade_type:"+trade_type+"\n"+"bank_type:"+bank_type+"\n"+"total_fee:"+total_fee+"\n"+"fee_type:"+fee_type+"\n"+"cash_fee:"+cash_fee+"\n"+"cash_fee_type:"+cash_fee_type+"\n"+"transaction_id:"+transaction_id+"\n"+"out_trade_no:"+out_trade_no+"\n"+"rate:"+rate+"\n"+"return_code:"+return_code+"\n"+"result_code:"+result_code); System.out.println("pay success"); //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { System.out.println("支付失败,错误信息:" + packageParams.get("err_code")); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文 ></return_msg>" + "</xml> "; } //------------------------------ //处理业务完毕 //------------------------------ BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream()); bos.write(resXml.getBytes()); bos.flush(); bos.close(); //for getting wechat respon--------end boolean signValidate = false; // 账号信息 String key = "set wechat ket here"; // key //判断签名是否正确 if(Method.isTenpaySign("UTF-8", packageParams,key)) { signValidate = true; System.out.println("NOTIFY : " + "tenpay sign success"); } else{ signValidate = false; System.out.println("NOTIFY : " + "tenpay sign fail"); } if ( (signValidate && return_code.equals("SUCCESS")) ) { if (signValidate && return_code.equals("SUCCESS") && result_code.equals("SUCCESS")) { //对数据库做交易成功的处理逻辑 } else { //对数据库做交易失败的处理逻辑 } } out.clear(); out = pageContext.pushBody();%>
五、写结果页面
jsapiResult.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ page language="java" import="java.net.*,java.io.*,java.text.*,java.util.*,com.demo.*,com.demo.dao.*,com.demo.utils.*,java.sql.*" %><%request.setCharacterEncoding("UTF-8");String page_SorF = request.getParameter("page_SorF")==null?"failpage":request.getParameter("page_SorF"); //successpage or failpageString amount = request.getParameter("amount")==null?"":request.getParameter("amount");String currCode = request.getParameter("currCode")==null?"":request.getParameter("currCode");%><%if("successpage".equals(page_SorF)){%><!--************************success page start********************************--><html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title> Result page </title> <link rel="stylesheet" type="text/css" media="all" href="../../css/common.css"> <meta name="viewport" content="width=device-width"> </script> </head> <body> <div> <form name="form1" method="post" action=""> 货币种类:<%=currCode %> 金额: <%=amount %> </form> </div> </body></html><!--*************************success page end*********************************--><%}else if("failpage".equals(page_SorF)){%><!--************************fail page start********************************--><html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title> fail </title> <link rel="stylesheet" type="text/css" media="all" href="../../css/common.css"> <meta name="viewport" content="width=device-width"> </head> <body> <form name="failForm" method="post" action="payForm.jsp"> <div>fail</div> </form> </body></html><!--*************************fail page end*********************************--><%}else{ %> <!--************************fail start********************************--> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title> failpage value null </title> <link rel="stylesheet" type="text/css" media="all" href="../../css/common.css"> <meta name="viewport" content="width=device-width"> </head> <body> <form name="failForm" method="post" action="payForm.jsp"> <div>failpage value null</div> </form> </body> </html> <!--*************************fail end*********************************--> <%}%>
六、写如果不是微信浏览器的时候的提示页面
remind.jsp
<html> <head> <title>Wrong Browser</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0" /> <link rel="stylesheet" type="text/css" href="https://res.wx.qq.com/open/libs/weui/0.4.1/weui.css" /> </head> <body> <div class="weui_msg"> <div class="weui_icon_area"> <i class="weui_icon_info weui_icon_msg"></i> </div> <div class="weui_text_area"> <h4 class="weui_msg_title">Please open with WeChat</h4> </div> </div> </body></html>
总结:代码写出来很快(com.demo.utils.*里面那些Method.xxx()、XMLUtils.xxx之类的方法,微信demo上有,我之前写的微信支付贴也有,只是一些生成随机字符、解析xml之类的方法,自己直接写也可以,很简单的),不过需要注意细节(redirect_url需要先urlencode、判断是否微信浏览器、微信账号的配置、code/openId/prepay_id的获取和使用),这些细节就是坑,做少了做错了就走不通。
- 微信扫码支付 模式一 (JSAPI)
- 微信支付-JSAPI模式开发
- 微信扫码支付模式一
- 微信扫码支付--模式一
- 微信扫码支付 模式一
- ThinkPHP整合微信支付之JSAPI模式
- 微信支付JSAPI模式及退款CodeIgniter集成篇
- 微信支付JSAPI模式及退款CodeIgniter集成篇
- ThinkPHP整合微信支付之JSAPI模式
- 微信JSAPI支付
- 微信 jsapi 支付
- 微信支付服务商模式(受理机构模式)开发注意事项,jsapi支付
- 微信支付服务商模式(受理机构模式)开发注意事项,jsapi支付
- 微信支付服务商模式(受理机构模式)开发注意事项,jsapi支付
- 微信支付Jsapi支付
- 微信支付JSAPI支付
- 微信扫码支付模式一的实现
- JAVA微信扫码支付模式一功能实现
- Android 将具体数值转换成dip简单方法
- 第六周算法分析与设计Ⅱ:Merge Two Sorted Lists
- 如何大数据帮助销售人员完成交易?
- jedis和在spring中配置文件
- 欢迎使用CSDN-markdown编辑器
- 微信扫码支付 模式一 (JSAPI)
- 蓝桥杯 基础练习 十六进制转十进制
- npm install 时总是报phantomjs-prebuilt@2.1.14安装失败
- react.js总结学习
- ROS Robotics Projects(1)代码使用编译
- React-Native 之 项目实战(三)
- LeetCode025 Reverse Nodes in k-Group
- 容灾双活
- Python学习笔记(5)——字符串