微信 企业付款到余额 开发 教程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chq00788/article/details/83239196

官方教程链接

开发流程概述

  1. 开通企业付款到余额功能
  2. 去商户后台获取商户账号appid、商户号、证书
  3. 生成签名
  4. 生成请求XML
  5. 向微信请求付款
  6. 付款结果分析保存

1、开通企业付款到余额功能

可以参照官方教程

2、获取商户相关信息

方法自行百度

3、生成签名和请求XML

生成签名的官方教程链接
下面是具体的方法

/**
     * 生成请求XML
     * @param code   订单编号
     * @param openid 微信用户的openid
     * @param amount 提现金额(分)
     * @return
     */
private String createXml(String code, String openid, String amount) {
        String[] arr = new String[9];
        arr[0] = "mch_appid=" + APP_ID;  					//商户账号appid
        arr[1] = "mchid=" + MCH_ID;							//商户号
        arr[2] = "nonce_str=" + NONCE_STR;			//随机字符串
        arr[3] = "partner_trade_no=" + code; 				//订单编号
        arr[4] = "openid=" + openid;							//用户openid
        arr[5] = "check_name=NO_CHECK";				//NO_CHECK:不校验真实姓名
        arr[6] = "amount=" + amount;//金额
        arr[7] = "desc=企业付款到余额";						//企业付款备注
        arr[8] = "spbill_create_ip=192.168.**.****";		//Ip地址
        Arrays.sort(arr);
        String param = "";
        for (int i = 0; i < arr.length; i++) {
            param += arr[i] + "&";
        }
        param += "key=569C626880EF3EFFBB91A1E138EEC150"; //API密钥
        String sign = MD5Util.MD5Encode(param, null).toUpperCase();
        String xml = StringUtils.join(
                "<xml>",
                "<mch_appid>" + APP_ID + "</mch_appid>",
                "<mchid>" + MCH_ID + "</mchid>",
                "<nonce_str>" + NONCE_STR + "</nonce_str>",
                "<partner_trade_no>" + code + "</partner_trade_no>",
                "<openid>" + openid + "</openid>",
                "<check_name>NO_CHECK</check_name>",
                "<amount>" + amount + "</amount>",
                "<desc>景芝云店余额提现</desc>",
                "<spbill_create_ip>192.168.**.****</spbill_create_ip>",
                "<sign>" + sign + "</sign>",
                "</xml>"
        );
        return xml;
    }

加密算法

import java.security.MessageDigest;

public class MD5Util {
    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;
    }

4、向微信请求付款

String xml = createXml(code, wechatUser.getOpenId(), String.valueOf(payAmount));
ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
/**
* URL:请求路径
*xml:请求参数
*CERT_PATH:证书路径(服务器绝对路径)
*MCH_ID:商户号
*/
String result = clientCustomSSL.doPay(URL, xml, CERT_PATH, MCH_ID);

请求方法

