微信支付实现过程:
1:首先是企业注册微信公众平台;
2:需要认证,然后开通微信支付;如图
3:进入这里来注册商户; 每一个小程序对应一个商户
4: 商户和小程序或者公众号做邦定,
5:根据开发需要 ,进行开发配置:
------------------------------------------------
以上准备工作做完后可进行开发,邦定成功后如图显示
小程序配置
接下来开始配置代码:
这里我只介绍小程序的支付配置:
小程序相对较为简单,关键是接下来的参数需要配置正确其余就ok了;
整体思路:
小程序发送一个支付请求,后端进行支付处理,返回5个参数,然后小程序发起支付输入密码,支付成功;
1: 小程发送请求 ,后端下单 ,返回5个参数
5个参数搞清楚了一切好办:
appid=wx5c022XXXXXXXX 小程序的appid
secret=3165b49d0772fdf28bd20 小程序的secret
key= 这个key就是上面商户配置中,帐户中心->API安全-> 设置密钥,,这个在你写程序的时候往往会出现解密不成功,或其他签名错误时,重新设置一下这个密钥,
mch_id=15236 绑定的商户号
body=支付收款名称
notify_url =https://wx.ing.com,这里配置小程序的配置里;
开始后端处理支付代码:
//CommonSdo我自己定义的返回类
public CommonSdo<Map<String,Object>> wxpay(String openid, //这是openid ,根据自己业务来传参 Long oid, //这是我们的 订单id 根据自己业务来传参 HttpServletRequest request){ if (null==openid){ return CommonSdo.error("登陆过期,请重新登陆"); } //客户下订单 Order order = findOrderById(oid).getItem(); //获取小程序端客户下的订单 //微信支付开始///////////////////////////////////////////////////////////////////////////////try { //生成的随机字符串 String nonce_str =getRandomStringByLength(32); //商品名称 String body = "工作室"; //获取客户端的ip地址 String spbill_create_ip = getIpAddr(request); //组装参数,用户生成统一下单接口的签名 Map<String, String> packageParams = new HashMap<String, String>(); packageParams.put("appid", apppid); //小程序的appid packageParams.put("mch_id", mch_id); //绑定的商户号 packageParams.put("nonce_str", nonce_str); //生成的随机字符串 packageParams.put("body", body); //商品名称 packageParams.put("out_trade_no",order.getCode()); //商户订单号,这个订单号注意不要重复,否则会提示已支付等问题 packageParams.put("total_fee",orderPrice); //支付金额,这边需要转成字符串类型,否则后面的签名会失败,以分为单位 packageParams.put("spbill_create_ip", spbill_create_ip);// packageParams.put("notify_url",notify_url);//支付成功后的回调地址 packageParams.put("trade_type", "JSAPI");//支付方式 packageParams.put("openid", openid); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 String prestr = PayUtil.createLinkString(packageParams); //MD5运算生成签名,这里是第一次签名,用于调用统一下单接口 String mysign = PayUtil.sign(prestr,key,"utf-8").toUpperCase(); //拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去 String xml = "<xml>" + "<appid>"+apppid+"</appid>" + "<body><![CDATA[" + body + "]]></body>" + "<mch_id>"+mch_id+"</mch_id>" + "<nonce_str>"+nonce_str + "</nonce_str>" + "<notify_url>"+notify_url+"</notify_url>" + "<openid>"+openid+"</openid>" + "<out_trade_no>"+order.getCode()+"</out_trade_no>" + "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>" + "<total_fee>"+orderPrice+"</total_fee>" + "<trade_type>"+"JSAPI"+"</trade_type>" + "<sign>"+mysign+"</sign>" + "</xml>"; System.out.println("调试模式_统一下单接口 请求XML数据:" + xml); //调用统一下单接口,并接受返回的结果 String result = PayUtil.httpRequest( "https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", xml); System.out.println("调试模式_统一下单接口 返回XML数据:" + result); //////////////////////////////////////////////////////////////////////////////// // 将解析结果存储在HashMap中 Map map = PayUtil.doXMLParse(result); String return_code = (String) map.get("return_code");//返回状态码 Map<String, Object> response = new HashMap<String, Object>();//返回给小程序端需要的参数 if (return_code.equals("SUCCESS")) { String prepay_id = (String) map.get("prepay_id");//返回的预付单信息 response.put("nonceStr", nonce_str); response.put("package", "prepay_id=" + prepay_id); Long timeStamp = System.currentTimeMillis() / 1000; response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误 //拼接签名需要的参数 String stringSignTemp = "appId=" + apppid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp; //再次签名,这个签名用于小程序端调用wx.requesetPayment方法 String paySign = PayUtil.sign(stringSignTemp, key, "utf-8").toUpperCase(); response.put("paySign", paySign); } response.put("appid", apppid); //////////////////////////////////////微信支付结束///////////////////////////////// //更改订单状态 order.setState(Order.STATE_PAY); orderRepository.save(order); /////////////////////////////////////////////// return CommonSdo.success(response); //CommonSdo我自己定义的返回类 } catch (Exception e) { e.printStackTrace(); } return CommonSdo.error("支付异常,未能支付成功"); } /** * StringUtils工具类方法 * 获取一定长度的随机字符串,范围0-9,a-z * * @param length:指定字符串长度 * @return 一定长度的随机字符串 */ public static String getRandomStringByLength(int length) { String base = "abcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } /** * IpUtils工具类方法 * 获取真实的ip地址 * * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { //多次反向代理后会有多个ip值,第一个ip才是真实ip int index = ip.indexOf(","); if (index != -1) { return ip.substring(0, index); } else { return ip; } } ip = request.getHeader("X-Real-IP"); if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { return ip; } return request.getRemoteAddr(); }
2:
官方小程序支付方法,然后小程序拿到返回的以下参数,即可发起支付
wx.requestPayment({ timeStamp: " ", nonceStr: " ", package: " ", signType: 'MD5', paySign: " ", success: function (res) { })