微信支付
微信支付有很多种方式,其中主要以小程序支付坑最多.主要在于再次签名的问题
主要说后台开发,前端同事登录后将微信返回的code码传给后台,后台组装请求路径
通过返回的数据中获取openID,然后组织参数调微信统一下单接口,这里调接口之前需要签名,这是第一次签名,具体参数可参照官方开发文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1
调用统一下单接口后,会返回给我们一些数据,我们要利用其中的部分数据进行再次签名,
再次签名参考官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
其中需要注意的几个点,小程序ID appId中的i要大写,不然签名不正确,还有就是时间戳要用统一支付接口返回给的时间戳,博主之前用的是自己生成的时间戳导致调微信支付页面显示签名错误,然后就是数据包
生成签名后将数据返回给前端,小程序支付基本就做好了,还有微信通知接口需要些,这里就不再写了.
下面是代码:
@ResponseBody @RequestMapping(value = "/miniPay", method = RequestMethod.GET) public String miniPay(String miniCode,String money){ Result result = new Result(); Map<String, String> params = new HashMap<String, String>(); String tradeNo = CommUtil.getNonce_str();// 获取订单号 String openidResult = null;; try { //获取open_id StringBuffer buffer = new StringBuffer(); buffer.append(mini_url); buffer.append("?appid="+miniappid); buffer.append("&secret="+appSecret); buffer.append("&js_code="+miniCode); buffer.append("&grant_type=authorization_code"); openidResult = HttpUtil.sendGet(buffer.toString()); Map<String, Object> openidMap = JSON.parseObject(openidResult); String openid = (String) openidMap.get("openid"); //从token中获取用户id String token = request.getHeader("token"); String userInfo = this.redisService.get(token); UserInfo user = JSON.parseObject(userInfo, UserInfo.class); params.put("product_id", user.getId() + ""); // 商品ID,对应用户ID //配置下单参数并下单 params.put("appid", miniappid); params.put("mch_id", mch_id); params.put("nonce_str", tradeNo); params.put("body", "劳资医生-积分充值"); params.put("out_trade_no", tradeNo); params.put("total_fee", changeMoney(money)); params.put("spbill_create_ip", CommUtil.getIpAddress(request)); params.put("notify_url", notify_url); params.put("trade_type", mini_trade_type); params.put("openid", openid); String sign = CommUtil.generateSignature(params, api_key, mdSignType); params.put("sign", sign); String requestXML = XMLUtil.mapToXml(params); String resultXML = HttpUtil.postData(ufdoder_url, requestXML); Map<String, String> resultMap = XMLUtil.doXMLParse(resultXML); //再次签名 String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳 Map<String, String> paySignMap = new HashMap<String,String>(); paySignMap.put("appId", miniappid);//小程序ID paySignMap.put("timeStamp", timeStamp);//时间戳 paySignMap.put("nonceStr", resultMap.get("nonce_str")); paySignMap.put("package", "prepay_id="+resultMap.get("prepay_id")); paySignMap.put("signType", "MD5"); //MD5加密生成签名 String paySign = CommUtil.generateSignature(paySignMap, api_key, mdSignType); resultMap.put("paySign", paySign); resultMap.put("timeStamp", timeStamp); result.setData(resultMap); } catch (Exception e) { logger.error("生成微信支付数据异常", e); getServerErrorResult(result); } return ResponseHelper.createResponse(result); }
发送HTTP的GET请求方法
public static String sendGet(String url) { String result = ""; BufferedReader in = null; try { String urlNameString = url; URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 URLConnection connection = realUrl.openConnection(); // 设置通用的请求属性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立实际的连接 connection.connect(); // 获取所有响应头字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定义 BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送GET请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; }
获取客户端IP方法
public static String getIpAddress(HttpServletRequest request) { String ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknow".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (ipAddress.equals(Constants.LOCALHOST1) || ipAddress.equals(Constants.LOCALHOST2)) { // 根据网卡获取本机配置的IP地址 InetAddress inetAddress = null; try { inetAddress = InetAddress.getLocalHost(); } catch (UnknownHostException e) { logger.error(e.getMessage()); } if(inetAddress != null){ ipAddress = inetAddress.getHostAddress(); } } } // 对于通过多个代理的情况,第一个IP为客户端真实的IP地址,多个IP按照','分割 if (null != ipAddress && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } return ipAddress; }
MD5加密网上都有,百度下就可以了.还有就是签名的时候一定要区分大小写,要就是要排序,排序后加上商户的key才可以进行加密,因为前段同事痛的是MD5加密,为了保持统一,也用的是MD5
PC端的扫码支付用的是HMAC-SHA256加密方式.
能想到的就这么多,以后再补充!