java-微信--企业向个人付款
功能描述:在微信公众号H5 用户赚取的金额 提现到微信用户个人钱包里;
实现原理:调用微信企业向个人付款接口 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
通过openId 和appId绑定用户.
开通企业向个人付款功能 必须要满足:1,商户号已入驻90日, 2,商户号有30天连续正常交易
需要的参数:
商户账号appid | mch_appid |
微信公众号配置里可以看到
商户号 | mchid |
随机字符串 | nonce_str |
String nonce_str = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");// 随机获取UUID
商户订单号 | partner_trade_no |
(只能是字母或者数字,不能包含有符号)
String fsNO = GenerateKeyNO.generate("FS");
String partner_trade_no = fsNO;
/**
* 生成订单号,格式:XX(前缀) + yyyyMMddHHmmss + 10位数
* @param prefix
* @return
*/
public static String generate(String prefix) {
synchronized(locker) {
if (sn == 999999999) {
sn = 0;
} else {
sn ++;
}
String str = String.format("%010d", sn);
return prefix + sdf.format(new Date()) + str;
}
}
用户openid | openid |
如何获取openid请参考我的另一篇文章
校验用户姓名选项 | check_name |
FORCE_CHECK:强校验真实姓名
金额 | amount |
String.valueOf((int)(amount*100)
企业付款描述信息 | desc |
Ip地址 | spbill_create_ip |
/**
*
* 功能描述:获取真实的IP地址
* @param request
* @return
* @author guoyx
*/
public static String getIpAddr(HttpServletRequest request)
{
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getRemoteAddr();
}
if (!isnull(ip) && ip.contains(","))
{
String[] ips = ip.split(",");
ip = ips[ips.length - 1];
}
//转换IP 格式
if(!isnull(ip)){
ip=ip.replace(".", "_");
}
return ip;
}
签名 | sign |
SortedMap<Object, Object> signParams = new TreeMap<Object, Object>();
signParams.put("mch_appid", mch_appid);
// 微信分配的公众账号ID(企业号corpid即为此appId)
signParams.put("mchid", mchid);// 微信支付分配的商户号
signParams.put("nonce_str", nonce_str);
// 随机字符串,不长于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:强校验真实姓名
signParams.put("amount", String.valueOf((int)(amount*100))); // 企业付款金额,单位为分
signParams.put("desc", desc); // 企业付款操作说明信息。必填。
signParams.put("spbill_create_ip", spbill_create_ip); // 调用接口的机器Ip地址
String sign = PayCommonUtil.createSign("UTF-8", signParams,key); //生成支付签名,要采用URLENCODER的原始值进行MD5算法!
/**
* @author
* @date 2016-4-22
* @Description:sign签名
* @param characterEncoding
* 编码格式
* @param parameters
* 请求参数
* @return
*/
public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
StringBuffer sb = new StringBuffer();
@SuppressWarnings("rawtypes")
Set es = packageParams.entrySet();
@SuppressWarnings("rawtypes")
Iterator it = es.iterator();
while (it.hasNext()) {
@SuppressWarnings("rawtypes")
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
public
static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString;
}
把参数封闭成XML格式
String requestXML = PayCommonUtil.getRequestXml(signParams);//封闭成XML格式
/**
* @author
* @date 2016-4-22
* @Description:将请求参数转换为xml格式的string
* @param parameters
* 请求参数
* @return
*/
@SuppressWarnings("rawtypes")
public static String getRequestXml(SortedMap<Object, Object> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
} else {
sb.append("<" + k + ">" + v + "</" + k + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
调用微信企业向个人付款接口
String jsonStr = HttpUtil.jsonStr(requestXML); //调用微信企业向个人付款接口
下面操作 调用微信需要的证书 证书在微信商户平台下载 java只用到apiclient_cert.p12这个证书 支付必须要有证书
/**
* 调用微信企业向个人付款接口
*/
public static String jsonStr (String requestXML) throws Exception{
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File(PropertiesHandler.getConfigValue("phoen.addr.url").toString())); // 从配置文件里读取证书的路径信息
String mchid = PropertiesHandler.getConfigValue("phoen.mch.id").toString(); // 商业号
keyStore.load(instream, mchid.toCharArray());// 证书密码是商户ID
instream.close();
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchid.toCharArray()).build();
@SuppressWarnings("deprecation")
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(PropertiesHandler.getConfigValue("ufdoder.url").toString()); //请求微信地址
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(requestXML, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
return jsonStr;
}
如果参数都对的上的话 就可以见到如下见面