需要用户绑定微信,获取用户openid,通过openid调取微信接口企业付款到零钱接口:

package com.framework.loippi.plugins.wxapppay.withdrawal;

import com.framework.loippi.cache.ConfigCache;

import com.framework.loippi.plugins.wxapppay.MD5;

import com.framework.loippi.plugins.wxapppay.MD5Util;

import org.apache.commons.codec.digest.DigestUtils;

import org.apache.http.HttpEntity;

import org.apache.http.client.config.RequestConfig;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClients;

import org.apache.http.ssl.SSLContexts;

import org.apache.http.util.EntityUtils;

import org.jdom.Document;

import org.jdom.input.SAXBuilder;

import org.springframework.util.ResourceUtils;

import javax.net.ssl.SSLContext;

import java.io.*;

import java.math.BigDecimal;

import java.security.KeyStore;

import java.util.*;

public class WeChatWithdrawalUtil {

private static final String TRANS_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";

// 微信商户appkey

private static String appKey = ConfigCache.getConfig("wx.pay.key");

// 微信商户证书路径

private static String certPath = ConfigCache.getConfig("wx.pay.ssl.pkcs12File");

// 与商户号关联应用(如微信公众号/小程序)的APPID

private static String mchAppId = ConfigCache.getConfig("wx.app.appId");

// 微信支付分配的商户号

private static String mchId = ConfigCache.getConfig("wx.pay.mchId");

// 商户名称, 如'XXX服务号'

private static String mchName = "顺路汽车养护平台";

//证书密码

private static String sslPassword = ConfigCache.getConfig("wx.pay.ssl.password");

// 请求器的配置

private static RequestConfig requestConfig;

// 连接超时时间,默认10秒

private static int socketTimeout = 10000;

// 传输超时时间,默认30秒

private static int connectTimeout = 30000;

/**

*微信提现

* @param partnerTradeNo 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有其他字符) 必填

* @param openid 用户的openid 必填 用户提现需要判断是小程序还是APP,小程序传小程序openid,app传微信openId(app登录使用)

* @param amount 付款金额 单位为元 必填

* @param desc 付款备注 必填

* @return result 返回结果列子(是一个xml字符串):

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

* 判断 失败:result.contains("CDATA[FAIL]") 返回true 失败 false成功

* SAXBuilder saxBuilder = new SAXBuilder();

* Document doc = saxBuilder.build(new StringReader(result));

* 获取错误原因:return doc.getRootElement().getChild("err_code_des").getValue();

* 成功 获取交易单号:return doc.getRootElement().getChild("payment_no").getValue();

*/

public static String doTransfers(String partnerTradeNo, String openid, BigDecimal amount, String desc){

String result ="success";

try

{

String nonceStr = genNonceStr();

// 1.计算参数签名

SortedMap parameters = new TreeMap();

parameters.put("amount", amount.multiply(new BigDecimal("100")).intValue()+"");

parameters.put("check_name", "NO_CHECK");

parameters.put("desc", desc);

parameters.put("mchid", mchId);

parameters.put("mch_appid", mchAppId);

parameters.put("nonce_str", nonceStr);

parameters.put("openid", openid);

parameters.put("partner_trade_no", partnerTradeNo);

parameters.put("sign", createSign(parameters, appKey));

String data = SortedMaptoXml(parameters);

// data = new String(data.getBytes("gbk"), "utf-8");

// 3.加载证书请求接口

System.out.println(data);

result = weChatWithdrawal(data);

System.out.println(result);

if(result.contains("CDATA[FAIL]")){

SAXBuilder saxBuilder = new SAXBuilder();

Document doc = saxBuilder.build(new StringReader(result));

return doc.getRootElement().getChild("err_code_des").getValue();

}

}

catch (Exception e)

{

e.printStackTrace();

return "微信提现失败";

}

return result;

}

private static String createLinkString(String partnerTradeNo, String openid, BigDecimal amount, String desc, String nonceStr)

{

// 微信签名规则 https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=4_3

Map paramMap = new HashMap();

paramMap.put("mch_appid", mchAppId);

paramMap.put("mchid", mchId);

paramMap.put("openid", openid);

paramMap.put("amount", amount);

paramMap.put("check_name", "NO_CHECK");

paramMap.put("desc", desc);

paramMap.put("partner_trade_no", partnerTradeNo);

paramMap.put("nonce_str", nonceStr);

List keys = new ArrayList(paramMap.keySet());

Collections.sort(keys);

String prestr = "";

for (int i = 0; i < keys.size(); i++ )

{

String key = keys.get(i);

Object value = (Object)paramMap.get(key);

if (i == keys.size() - 1)

{// 拼接时,不包括最后一个&字符

prestr = prestr + key + "=" + value;

}

else

{

prestr = prestr + key + "=" + value + "&";

}

}

return prestr;

}

/**

* 证书使用

* 微信提现

*/

@SuppressWarnings("deprecation")

public static String weChatWithdrawal(String data) throws Exception {

KeyStore keyStore = KeyStore.getInstance("PKCS12");

StringBuffer pkcsPath = new StringBuffer();

pkcsPath.append("classpath:").append(certPath);

System.out.println("certPath"+certPath);

InputStream instream = null;

try {

instream = ResourceUtils.getURL(pkcsPath.toString()).openStream();

} catch (IOException var10) {

}

if (instream == null) {

return null;

}

String result = "";

try {

keyStore.load(instream, sslPassword.toCharArray());

} finally {

instream.close();

}

// Trust own CA and all self-signed certs

SSLContext sslcontext = SSLContexts.custom()

.loadKeyMaterial(keyStore, sslPassword.toCharArray())

.build();

// Allow TLSv1 protocol only

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(

sslcontext,

new String[]{"TLSv1"},

null,

SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

CloseableHttpClient httpclient = HttpClients.custom()

.setSSLSocketFactory(sslsf)

.build();

try {

HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");

StringEntity entitys = new StringEntity(data,"UTF-8");

httppost.setEntity((HttpEntity) entitys);

// 根据默认超时限制初始化requestConfig

requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();

// 设置请求器的配置

httppost.setConfig(requestConfig);

CloseableHttpResponse response = httpclient.execute(httppost);

try {

HttpEntity entity = response.getEntity();

result = EntityUtils.toString(entity,"UTF-8");

} finally {

response.close();

}

} finally {

httpclient.close();

}

return result;

}

/**

* 生成32位随机数字

*/

public static String genNonceStr() {

Random random = new Random();

return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());

}

/**

* 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。

*/

public static String createSign(SortedMap packageParams, String AppKey) {

StringBuffer sb = new StringBuffer();

Set es = packageParams.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 (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {

sb.append(k + "=" + v + "&");

}

}

sb.append("key=" + AppKey);

String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();

return sign;

}

/**

* @param params

* @Author: WQY

* @Description:请求值转换为xml格式 SortedMap转xml

* @Date: 2017-9-7 17:18

*/

private static String SortedMaptoXml(SortedMap params) {

StringBuilder sb = new StringBuilder();

Set es = params.entrySet();

Iterator it = es.iterator();

sb.append("\n");

while (it.hasNext()) {

Map.Entry entry = (Map.Entry) it.next();

String k = (String) entry.getKey();

Object v = entry.getValue();

sb.append("");

sb.append(v);

sb.append("" + k + ">\n");

}

sb.append("");

return sb.toString();

}

public static void main(String[] args) {

try {

String results = WeChatWithdrawalUtil.doTransfers("20200921111523187","oZb9e5YIbMnqN1bSDoOVY3O7ITLY",new BigDecimal("1"),"");

System.out.println(results);

}catch(Exception e){

e.printStackTrace();

}

}

}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