应用场景
微信支付并没有为小程序付款到零钱(企业付款到零钱)给出对应的Demo,所以写出demo供大家参考,大家可以根据自己的需求进行对应的更改以满足实际开发。
企业付款为企业提供付款至用户零钱的能力,支持通过API接口付款,或通过微信支付商户平台(pay.weixin.qq.com)网页操作付款。
应场景:小程序抽取红包,积分换取金额等
更多分布式微服务课程关注:www.majiaxueyuan.com
首先微信相关配置
public class WxPayConfig {// 小程序appidpublic static final String APP_ID = "APP_ID";// APP——Secretpublic static final String APP_SECRET = "APP_SECRET";// 微信支付的商户号public static final String MCH_ID = "MCH_ID";// 微信支付的商户秘钥public static final String KEY = "KEY ";// 支付成功后的服务器回调urlpublic static final String notify_url = "notify_url";// 签名方式,固定值public static final String SIGNTYPE = "MD5";// 交易类型,小程序支付的固定值为JSAPIpublic static final String TRADETYPE = "JSAPI";// 微信统一下单接口地址public static final String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";// 微信直接转账到个人请求public static final String TRANSFOR_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";public static final String STATIC_NUM = "a0A0b1B2c1C3d2D1e3E2f4F3g5G7h4H6i5Ij4J9k5K6l6Lm7M7n8N8o9Op0PqQrRsStTuUv9VwWxXy8YzZ";}证书下载
企业支付的话需要到支付平台去下载证书
微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->证书下载
表4.2:证书文件说明
| 证书附件 | 描述 | 使用场景 | 备注 |
|---|---|---|---|
| pkcs12格式 (apiclient_cert.p12、 | 包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份 | 撤销、退款申请API中调用 | windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户ID(如:10010000) |
| 证书pem格式 (apiclient_cert.pem) | 从apiclient_cert.p12中导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制 | PHP等不能直接使用p12文件,而需要使用pem,为了方便您使用,已为您直接提供 | 您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem |
| 证书密钥pem格式 (apiclient_key.pem) | 从apiclient_key.pem中导出密钥部分的文件,为pem格式 | PHP等不能直接使用p12文件,而需要使用pem,为了方便您使用,已为您直接提供 | 您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem |
使用商户证书
- ◆ apiclient_cert.p12是商户证书文件,除PHP外的开发均使用此证书文件。
- ◆ 商户如果使用.NET环境开发,请确认Framework版本大于2.0,必须在操作系统上双击安装证书apiclient_cert.p12后才能被正常调用。
- ◆ 商户证书调用或安装都需要使用到密码,该密码的值为微信商户号(mch_id)
商户证书安全
1.证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载;
2.建议将证书文件名改为复杂且不容易猜测的文件名;
3.商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。
参数说明
接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
请求需要双向证书。 详见证书使用
请求参数说明
| 字段名 | 变量名 | 必填 | 示例值 | 类型 | 描述 |
|---|---|---|---|---|---|
| 商户账号appid | mch_appid | 是 | wx8888888888888888 | String | 申请商户号的appid或商户号绑定的appid |
| 商户号 | mchid | 是 | 1900000109 | String(32) | 微信支付分配的商户号 |
| 设备号 | device_info | 否 | 013467007045764 | String(32) | 微信支付分配的终端设备号 |
| 随机字符串 | nonce_str | 是 | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | String(32) | 随机字符串,不长于32位 |
| 签名 | sign | 是 | C380BEC2BFD727A4B6845133519F3AD6 | String(32) | 签名,详见签名算法 |
| 商户订单号 | partner_trade_no | 是 | 10000098201411111234567890 | String | 商户订单号,需保持唯一性 (只能是字母或者数字,不能包含有符号) |
| 用户openid | openid | 是 | oxTWIuGaIt6gTKsQRLau2M0yL16E | String | 商户appid下,某用户的openid |
| 校验用户姓名选项 | check_name | 是 | FORCE_CHECK | String | NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名 |
| 收款用户姓名 | re_user_name | 可选 | 王小王 | String | 收款用户真实姓名。 如果check_name设置为FORCE_CHECK,则必填用户真实姓名 |
| 金额 | amount | 是 | 10099 | int | 企业付款金额,单位为分 |
| 企业付款描述信息 | desc | 是 | 理赔 | String | 企业付款操作说明信息。必填。 |
| Ip地址 | spbill_create_ip | 是 | 192.168.0.1 | String(32) | 该IP同在商户平台设置的IP白名单中的IP没有关联,该IP可传用户端或者服务端的IP。 |
这里要注意金额至少为一块(100分)
发送红包请求
(核心代码)
public static Map<String, String> sendRedPacket(String openId, Long money, String orderNo, String ipAddress)throws Exception {// 生成的随机字符串String nonce_str = getRandomStringByLength(32);String totleMoney = money + "";String desc = "现金红包测试";// 组装参数,用户生成统一下单接口的签名Map<String, String> packageParams = new HashMap<String, String>();packageParams.put("mch_appid", WxPayConfig.APP_ID);packageParams.put("mchid", WxPayConfig.MCH_ID);packageParams.put("nonce_str", nonce_str);packageParams.put("partner_trade_no", orderNo);// 商户订单号packageParams.put("openid", openId);packageParams.put("check_name", "NO_CHECK");packageParams.put("amount", totleMoney);packageParams.put("desc", desc);// 支付成功后的回调地址packageParams.put("spbill_create_ip", ipAddress);String prestr = PayUtil.createLinkString(packageParams);// MD5运算生成签名,这里是第一次签名,用于调用统一下单接口String mysign = PayUtil.sign(prestr, WxPayConfig.KEY, "utf-8").toUpperCase();packageParams.put("sign", mysign);String xml = "<xml><mch_appid>" + WxPayConfig.APP_ID + "</mch_appid><mchid>" + WxPayConfig.MCH_ID+ "</mchid><nonce_str>" + nonce_str + "</nonce_str><partner_trade_no>" + orderNo+ "</partner_trade_no><openid>" + openId + "</openid><check_name>NO_CHECK</check_name><amount>"+ totleMoney + "</amount><desc>" + desc + "</desc><spbill_create_ip>" + ipAddress+ "</spbill_create_ip><sign>" + mysign + "</sign></xml>";KeyStore keyStore = KeyStore.getInstance("PKCS12"); // p12证书路径FileInputStream instream = new FileInputStream(new File("C:/Users/Liao/Desktop/dangj/cert/apiclient_cert.p12")); // 微信支付的商户号keyStore.load(instream, "商户号".toCharArray());instream.close(); // 微信支付的商户号SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "商户号".toCharArray()).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();HttpPost httpost = new HttpPost(WxPayConfig.TRANSFOR_URL);httpost.addHeader("Connection", "keep-alive");httpost.addHeader("Accept", "*/*");httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");httpost.addHeader("Host", "api.mch.weixin.qq.com");httpost.addHeader("X-Requested-With", "XMLHttpRequest");httpost.addHeader("Cache-Control", "max-age=0");httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");httpost.setEntity(new StringEntity(xml, "UTF-8"));CloseableHttpResponse response = httpclient.execute(httpost);HttpEntity entity = response.getEntity();String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");// 打印返回慘呼System.out.println(JSON.toJSONString(jsonStr));EntityUtils.consume(entity);return null;}
PayUtils签名算法
public class PayUtil {/** * 签名字符串 * * @param text需要签名的字符串 * @param key * 密钥 * @param input_charset编码格式 * @return 签名结果 */public static String sign(String text, String key, String input_charset) {text = text + "&key=" + key;return DigestUtils.md5Hex(getContentBytes(text, input_charset));}/** * 签名字符串 * * @param text需要签名的字符串 * @param sign * 签名结果 * @param key密钥 * @param input_charset * 编码格式 * @return 签名结果 */public static boolean verify(String text, String sign, String key, String input_charset) {text = text + "&key=" + key;String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));if (mysign.equals(sign)) {return true;} else {return false;}}}随机数生成方法
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();}
调用发送红包
public static void main(String[] args) {try {sendRedPacket("openId", 100L, "orderNo", "192.168.0.1");} catch (Exception e) {e.printStackTrace();}}
错误信息处理
如果出现CA证书错误,查看证书路径和支付商户号是否正确
错误NOAUTH,提示产品权限验证失败。需要到微信支付平台->产品中心->企业付款到零钱,开通企业付款到零钱,开通需求:微信支付商户后台需要90天、连续正常交易流水30天,才可以申请开通“企业付款到零钱”产品。
更多的错误信息点击微信支付官方链接查看
https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2













