java 企业付款到微信钱包(V2)、银行卡

开通条件。

商户注册超过90天且,连续30天有交易,可以每天支付1元来刷,目前测试可行。随后在微信商户平台 - 产品管理自动开启,然后需要申请。

注意:要有公众号appid才行,但是听说移动应用的appid也可以。

小程序appid与对应的openid也可以,如果非同主体,可以尝试mch_id与appid绑定;

移动应用appid与对应的openid也可以,如果非同主体,可以尝试mch_id与appid绑定;

Attention:如果主体里面有括号,注意英文括号和中文括号区别;

2.此类接口使用场景。

无论是微信还是支付宝,现金红包,单笔转账,企业转账等资金支出类接口都可以用作,活动营销、招新、邀请好友发送奖励、企业内部报销、合伙人团长提现等场景。

注意:

1.微信商户账号需要有余额;

2.根据实际业务,比如发红包,需要做并发和同步锁处理,同时建议在商户平台开启防盗刷处理;

3.调用三方接口,看好官方文档,参数获取的对,传递的对,工具类找的好,基本就ok了;

4.不支持给非实名用户付款,如果报错,请处理,并且展示给前端可理解字

企业付款到微信:

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import com.yx.api.ms.mk.alipay.AlipayConfig;
import com.yx.api.ms.mk.wxpay.MyWXPayConfig;
import com.yx.api.ms.mk.wxpay.WXPayUtil;
import com.yx.api.ms.mk.wxpay.util.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.PublicKey;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Description: 提现
 **/
public class WxWithdrawBank {
    private Logger logger = LoggerFactory.getLogger(TransactionServiceImpl.class);

    @Resource
    private MyWXPayConfig config;

    @Resource
    private WXPay wxPay;

    /**
     * 微信提现到钱包
     * @param request request
     * @return Result
     * @throws Exception Exception
     */
    public Result transferPay(HttpServletRequest request) throws Exception {
        Map<String, String> map = new HashMap<>();
        map.put("mch_appid",config.getAppID());
        map.put("mchid",config.getMchID());
        //随机字符串
        map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
        //本地订单编号
        map.put("partner_trade_no","订单号");
        //openid
//        map.put("openid","oYeUZ6E_9Xafm7NLOdIlRn2uL3x4");
        map.put("openid","微信openid");
        //需要收款人真实姓名
        map.put("check_name","FORCE_CHECK");
//        map.put("check_name","NO_CHECK");
        map.put("re_user_name","收款人姓名");
        //金额
        BigDecimal totalAmount = new BigDecimal("100");
        int amount = new BigDecimal("10").multiply(totalAmount).intValue();
        map.put("amount",amount+"");
        map.put("desc","提现!");
        //IP
        map.put("spbill_create_ip",getClientIpAddress(request));
        map.put("sign", WXPayUtil.generateSignature(map, config.getKey(), WXPayConstants.SignType.MD5));

        //生成交易记录,这一步才调用微信提现接口,上面的是封装参数
        String restxml = HttpUtils.posts(config.getTransfersUrl(), XmlUtil.xmlFormat(map, false));

        Map<String, String> transferInfo  = XmlUtil.xmlParse(restxml);
        logger.error(transferInfo.get("err_code_des"));
        if (CollectionUtil.isNotEmpty(transferInfo) && "SUCCESS".equals(transferInfo.get("result_code"))) {
            // 提现成功,处理业务逻辑
            
            return Result.success(CommonExceptionStatus.ACCEPTED, "提现成功", transactionDTO.getRecId());
        }
        if ( CollectionUtil.isNotEmpty(transferInfo) && "NOTENOUGH".equals(transferInfo.get("err_code"))){
            return Result.failure(CommonExceptionStatus.NOT_SUFFICIENT_FUNDS, "not_sufficient_funds", request.getRequestURI(),request.getMethod());
        }
        logger.error("微信提现钱包失败,请稍后再试");
        return Result.failure(CommonExceptionStatus.UPDATE_FAILURE, "remit_failure", request.getRequestURI(),request.getMethod());
    }

    public static void main(String[] args) throws Exception {
        Map<String, String> map = new HashMap<>();
        //微信支付分配的商户号
        map.put("mch_id","1513745611");
        //随机字符串
        map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
        //签名
        map.put("sign", WXPayUtil.generateSignature(map, "38844f2e2a142b0a8e727512d2911ad9", WXPayConstants.SignType.MD5).toUpperCase());

        //生成交易记录,这一步才调用微信提现接口,上面的是封装参数
        // 将当前的map结合转化成xml格式
        String restxml = HttpUtils.posts("https://fraud.mch.weixin.qq.com/risk/getpublickey", XmlUtil.xmlFormat(map, false));

        Map<String, String> transferInfo  = XmlUtil.xmlParse(restxml);
        System.err.println(transferInfo.get("return_code"));
        System.err.println(transferInfo.get("return_msg"));
        if (CollectionUtil.isNotEmpty(transferInfo) && "SUCCESS".equals(transferInfo.get("result_code"))) {
            System.err.println(transferInfo);
            System.err.println(transferInfo.get("return_code"));
            System.err.println(transferInfo.get("return_msg"));
        }
        System.err.println(transferInfo.get("err_code"));
        System.err.println(transferInfo.get("err_code_des"));
    }

