微信企业转账相比支付和退款,相关的文章少很多。下面笔者把转账的开发流程写下来,大家不要心急耐心的看下去照着做参考一定可以实现。
做之前希望大家花一点时间看看微信的官方文档,如果看过了请略过。 微信企业付款官方文档,企业付款需要你的商户号去开通这个功能,相比支付和退款企业付款是需要一点前提条件的。
下面展开代码讲解:
首先做企业付款我们要先get到用户的openID这个id是每个用户独有的。
String openid = request.getParameter("openid"); // 用户的openid重要参数
if (!openid.equals("") && openid != null) {
}
我在方法的开始就做了判断是否get到openId,拿到openId之后我们开始给其他付款需要的参数进行赋值。
String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
InetAddress ia = InetAddress.getLocalHost();
String ip = ia.getHostAddress(); // 获取本机IP地址
String uuid = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");// 随机获取UUID
String appid = Configure.getAppID();// 微信分配的公众账号ID(企业号corpid即为此appId)
String mchid = Configure.getMch_id();// 微信支付分配的商户号
String partner_trade_no = RandCharsUtils.getOutTradeNo();
int amount = 100; // 微信转账金额(最少1元)
String desc = "测试"; // 付款操作说明信息
URL是微信官方提供的付款接口,amount则是转账的金额1表示1分钱,转账最少需要一元也就是100。
SortedMap<Object, Object> signParams = new TreeMap<Object, Object>();
signParams.put("mch_appid", appid); // 微信分配的公众账号ID(企业号corpid即为此appId)
signParams.put("mchid", mchid);// 微信支付分配的商户号
signParams.put("nonce_str", uuid); // 随机字符串,不长于32位
signParams.put("partner_trade_no", partner_trade_no); // 商户订单号,需保持唯一性
signParams.put("openid", openid); // 商户appid下,某用户的openid
signParams.put("check_name", "NO_CHECK"); // NO_CHECK:不校验真实姓名
// FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账)
// OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功)
signParams.put("amount", amount); // 企业付款金额,单位为分
signParams.put("desc", desc); // 企业付款操作说明信息。必填。
signParams.put("spbill_create_ip", ip); // 调用接口的机器Ip地址
然后把赋值的参数保存在SortedMap里面等下签名加密会用到。
String sign = WXSignUtils.createSign("UTF-8", signParams);
// sign = createSign("UTF-8", signParams);
// System.out.println(sign);
String data = "<xml><mch_appid>";
data += appid + "</mch_appid><mchid>"; // APPID
data += mchid + "</mchid><nonce_str>"; // 商户ID
data += uuid + "</nonce_str><partner_trade_no>"; // 随机字符串
data += partner_trade_no + "</partner_trade_no><openid>"; // 订单号
data += openid + "</openid><check_name>NO_CHECK</check_name><amount>"; // 是否强制实名验证
data += amount + "</amount><desc>"; // 企业付款金额,单位为分
data += desc + "</desc><spbill_create_ip>"; // 企业付款操作说明信息。必填。
data += ip + "</spbill_create_ip><sign>";// 调用接口的机器Ip地址
data += sign + "</sign></xml>";// 签名
这是签名的部分,签名之后的数据和之前上面赋值的数据一定要按照这个xml的格式保存起来不然你发送给官方api是不认的,之前我做的时候一直付款失败就是因为签名的方法出了问题。
public static String createSign(String characterEncoding, Map<Object, Object> parameters){
StringBuffer sb = new StringBuffer();
Set<Entry<Object, Object>> es = parameters.entrySet();
Iterator<Entry<Object, Object>> it = es.iterator();
while (it.hasNext()) {
Entry<Object, Object> entry = it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + Configure.getKey());
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
这个是我签名的方法,大家可以直接复制拿去用就好。
<xml>
<mch_appid>wxe062425f740c30d8</mch_appid>
<mchid>10000098</mchid>
<nonce_str>3PG2J4ILTKCH16CQ2502SI8ZNMTM67VS</nonce_str>
<partner_trade_no>100000982014120919616</partner_trade_no>
<openid>ohO4Gt7wVPxIT1A9GjFaMYMiZY1s</openid>
<check_name>FORCE_CHECK</check_name>
<re_user_name>张三</re_user_name>
<amount>100</amount>
<desc>节日快乐!</desc>
<spbill_create_ip>10.2.3.10</spbill_create_ip>
<sign>C97BDBACF37622775366F38B629F45E3</sign>
</xml>
这是生成的签名,可以对比一下自己生成的签名有没有少东西或者格式不正确。
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File(Configure.getUrl())); // 从配置文件里读取证书的路径信息
keyStore.load(instream, mchid.toCharArray());// 证书密码是商户ID
instream.close();
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchid.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" },
null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
企业付款需要有登陆商户号下载的安全证书,这个证书的有效期是半年,我们下载下来之后把证书起来用的时候直接引用证书URL即可。
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
HttpPost httpost = new HttpPost(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(data, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("请求返回的数据为:" + jsonStr);
EntityUtils.consume(entity);
这一段是把数据发送给官方api的代码赋值即用。
Document dom = DocumentHelper.parseText(jsonStr);
Element root = dom.getRootElement();
String returnCode = root.element("result_code").getText(); // 获取返回代码
if (StringUtils.equals(returnCode, "SUCCESS")) { // 判断返回码为成功还是失败
String payment_no = root.element("payment_no").getText(); // 获取支付流水号
String payment_time = root.element("payment_time").getText(); // 获取支付时间
map.put("state", returnCode);
map.put("payment_no", payment_no);
map.put("payment_time", payment_time);
return map;
} else {
String err_code = root.element("err_code").getText(); // 获取错误代码
String err_code_des = root.element("err_code_des").getText();// 获取错误描述
map.put("state", returnCode);// state
map.put("err_code", err_code);// err_code
map.put("err_code_des", err_code_des);// err_code_des
return map;
}
然后通过Document 把返回的字符串解析成DOM节点,通过返回数据的return_code来判断api是否执行成功。
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[]]></return_msg>
<mch_appid><![CDATA[wxec38b8ff840bd989]]></mch_appid>
<mchid><![CDATA[10013274]]></mchid>
<device_info><![CDATA[]]></device_info>
<nonce_str><![CDATA[lxuDzMnRjpcXzxLx0q]]></nonce_str>
<result_code><![CDATA[SUCCESS]]></result_code>
<partner_trade_no><![CDATA[10013574201505191526582441]]></partner_trade_no>
<payment_no><![CDATA[1000018301201505190181489473]]></payment_no>
<payment_time><![CDATA[2015-05-19 15:26:59]]></payment_time>
</xml>
这个是调用成功返回的xml。
企业付款的流程就是这样,如果有不懂的可以下载源码:微信企业付款源码