参考文档:微信公众号支付
微信公众号支付,最为麻烦的是需要获取支付者的openid,这就需要用户在查看商品时,就要提前获取到用户的openid,注意:尽量在支付之前就获取到openid,保存在session中,以方便接下来的调用。
下面是具体开发步骤:
1.登陆微信公众平台,查看“开发”-->“接口权限”,如下图
2.如未获取网页授权权限,需要先申请,接下来需要配置授权域名,点击修改,打开如下页面
3.点击设置,配置授权域名如图,这里需要注意的时,回调域名说明中的3,首先按照说明,下载文件,打开文件
MP_verify_suf8fVQzCk0Mh42y.txt,把文件中的内容复制出来。接下里在项目中配置一个供直接访问的文件路径。
@RequestMapping("/MP_verify_suf8fVQzCk0Mh42y.txt") public ResponseEntity<String> checkWX(){ HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("Content-Type", "application/json;charset=UTF-8"); return new ResponseEntity<String>("XXXXXXXXXXX",responseHeaders, HttpStatus.OK); }
4.配置成功后,查看公众号中的开发者id,打开“开发”-->“基本配置”。接下来把微信支付配置也顺便处理了,打开“微信支付”-->“开发配置”,配置支付授权目录(注意,目录至少配置到二级或三级,如www.baidu.com/wx/pay/,通知以“/”结尾,这个域名需要和网页授权域名相同,这个很容易忽略!)
5.获取用户openid,一般通过静默授权,打开链接 https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx00000000000&redirect_uri=http%3A%2F%2Fwww.baidu.com%2Fwx?response_type=code&scope=snsapi_base&state=dac24d03f848ce899f28ad787eba74e2&connect_redirect=1#wechat_redirect。红色标识为需要根据自己公众号改变的,得到code。
6.拦截到5中配置的回调链接,拿到code,再去获取用户的openid。代码如下
public static User getUserWXOpenid(String code){ //1.得到access_token String jsonUrl="https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx000000000000&secret=5652222222222200000&code="+code+"&grant_type=authorization_code"; //appid和secret根据上述在基本配置中查看 String jsonResponse=sendGet(jsonUrl); //2.对json数据进行解析 JSONObject jsonObject=JSONObject.parseObject(jsonResponse); String access_token=jsonObject.getString("access_token"); String openid=jsonObject.getString("openid"); User user=new User(); user.setOpenid(openid); return user; }
@RequestMapping("/wx") public String wx_open(HttpServletRequest request, Model model) { System.out.println("得到code"); String code = request.getParameter("code"); System.out.println("code:"+code); User user = getUserWXOpenid(code); System.out.println("openId:"+user.getOpenid()); request.getSession().setAttribute("openId",user.getOpenid()); request.getSession().setAttribute("is_got_auth",true); return "redirect:/index"; }
7.下面就是吊起微信公众号支付的核心代码
String subject="商品";
String openid=request.getSsion.getAttribute("openid");//得到之前存在session中的openid //微信支付 Utils.getIP(request) String now_ip= "192.168.1.3"; String nonce_str=Utils.getCharAndNum(32); String total_fee="1";//注意:微信支付单位为分 String prepay_id=null; Map<String,String> paraMap=new HashMap<>(); paraMap.put("appid", PayConfigUtils.getWx_app_id());//appid paraMap.put("attach", subject); paraMap.put("body", subject); paraMap.put("mch_id", PayConfigUtils.getWx_mch_id()); //商户id,登陆微信商户平台查看 paraMap.put("nonce_str", nonce_str); paraMap.put("notify_url", PayConfigUtils.getWebUrl()+"wx_pay/notify");//微信支付回执链接,用于回馈支付结果 paraMap.put("openid", openId); paraMap.put("out_trade_no", "5225555111"); paraMap.put("spbill_create_ip", now_ip); paraMap.put("total_fee", total_fee); paraMap.put("trade_type", "JSAPI"); List<String> keys =new ArrayList<>(paraMap.keySet()); Collections.sort(keys); StringBuilder authInfo = new StringBuilder(); for (int i=0;i<keys.size()-1; i++) { String value = paraMap.get(keys.get(i)); authInfo.append(keys.get(i)+"="+value+"&"); } authInfo.append(keys.get(keys.size()-1)+"="+paraMap.get(keys.get(keys.size()-1))); String stringA=authInfo.toString()+"&key="+PayConfigUtils.getWx_app_secret_key(); String sign=Utils.encode("MD5",stringA).toUpperCase(); //封装xml String paras="<xml> " + " <appid>"+PayConfigUtils.getWx_app_id()+"</appid> " + " <attach>"+subject+"</attach> " + " <body>"+subject+"</body> " + " <mch_id>"+PayConfigUtils.getWx_mch_id()+"</mch_id> " + " <nonce_str>"+nonce_str+"</nonce_str> " + " <notify_url>"+paraMap.get("notify_url")+"</notify_url> " + " <out_trade_no>"+order.getPay_number()+"</out_trade_no> " + " <spbill_create_ip>"+now_ip+"</spbill_create_ip> " + " <total_fee>"+total_fee+"</total_fee> " + " <openid>"+openId+"</openid> " + " <trade_type>JSAPI</trade_type> " + " <sign>"+sign+"</sign> " + "</xml>"; try { String content=senPost(paras); if(content!=null){ prepay_id=Utils.readStringXml(content); } if(prepay_id!=null){ String current_noncestr=Utils.getCharAndNum(32); String current_sign=null; long current_timestamp=System.currentTimeMillis()/1000; result.put("appid",PayConfigUtils.getWx_app_id()); result.put("signType","MD5"); result.put("package","prepay_id="+prepay_id); //a,n,p,s,t result.put("noncestr",current_noncestr); result.put("timestamp",current_timestamp); //加密算法 String nowStringA="appId="+PayConfigUtils.getWx_app_id()+"&nonceStr="+current_noncestr+"&package=prepay_id="+prepay_id+"&signType=MD5&timeStamp="+current_timestamp+"&key="+PayConfigUtils.getWx_app_secret_key(); System.out.println(nowStringA); current_sign=Utils.encode("MD5",nowStringA).toUpperCase(); System.out.println(current_sign); result.put("paySign",current_sign); } } catch (Exception e) { e.printStackTrace(); } System.out.println(result.toString());
//发送post请求,得到微信预支付id public static String senPost(String paras) throws IOException { boolean is_success=true; int i=0; String result=""; while (is_success){ String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; HttpClient httpClient = new DefaultHttpClient(); HttpPost post = new HttpPost(url); StringEntity postingString = new StringEntity(paras,"utf-8");// xml传递 post.setEntity(postingString); post.setHeader("Content-type", "text/html; charset=UTF-8"); HttpResponse response = httpClient.execute(post); result = EntityUtils.toString(response.getEntity()); if(result==null||result.isEmpty()){ i++; }else { break; } if(i>2){ break; } } return result; } 8.至此,微信公众号支付的参数已准备完毕,最后是前台的js吊起微信支付,具体代码如下: function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 "timeStamp":" 1395712654", //时间戳,自1970年以来的秒数 "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 "package" : "prepay_id=u802345jgfjsdfgsdg888", "signType" : "MD5", //微信签名方式: "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 } ); } 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(); }
9.微信公众支付过程比较繁琐,细节要注意好!