微信支付分很多种,其中微信H5支付是给在手机浏览器上使用,在手机上发起付款,自动跳转到微信并付款
微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
微信H5支付文档:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1
微信统一下单接口:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_1
微信H5支付流程:
1、用户在商户侧完成下单,使用微信支付进行支付
2、由商户后台向微信支付发起下单请求(调用统一下单接口)注:交易类型trade_type=MWEB
3、统一下单接口返回支付相关参数给商户后台,如支付跳转url(参数名“mweb_url”),商户通过mweb_url调起微信支付中间页
4、中间页进行H5权限的校验,安全性检查(此处常见错误请见下文)
5、如支付成功,商户后台会接收到微信侧的异步通知
6、用户在微信支付收银台完成支付或取消支付,返回商户页面(默认为返回支付发起页面)
7、商户在展示页面,引导用户主动发起支付结果的查询
8,9、商户后台判断是否接到收微信侧的支付结果通知,如没有,后台调用我们的订单查询接口确认订单状态
10、展示最终的订单支付结果给用户
支付部分代码:
/** * 微信H5支付2号方案 */ @RequestMapping("/wapPay") @ResponseBody public net.sf.json.JSONObject pay(HttpServletRequest request, HttpServletResponse response, Integer userid, Double money, Integer num) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); net.sf.json.JSONObject json = new net.sf.json.JSONObject(); String ip = null; //以下代码为获取请求的公网IP //X-Forwarded-For:Squid 服务代理 String ipAddresses = request.getHeader("X-Forwarded-For"); if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //Proxy-Client-IP:apache 服务代理 ipAddresses = request.getHeader("Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //WL-Proxy-Client-IP:weblogic 服务代理 ipAddresses = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //HTTP_CLIENT_IP:有些代理服务器 ipAddresses = request.getHeader("HTTP_CLIENT_IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //X-Real-IP:nginx服务代理 ipAddresses = request.getHeader("X-Real-IP"); } //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP if (ipAddresses != null && ipAddresses.length() != 0) { ip = ipAddresses.split(",")[0]; } //还是不能获取到,最后再通过request.getRemoteAddr();获取 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { ip = request.getRemoteAddr(); } if (StrKit.isBlank(ip)) { ip = "127.0.0.1"; } int intMoney =(int)(money * 100); //商户相关资料 String appid = "***";//公众号appid String appsecret = "***";//公众号秘钥 String partner = "***";//商户号 String partnerkey = "***";//商户API秘钥 //用于获取随机数 String currTime = TenpayUtil.getCurrTime();//获取当前时间 String strTime = currTime.substring(8, currTime.length());//8位日期 String strRandom = TenpayUtil.buildRandom(4) + "";//四位随机数 String strReq = strTime + strRandom;//10位序列号,可以自行调整 String orderNo=appid+userid+ Sha1Util.getTimeStamp();//随机生成了一个订单号 //商户号 String mch_id = partner; //设备号 非必输 String device_info="WEB"; //随机数 String nonce_str = strReq; //商品描述 String body = "号码筛选充值"; //附加数据 String attach = "shengyu"; //商户订单号 String out_trade_no = orderNo; //总金额以分为单位,不带小数点 int total_fee = intMoney; // String spbill_create_ip = request.getRemoteAddr(); String spbill_create_ip = ip; String trade_type = "MWEB";//H5支付方式 SortedMap<String, String> packageParams = new TreeMap<String, String>(); packageParams.put("appid", appid); packageParams.put("mch_id", mch_id); packageParams.put("nonce_str", nonce_str); packageParams.put("body", body); packageParams.put("attach", attach); packageParams.put("out_trade_no", out_trade_no); packageParams.put("total_fee", String.valueOf((intMoney))); packageParams.put("spbill_create_ip", spbill_create_ip); packageParams.put("notify_url", notify_url); packageParams.put("trade_type", trade_type); RequestHandler reqHandler = new RequestHandler(request, response); reqHandler.init(appid, appsecret, partnerkey); //获取签名 String sign = reqHandler.createSign(packageParams); String xml="<xml>"+ "<appid>"+appid+"</appid>"+ "<mch_id>"+mch_id+"</mch_id>"+ "<nonce_str>"+nonce_str+"</nonce_str>"+ "<sign>"+sign+"</sign>"+ "<body>"+body+"</body>"+ "<attach>"+attach+"</attach>"+ "<out_trade_no>"+out_trade_no+"</out_trade_no>"+ "<total_fee>"+total_fee+"</total_fee>"+ "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+ "<notify_url>"+notify_url+"</notify_url>"+ "<out_trade_no>"+ orderNo+"</out_trade_no>"+ "<trade_type>"+trade_type+"</trade_type>"+ "</xml>"; String allParameters = "";//没用 try { allParameters = reqHandler.genPackage(packageParams); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //请求微信统一下单接口,成功后返回预支付交易会话标识prepay_id String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; String prepay_id = ""; String mweb_url=""; try { Map<String ,String> returnmap= new GetWxOrderno().getPayNo(createOrderURL, xml); prepay_id=returnmap.get("prepay_id"); mweb_url=returnmap.get("mweb_url"); if(prepay_id.equals("")){ json.put("msg","统一支付接口获取预支付订单出错"); return json; } //这里可以放增加订单信息 } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } //生成H5调起微信支付API相关参数(前端页面js的配置参数) SortedMap<String, String> finalpackage = new TreeMap<String, String>(); String timestamp = Sha1Util.getTimeStamp();//当前时间的时间戳 String packages = "prepay_id="+prepay_id;;//订单详情扩展字符串 finalpackage.put("appId", appid);//公众号appid finalpackage.put("timeStamp", timestamp); finalpackage.put("nonceStr", strReq); //随机数 finalpackage.put("package", packages); finalpackage.put("signType", "MD5");//签名方式 String finalsign = reqHandler.createSign(finalpackage);//签名 String returnurl_1=""; try { returnurl_1=returnurl; // 将普通字符创转换成application/x-www-from-urlencoded字符串 returnurl_1 = URLEncoder.encode(returnurl, "GBK"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } json.put("appId", appid); json.put("timeStamp", timestamp); json.put("nonceStr", strReq); json.put("packages", packages); json.put("sign", finalsign); json.put("mweb_url", mweb_url+"&redirect_url="+returnurl);//+"&redirect_url=wap%2frechargeSuccess.html" return json; } /** * 支付完成的回调,修改订单状态等 * @return */ @ResponseBody @RequestMapping("/trueOrder") public String notify(HttpServletRequest request, HttpServletResponse response) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream())); String line = null; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { sb.append(line); } StringBuilder jsonStr = sb; Map<String, Object> dataMap = new HashMap<String, Object>(); Map map = doXMLParse(jsonStr.toString()); String out_trade_no = (String) map.get("out_trade_no");//获取订单号 //下面是根据订单号修改订单状态、账户余额等 //返回,如果不加可能会请求多次 return "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[支付成功]]></return_msg>" + "</xml>"; }