最近因为项目要做微信支付、所以把过程记录下来以备以后会需要到。
1.微信支付文档:https://open.swiftpass.cn/openapi/doc?index_1=5&index_2=1&chapter_1=30&chapter_2=32#
2.因为项目是Java的、所以我下载了Java的demo
如下:
这里的servlet就是主要的方法:测试支付、订单状态查询、通知、测试退款、退款查询几个方法、这些都有针对的APi文档可以查看;
1.测试支付
1 public String wechatPay(HttpServletRequest req, HttpServletResponse resp, DOPayBean bean) throws ServletException, IOException { 2 Map<String,String> orderResult = new HashMap<String, String>(); //用来存储订单的交易状态(key:订单号,value:状态(0:未支付,1:已支付)) ---- 这里可以根据需要存储在数据库中 3 req.setCharacterEncoding("utf-8"); 4 resp.setCharacterEncoding("utf-8"); 5 6 SortedMap<String,String> map = XmlUtils.getParameterMap(req); 7 8 9 map.put("mch_id", "175510359638"); 10 //重复提交的时候直接查询本地的状态 11 /* if(orderResult != null && orderResult.containsKey(map.get("out_trade_no"))){ 12 String status = "0".equals(orderResult.get(map.get("out_trade_no"))) ? "未支付" : "已支付"; 13 resp.setHeader("Content-type", "text/html;charset=UTF-8"); 14 resp.getWriter().write(status); 15 }else{*/ 16 map.put("notify_url", "http://wasdsad.net/card/swpay/pay_notify_alipay_pay.html"); 17 // map.put("out_trade_no", "2017060612004115998"); 18 map.put("out_trade_no", "2017060612004115999"); 19 20 map.put("service", "pay.weixin.wappay"); 21 map.put("version", "2.0"); 22 map.put("charset", "UTF-8"); 23 map.put("sign_type", "MD5"); 24 map.put("body", "测试购买商品"); 25 map.put("attach", "附加信息"); 26 map.put("total_fee", "1"); 27 map.put("mch_create_ip", "127.0.0.1"); 28 29 map.put("nonce_str", String.valueOf(new Date().getTime())); 30 map.put("callback_url","https://www.baidu.com/");//前端页面跳转地址(包括支付成功和关闭时都会跳到这个地址) 31 32 //注意:device_info、mch_app_name、mch_app_id这三个具体传值必须以文档说明为准,传真实有效的,否则有可能无法正常支付!!! 33 map.put("device_info", "AND_SDK"); 34 map.put("mch_app_name", "王者荣耀"); 35 map.put("mch_app_id", "com.tencent.tmgp.sgame"); 36 Map<String,String> params = SignUtils.paraFilter(map); 37 StringBuilder buf = new StringBuilder((params.size() +1) * 10); 38 SignUtils.buildPayParams(buf,params,false); 39 String preStr = buf.toString(); 40 String sign = MD5.sign(preStr, "&key=" + "61307e5f2aebcacecb****fe5296df9c", "utf-8"); 41 map.put("sign", sign); 42 43 String reqUrl = "https://pay.swiftpass.cn/pay/gateway"; 44 System.out.println("reqUrl:" + reqUrl); 45 46 System.out.println("reqParams:" + XmlUtils.parseXML(map)); 47 CloseableHttpResponse response = null; 48 CloseableHttpClient client = null; 49 String res = null; 50 try { 51 HttpPost httpPost = new HttpPost(reqUrl); 52 StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map),"utf-8"); 53 httpPost.setEntity(entityParams); 54 //httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1"); 55 client = HttpClients.createDefault(); 56 response = client.execute(httpPost); 57 if(response != null && response.getEntity() != null){ 58 Map<String,String> resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8"); 59 res = XmlUtils.toXml(resultMap); 60 System.out.println("请求结果:" + res); 61 62 if(resultMap.containsKey("sign")){ 63 if(!SignUtils.checkParam(resultMap, SwiftpassConfig.key)){ 64 res = "验证签名不通过"; 65 }else{ 66 if("0".equals(resultMap.get("status")) && "0".equals(resultMap.get("result_code"))){ 67 if(orderResult == null){ 68 orderResult = new HashMap<String,String>(); 69 } 70 orderResult.put(map.get("out_trade_no"), "0");//初始状态 72 String pay_info = resultMap.get("pay_info"); 75 resp.sendRedirect(pay_info); //这里直接挑转到微信支付的页面 81 }else{ 82 req.setAttribute("result", res); 83 } 84 } 85 } 86 }else{ 87 res = "操作失败"; 88 } 89 } catch (Exception e) { 90 e.printStackTrace(); 91 res = "系统异常"; 92 } finally { 93 if(response != null){ 94 response.close(); 95 } 96 if(client != null){ 97 client.close(); 98 } 99 } 100 if(res.startsWith("<")){ 101 resp.setHeader("Content-type", "text/xml;charset=UTF-8"); 102 }else{ 103 resp.setHeader("Content-type", "text/html;charset=UTF-8"); 104 } 105 resp.getWriter().write(res); 106 return res; 107 //} 108 } 109
注 :1.因为是用于测试,所以目前把所有参数都是写死的。这样根据以上代码就可以完成支付了,给自己开发的时候就要换上自己的key和商户号这些参数了
2. notify_url这个参数必须要传给一个可以在公网上接收到的接口中、可以是接口、可以是方法(我本地用的是nat123 -- 方便开发测试、这个工具把本地的端口映射到公网、然后在支付的时候配置的接收通知的接口);下篇将讲述接受通知的方法。