public class ClientCustomSSL {
    /**
     * 企业付款到余额
     * @param url
     * @param data
     * @return
     * @throws Exception
     */
    public String doPay(String url, String data,String sslcertPath,String mch_id) throws Exception {
        /**
         * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
         */

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        /**
         *此处要改
         *wxconfig.SSLCERT_PATH : 指向你的证书的绝对路径,带着证书去访问
         */

        FileInputStream instream = new FileInputStream(new File(sslcertPath));//P12文件目录
        try {
            /**
             * 此处要改
             *
             * 下载证书时的密码、默认密码是你的MCHID mch_id
             * */
            keyStore.load(instream, mch_id.toCharArray());//这里写密码
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        /**
         * 此处要改
         * 下载证书时的密码、默认密码是你的MCHID mch_id
         * */
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, mch_id.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 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);
            try {
                HttpEntity entity = response.getEntity();

                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}

5、付款结果分析保存

EnterpriceToCustomer refundResult = parseXmlToMapEnterpriceToCustomer(result);
if (SUCCESS.equalsIgnoreCase(refundResult.getResult_code()) && SUCCESS.equalsIgnoreCase(refundResult.getReturn_code())) {
            //8表示成功
        } else {
            //9 表示失败
        }

返回结果实体类

/**
 * 企业 付款到 客户 结果 实体类
 *
 * @author CHQ
 * @create 2018-10-19 18:56
 **/
public class EnterpriceToCustomer {

    /*	<xml>
        <return_code><![CDATA[SUCCESS]]></return_code>
		<return_msg><![CDATA[]]></return_msg>
		<mchid><![CDATA[1488323162]]></mchid>
		<nonce_str><![CDATA[o9fcpfvqow1aks48a2omvayu1ne7c709]]></nonce_str>
		<result_code><![CDATA[SUCCESS]]></result_code>
		<partner_trade_no><![CDATA[xvuct0087w4t1dpr87iqj98w5f71ljae]]></partner_trade_no>
		<payment_no><![CDATA[1000018301201801163213961289]]></payment_no>
		<payment_time><![CDATA[2018-01-16 14:52:16]]></payment_time>
		</xml>
	*/
    private String return_code;
    private String return_msg;
    private String mchid;
    private String nonce_str;
    private String result_code;
    private String partner_trade_no;
    private String payment_no;
    private String payment_time;

    /*
     * 支付错误时,返回的代码
     *  key是:return_code,值是:SUCCESS
        key是:return_msg,值是:支付失败
        key是:mch_appid,值是:wx49c22ad731b679c3
        key是:mchid,值是:1488323162
        key是:result_code,值是:FAIL
        key是:err_code,值是:AMOUNT_LIMIT
        key是:err_code_des,值是:付款金额超出限制。低于最小金额1.00元或累计超过20000.00元。
     *
     */
    private String err_code;

    private String err_code_des;

    public String getErr_code() {
        return err_code;
    }

    public void setErr_code(String errCode) {
        err_code = errCode;
    }

    public String getErr_code_des() {
        return err_code_des;
    }

    public void setErr_code_des(String errCodeDes) {
        err_code_des = errCodeDes;
    }

    public String getReturn_code() {
        return return_code;
    }

    public void setReturn_code(String returnCode) {
        return_code = returnCode;
    }

    public String getReturn_msg() {
        return return_msg;
    }

    public void setReturn_msg(String returnMsg) {
        return_msg = returnMsg;
    }

    public String getMchid() {
        return mchid;
    }

    public void setMchid(String mchid) {
        this.mchid = mchid;
    }

    public String getNonce_str() {
        return nonce_str;
    }

    public void setNonce_str(String nonceStr) {
        nonce_str = nonceStr;
    }

    public String getResult_code() {
        return result_code;
    }

    public void setResult_code(String resultCode) {
        result_code = resultCode;
    }

    public String getPartner_trade_no() {
        return partner_trade_no;
    }

    public void setPartner_trade_no(String partnerTradeNo) {
        partner_trade_no = partnerTradeNo;
    }

    public String getPayment_no() {
        return payment_no;
    }

    public void setPayment_no(String paymentNo) {
        payment_no = paymentNo;
    }

    public String getPayment_time() {
        return payment_time;
    }

    public void setPayment_time(String paymentTime) {
        payment_time = paymentTime;
    }

    @Override
    public String toString() {
        return "EnterpriceToCustomer [err_code=" + err_code + ", err_code_des="
                + err_code_des + ", mchid=" + mchid + ", nonce_str="
                + nonce_str + ", partner_trade_no=" + partner_trade_no
                + ", payment_no=" + payment_no + ", payment_time="
                + payment_time + ", result_code=" + result_code
                + ", return_code=" + return_code + ", return_msg=" + return_msg
                + "]";
    }

结果解析方法

/**
     * 下面是需要通过跟节点,找找到对应的类属性,手动把它set进去。因此API返回的参数不一样。需要写每个返回的Bean。
     * 解析企业支付申请
     * 解析的时候自动去掉CDMA
     *
     * @param xml
     */
    public static EnterpriceToCustomer parseXmlToMapEnterpriceToCustomer(String xml) {
        EnterpriceToCustomer enterpriceToCustomer = new EnterpriceToCustomer();
        try {
            StringReader read = new StringReader(xml);
            // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
            InputSource source = new InputSource(read);
            // 创建一个新的SAXBuilder
            SAXBuilder sb = new SAXBuilder();
            // 通过输入源构造一个Document
            Document doc;
            doc = (Document) sb.build(source);

            Element root = doc.getRootElement();// 指向根节点
            List<Element> list = root.getChildren();

            if (list != null && list.size() > 0) {
                for (Element element : list) {
                    System.out.println("key是:" + element.getName() + ",值是:" + element.getText());
                    if ("return_code".equals(element.getName())) {
                        enterpriceToCustomer.setReturn_code(element.getText());
                    }

                    if ("return_msg".equals(element.getName())) {
                        enterpriceToCustomer.setReturn_msg(element.getText());
                    }

                    if ("mchid".equals(element.getName())) {
                        enterpriceToCustomer.setMchid(element.getText());
                    }

                    if ("nonce_str".equals(element.getName())) {
                        enterpriceToCustomer.setNonce_str(element.getText());
                    }
                    if ("result_code".equals(element.getName())) {
                        enterpriceToCustomer.setResult_code(element.getText());
                    }
                    if ("partner_trade_no".equals(element.getName())) {
                        enterpriceToCustomer.setPartner_trade_no(element.getText());
                    }
                    if ("payment_no".equals(element.getName())) {
                        enterpriceToCustomer.setPayment_no(element.getText());
                    }
                    if ("payment_time".equals(element.getName())) {
                        enterpriceToCustomer.setPayment_time(element.getText());
                    }
                    if ("err_code".equals(element.getName())) {
                        enterpriceToCustomer.setErr_code(element.getText());
                    }
                    if ("err_code_des".equals(element.getName())) {
                        enterpriceToCustomer.setErr_code_des(element.getText());
                    }

                }
            }
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return enterpriceToCustomer;
    }

如果正确会返回如下信息

<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[]]></return_msg>
<mch_appid><![CDATA[wxc496d2a]]></mch_appid>
<mchid><![CDATA[10478671]]></mchid>
<nonce_str><![CDATA[5K8264ILTTCU16CQ2NMTM67VS]]></nonce_str>
<result_code><![CDATA[SUCCESS]]></result_code>
<partner_trade_no><![CDATA[TX154000445301]]></partner_trade_no>
<payment_no><![CDATA[100001830129966]]></payment_no>
<payment_time><![CDATA[2018-10-21 09:04:23]]></payment_time>
</xml>

如果按照上面的方法应该能成功

参考文章:
https://blog.csdn.net/xiaozhegaa/article/details/79178751
https://blog.csdn.net/xiaozhegaa/article/details/79127283

猜你喜欢

转载自blog.csdn.net/chq00788/article/details/83239196