    /**
     * 微信提现到银行卡
     * @param request request
     * @param transactionDTO 交易对象
     * @return Result
     * @throws Exception Exception
     */
    public Result transferPayBank(HttpServletRequest request) throws Exception {
        //需加密的银行账号
        String encBankAcctNo = "银行账号";
        //需加密的银行账户名
        String encBankAcctName = "银行账户名";

        //读取PKCS8密钥文件
        File file = ResourceUtils.getFile("classpath:wxPay/public_key.pem");
        PublicKey pub= RSAUtils.getPubKey(file.toString(),"RSA");
        // rsa是微信付款到银行卡要求我们填充的字符串(Java)
        String rsa = "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING";
        //对银行账号进行加密
        byte[] estr = RSAUtils.encrypt(encBankAcctNo.getBytes("UTF-8"),pub,2048, 11,rsa);
        //并转为base64格式----  调用付款需要传的 银行卡号
        encBankAcctNo = Base64.encode(estr);

        //对银行账号用户名进行加密
        byte[] name = RSAUtils.encrypt(encBankAcctName.getBytes("UTF-8"),pub,2048, 11,rsa);
        //并转为base64格式--调用付款需要传的 用户名
        encBankAcctName =Base64.encode(name);
        Map<String, String> map = new HashMap<>();
        //金额
        BigDecimal totalAmount = new BigDecimal("100");
        int amount = new BigDecimal("10").multiply(totalAmount).intValue();
        map.put("amount",amount+"");
        //收款方开户行
        map.put("bank_code", "开户行号");
        map.put("desc","提现!");
        //收款方银行卡号
        map.put("enc_bank_no", "银行卡号");
        //收款方用户名
        map.put("enc_true_name","用户名");
        //微信支付分配的商户号
        map.put("mch_id",config.getMchID());
        //随机字符串
        map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
        //订单编号
        map.put("partner_trade_no","订单号");
        //签名
        map.put("sign", WXPayUtil.generateSignature(map, config.getKey(), WXPayConstants.SignType.MD5).toUpperCase());

        //生成交易记录,这一步才调用微信提现接口,上面的是封装参数
        // 将当前的map结合转化成xml格式
        String restxml = HttpUtils.posts(config.getTransfersPayBank(), XmlUtil.xmlFormat(map, false));
        Map<String, String> transferInfo  = XmlUtil.xmlParse(restxml);
        if (CollectionUtil.isNotEmpty(transferInfo) && "SUCCESS".equals(transferInfo.get("result_code"))) {
            // 提现成功,进行业务逻辑处理
            
            return Result.success(CommonExceptionStatus.ACCEPTED, "提现成功");
        }
        //错误代码
        logger.error(transferInfo.get("err_code"));
        if ( CollectionUtil.isNotEmpty(transferInfo) && "NOTENOUGH".equals(transferInfo.get("err_code"))){
            //错误代码描述
            logger.error(transferInfo.get("err_code_des"));
            return Result.failure(CommonExceptionStatus.NOT_SUFFICIENT_FUNDS, "not_sufficient_funds", request.getRequestURI(),request.getMethod());
        }
        //错误代码描述
        logger.error(transferInfo.get("err_code_des"));
        logger.error("微信提现到银行卡失败,请稍后再试");
        return Result.failure(CommonExceptionStatus.UPDATE_FAILURE, "remit_failure", request.getRequestURI(),request.getMethod());
    }

    /**
     * 查询企业付款到零钱
     */
    @GetMapping("/wxPay/transferIQuery")
    public Result getTransferInfo(HttpServletRequest request, HttpServletResponse response,
                                  String callback,String order_code) throws Exception {
        Map<String, String> restmap = null;
        Map<String, String> parm = new HashMap<String, String>();
        parm.put("appid", config.getAppID());
        //商户id
        parm.put("mch_id", config.getMchID());
        parm.put("partner_trade_no", order_code);
        parm.put("nonce_str", UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
        parm.put("sign",WXPayUtil.generateSignature(parm, config.getKey(), WXPayConstants.SignType.MD5));

        String restxml = HttpUtils.posts(config.getTransfersPayQuery(), XmlUtil.xmlFormat(parm, true));
        restmap = XmlUtil.xmlParse(restxml);

        if (CollectionUtil.isNotEmpty(restmap) && "SUCCESS".equals(restmap.get("result_code"))) {
            // 订单查询成功 处理业务逻辑
            //logger.info("订单查询:订单" + restmap.get("partner_trade_no") + "支付成功");
            Map<String, String> transferMap = new HashMap<>();
            //商户转账订单号
            transferMap.put("partnerTradeNo", restmap.get("partner_trade_no"));
            //收款微信号
            transferMap.put("openid", restmap.get("openid"));
            //转账金额
            transferMap.put("paymentAmount", restmap.get("payment_amount"));
            //转账时间
            transferMap.put("transferTime", restmap.get("transfer_time"));
            //转账描述
            transferMap.put("desc", restmap.get("desc"));
            return Result.success().setData(transferMap);
        }else {
            if (CollectionUtil.isNotEmpty(restmap)) {
                //logger.info("订单转账失败:" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));
            }
            return Result.success().setData(restmap);
        }
    }
}

企业付款http请求工具:HttpUtils

package com.yx.api.ms.mk.wxpay.util;

import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
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.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.util.ResourceUtils;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Description: 企业付款http请求工具
 **/
public class HttpUtils {

