谨以此做记录,方便下次实现,不适合新手拷贝,如有指教,欢迎留言讨论!
新手请参考博文:https://blog.csdn.net/javaYouCome/article/details/79473743,致谢该博主!
微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
记录几个容易出问题的点:
1、参与签名的参数名大小写保持与官方文档一致,
2、在商户平台配置支付目录,类似配置js安全接口域名
3、调用统一下单接口获取prepay_id=参数(参数签名浪费了很多时间,注意参数名保持一致)
主要代码:
后台调用统一下单接口:参数签名工具类来自微信官方支付demo
/** * 统一下单接口,获取prepay_id * @param request * @return */ @RequestMapping(value = "/unifiedOrder", method = RequestMethod.GET) @ResponseBody public Map<String, String> unifiedOrder(HttpServletRequest request,String openId,String totalFee) { try { // 不带properties扩展名的文件名 ResourceBundle wx = ResourceBundle.getBundle("wx"); // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //拼接统一下单地址参数 Map<String, String> paraMap = new HashMap<String, String>(); //获取请求ip地址 String ip = request.getHeader("x-forwarded-for"); if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){ ip = request.getHeader("Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){ ip = request.getHeader("WL-Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){ ip = request.getRemoteAddr(); } if(ip.indexOf(",")!=-1){ String[] ips = ip.split(","); ip = ips[0].trim(); } String appid = wx.getString("wx_appid"); paraMap.put("appid", appid); paraMap.put("body", "********"); paraMap.put("mch_id", "****"); paraMap.put("nonce_str", WXPayUtil.generateNonceStr()); paraMap.put("openid", openId); paraMap.put("out_trade_no", new Date().getTime()+"");//订单号 paraMap.put("spbill_create_ip", ip); paraMap.put("total_fee",totalFee); paraMap.put("trade_type", "JSAPI"); paraMap.put("notify_url",wx.getString("red_url") + "/callback.do");// 此路径是微信服务器调用支付结果通知路径随意写 String sign = WXPayUtil.generateSignature(paraMap, "********"); paraMap.put("sign", sign); String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式 System.out.println(xml); String xmlStr = wxMpService.post(unifiedorder_url, xml); //发送post请求"统一下单接口"返回预支付id:prepay_id //以下内容是返回前端页面的json数据 String prepay_id = "";//预支付id if (xmlStr.indexOf("SUCCESS") != -1) { Map<String, String> map = WXPayUtil.xmlToMap(xmlStr); prepay_id = (String) map.get("prepay_id"); } Map<String, String> payMap = new HashMap<String, String>(); payMap.put("appId", appid); payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+""); payMap.put("nonceStr", WXPayUtil.generateNonceStr()); payMap.put("signType", "MD5"); payMap.put("package", "prepay_id=" + prepay_id); String paySign = WXPayUtil.generateSignature(payMap, "*******"); payMap.put("paySign", paySign); String xml2 = WXPayUtil.mapToXml(payMap);//将所有参数(map)转xml格式 System.out.println(xml2); return payMap; } catch (Exception e) { e.printStackTrace(); return null; } } @RequestMapping(value="/callback",method=RequestMethod.GET) public String callBack(HttpServletRequest request,HttpServletResponse response){ //System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息"); InputStream is = null; try { is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读) String xml = WXPayUtil.inputStream2String(is, "UTF-8"); Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map if(notifyMap.get("return_code").equals("SUCCESS")){ //支付成功 } //告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可 response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>"); is.close(); } catch (Exception e) { e.printStackTrace(); } return null; }
前台jssdk接收配置参数,调起支付:
//支付 function pay(price){ $.get("${basePath}/pay/unifiedOrder.do",{"openId":"${sessionScope.openId }","totalFee":price},function(data,status){ wx.ready(function() { wx.chooseWXPay({ timestamp: data.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位 package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*) signType: data.signType, // 签名方式,默认为‘SHA1‘,使用新版支付需传入‘MD5‘ paySign: data.paySign, // 支付签名 success: function (res) { // 支付成功后的回调函数 alert(1); } }) }); }); }