    private static final String DEFAULT_CHARSET = "UTF-8";

    //链接超时时间3秒
    private static final int CONNECT_TIME_OUT = 5000;

    private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().setConnectTimeout(CONNECT_TIME_OUT).build();

    //微信支付ssl证书
    private static SSLContext wx_ssl_context = null;

    /**
     * 证书密码默认是商户号
     */
    private static final String MCH_ID  = "1513745611";

    static{
        InputStream inputStream = null;
        //证书
        //Resource resource = new ClassPathResource("classpath:wxPay/apiclient_cert.p12");
        try {
            File file = ResourceUtils.getFile("classpath:wxPay/apiclient_cert.p12");
            String fileUrl = file.toString();
            inputStream = new FileInputStream(file);
            KeyStore keystore = KeyStore.getInstance("PKCS12");
            //证书密码
            char[] keyPassword = MCH_ID.toCharArray();
            keystore.load(inputStream, keyPassword);
            wx_ssl_context = SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @description 功能描述: get 请求
     * @param url 请求地址
     * @param params 参数
     * @param headers headers参数
     * @return 请求失败返回null
     */
    public static String get(String url, Map<String, String> params, Map<String, String> headers) {

        CloseableHttpClient httpClient = null;
        if (params != null && !params.isEmpty()) {
            StringBuffer param = new StringBuffer();
            boolean flag = true; // 是否开始
            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (flag) {
                    param.append("?");
                    flag = false;
                } else {
                    param.append("&");
                }
                param.append(entry.getKey()).append("=");

                try {
                    param.append(URLEncoder.encode(entry.getValue(), DEFAULT_CHARSET));
                } catch (UnsupportedEncodingException e) {
                    //编码失败
                }
            }
            url += param.toString();
        }

        String body = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();
            HttpGet httpGet = new HttpGet(url);
            response = httpClient.execute(httpGet);
            body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return body;
    }

    /**
     * @description 功能描述: get 请求
     * @param url 请求地址
     * @return 请求失败返回null
     */
    public static String get(String url) {
        return get(url, null);
    }

    /**
     * @description 功能描述: get 请求
     * @param url 请求地址
     * @param params 参数
     * @return 请求失败返回null
     */
    public static String get(String url, Map<String, String> params) {
        return get(url, params, null);
    }

    /**
     * @description 功能描述: post 请求
     * @param url 请求地址
     * @param params 参数
     * @return 请求失败返回null
     */
    public static String post(String url, Map<String, String> params) {
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nameValuePairs = new ArrayList<>();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }

        String body = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));
            response = httpClient.execute(httpPost);
            body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return body;
    }

    /**
     * @description 功能描述: post 请求
     * @param url 请求地址
     * @param s 参数xml
     * @return 请求失败返回null
     */
    public static String post(String url, String s) {
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = new HttpPost(url);
        String body = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();
            httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));
            response = httpClient.execute(httpPost);
            body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return body;
    }

    /**
     * @description 功能描述: post https请求,服务器双向证书验证
     * @param url 请求地址
     * @param params 参数
     * @return 请求失败返回null
     */
    public static String posts(String url, Map<String, String> params) {
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nameValuePairs = new ArrayList<>();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }

        String body = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).setSSLSocketFactory(getSSLConnectionSocket()).build();
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));
            response = httpClient.execute(httpPost);
            body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return body;
    }

    /**
     * @description 功能描述: post https请求,服务器双向证书验证
     * @param url 请求地址
     * @param s 参数xml
     * @return 请求失败返回null
     */
    public static String posts(String url, String s) {
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = new HttpPost(url);
        String body = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).setSSLSocketFactory(getSSLConnectionSocket()).build();
            httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));
            response = httpClient.execute(httpPost);
            body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return body;
    }

    //获取ssl connection链接
    private static SSLConnectionSocketFactory getSSLConnectionSocket() {
        return new SSLConnectionSocketFactory(wx_ssl_context, new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    }
}

银行卡、用户名称加密辅助类:RSAUtils

package com.yx.api.ms.mk.wxpay.util;

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.springframework.util.ResourceUtils;

import javax.crypto.Cipher;
import java.io.*;
import java.lang.reflect.Method;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @Description: 银行卡、用户名称加密辅助类
 **/
public class RSAUtils {
    public static void main(String[] args) throws Exception {

        //加密的银行账号
        String encBankAcctNo = "银行卡号";
        //加密的银行账户名
        String encBankAcctName = "账户名";
  
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凱凱啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值