0
点赞
收藏
分享

微信扫一扫

JAVA微信支付——企业付款(企业向微信用户个人付款、转账)

朱悟能_9ad4 2022-02-17 阅读 130
java微信

ClientCustomSSL.java

package com.weixinpay;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;


/**
 * This example demonstrates how to create secure connections with a custom SSL
 * context.
 */
public class ClientCustomSSL {

    public static String getInSsl(String url,File pkcFile,String storeId, 
            String params,String contentType) 
            throws Exception {
        String text = "";
        // 指定读取证书格式为PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // 读取本机存放的PKCS12证书文件
        FileInputStream instream = new FileInputStream(pkcFile);
        try {
            // 指定PKCS12的密码(商户ID)
            keyStore.load(instream, storeId.toCharArray());
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, storeId.toCharArray()).build();
        // Allow TLSv1 protocol only
        // 指定TLS版本 
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        // 设置httpclient的SSLSocketFactory
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        try {
            HttpPost post = new HttpPost(url);
            StringEntity s = new StringEntity(params,"utf-8");
            if(StringUtils.isBlank(contentType)){
               s.setContentType("application/xml");
            }
            s.setContentType(contentType);
            post.setEntity(s);
            HttpResponse res = httpclient.execute(post);
            HttpEntity entity = res.getEntity();
            text= EntityUtils.toString(entity, "utf-8");
        } finally {
            httpclient.close();
        }
        return text;
    }

}

Config.java

package com.weixinpay;

public class PaymentConfig {
    /*******微信支付参数*********/

    //公众账号ID
    public static final String appid="wxd3e";

    //密钥 key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
    public static final String appKey="abcde";

    //商户号
    public static final String mch_id="15849";

    //转账请求接口地址
    public static final String pay_url="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";


    /**
     * 62个字母和数字,含大小写
     */
    public static final char[] N62_CHARS = {'0', '1', '2', '3', '4', '5', '6',
            '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
            'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
            'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
            'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
            'x', 'y', 'z'};
}

PayUtil.java

package com.weixinpay;

import org.apache.commons.lang.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.*;


public class PayUtil {

    /**
     * UTF-8编码
     */
    public static final String UTF8 = "UTF-8";


    /**
    * 将需要传递给微信的参数转成xml格式
    * @param parameters
    * @return
    */
    public static String assembParamToXml(Map<String,String> parameters){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set<String> es = parameters.keySet();
        List<Object> list=new ArrayList<Object>(es);
        Object[] ary =list.toArray();
        Arrays.sort(ary);
        list=Arrays.asList(ary);
        Iterator<Object> it = list.iterator();
        while(it.hasNext()) {
            String key =  (String) it.next();
            String val=(String) parameters.get(key);
            if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
                sb.append("<"+key+">"+"<![CDATA["+val+"]]></"+key+">");
            }else {
                sb.append("<"+key+">"+val+"</"+key+">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Map parseXMLToMap(String strxml) throws JDOMException, IOException {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\""+UTF8+"\"");
        if(null == strxml || "".equals(strxml)) {
            return null;
        }
        Map m = new HashMap();
        InputStream in = new ByteArrayInputStream(strxml.getBytes(UTF8));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while(it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if(children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v =PayUtil.getChildrenText(children);
            }
            m.put(k, v);
        }
        //关闭流
        in.close();
        return m;
    }

    /**
     * 获取子结点的xml
     * @param children
     * @return String
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if(!children.isEmpty()) {
            Iterator it = children.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if(!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }

    /**
    * 微信支付签名sign
    * @param param
    * @param key
    * @return
    */
    public static String createSign(Map<String, String> param,String key){
        //签名步骤一:按字典排序参数
        List list=new ArrayList(param.keySet());
        Object[] ary =list.toArray();
        Arrays.sort(ary);
        list=Arrays.asList(ary);
        String str="";
        for(int i=0;i<list.size();i++){
            str+=list.get(i)+"="+param.get(list.get(i)+"")+"&";
        }
        //签名步骤二:加上key
        str+="key="+key;
        //步骤三:加密并大写
        str=PayUtil.MD5Encode(str,"utf-8").toUpperCase();
        return str;
    }

    public static String MD5Encode(String origin,String charsetName){
        String resultString=null;
        try{
            resultString=new String(origin);
            MessageDigest md=MessageDigest.getInstance("MD5");
            if(StringUtils.isBlank(charsetName)){
                resultString=byteArrayToHexString(md.digest(resultString.getBytes()));
            }else{
                resultString=byteArrayToHexString(md.digest(resultString.getBytes(charsetName)));
            }
        }catch(Exception e){
        
        }
        return resultString;
    }

    public static String byteArrayToHexString(byte b[]){
        StringBuffer resultSb=new StringBuffer();
        for(int i=0;i<b.length;i++){
            resultSb.append(PayUtil.byteToHexString(b[i]));
        }
        return resultSb.toString();
    }

    public static String byteToHexString(byte b){
        int n=b;
        if(n<0){
            n+=256;
        }
        int d1=n/16;
        int d2=n%16;
        return PayUtil.hexDigits[d1]+PayUtil.hexDigits[d2];
    }

    public static final String hexDigits[]={ "0", "1", "2", "3", "4", "5",  
    "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };


    /**
     * 元转换为分
     * @param amount
     */
    public static String changeY2F(Double amount){    
            String currency =  amount.toString();  
            int index = currency.indexOf(".");    
            int length = currency.length();    
            Long amLong = 0l;    
            if(index == -1){    
                amLong = Long.valueOf(currency+"00");    
            }else if(length - index >= 3){    
                amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));    
            }else if(length - index == 2){    
                amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);    
            }else{    
                amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");    
            }    
            return amLong.toString();    
    }

}

WeixinPay.java

package com.weixinpay;

import org.apache.commons.lang.RandomStringUtils;

import java.io.File;
import java.util.HashMap;
import java.util.Map;


public class WeixinPay {


    /**
     * 企业付款接口  用于企业向微信用户个人付款
     * 目前支持向指定微信用户的openid付款。
     * @param pkcFile  商户证书文件
     * @param orderNo  订单编号
     * @param weixinOpenId  要付款的用户openid
     * @param realname  收款用户姓名
     * @param payAmount 转账金额
     * @param desc  企业付款备注
     * @param ip  ip地址
     * @return
     */
    public static Object[] payToUser(File pkcFile, String orderNo, String weixinOpenId, String realname
            , Double payAmount, String desc, String ip) {
        Map<String, String> paramMap = new HashMap<String, String>();
        // 公众账号appid[必填]
        paramMap.put("mch_appid", PaymentConfig.appid);
        // 微信支付分配的商户号 [必填]
        paramMap.put("mchid", PaymentConfig.mch_id);
        // 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB" [非必填]
        paramMap.put("device_info", "WEB");
        // 随机字符串,不长于32位。 [必填]
        paramMap.put("nonce_str", RandomStringUtils.random(16, Num62.N62_CHARS));

        // 商户订单号,需保持唯一性[必填]
        paramMap.put("partner_trade_no", orderNo);

        // 商户appid下,某用户的openid[必填]
        paramMap.put("openid", weixinOpenId);

        //校验用户姓名选项   NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
        paramMap.put("check_name", "OPTION_CHECK");

        //收款用户姓名,如果check_name设置为FORCE_CHECK,则必填用户真实姓名
        paramMap.put("re_user_name", realname);
        // 企业付款金额,金额必须为整数 单位为分 [必填]
        paramMap.put("amount", PayUtil.changeY2F(payAmount));
        // 企业付款描述信息 [必填]
        paramMap.put("desc", desc);
        // 调用接口的机器Ip地址[必填]
        paramMap.put("spbill_create_ip", ip);
        // 根据微信签名规则,生成签名
        paramMap.put("sign",
                PayUtil.createSign(paramMap, PaymentConfig.appKey));
        // 把参数转换成XML数据格式
        String xmlWeChat = PayUtil.assembParamToXml(paramMap);
        String resXml = "";
        boolean postError = false;
        try {
            resXml = ClientCustomSSL.getInSsl(PaymentConfig.pay_url, pkcFile, PaymentConfig.mch_id
                    , xmlWeChat, "application/xml");
        } catch (Exception e1) {
            postError = true;
            e1.printStackTrace();
        }
        Object[] result = new Object[2];
        result[0] = postError;
        result[1] = resXml;
        return result;
    }



}

//测试

/**
	 * 企业付款到用户个人微信
	 * 简单demo 需要自行完善逻辑
	 * @return
	 */
	public static void main(String[] args) {
		String orderNo = "456961196489211111";
		String weixinOpenId = "RBRyYar0";
		String realname = "李";
		//转账的金额  金额格式转换可以参考 https://www.cnblogs.com/pxblog/p/13186037.html
		Double payAmount = 0.3;
		String desc = "企业付款备注";

		Object result[] = WeixinPay.payToUser( orderNo, weixinOpenId, realname, payAmount, desc);
		String resXml = (String) result[1];
		boolean postError = (Boolean) result[0];
		if (!postError) {
			Map<String, String> map = new HashMap<String, String>();
			try {
				map = PayUtil.parseXMLToMap(resXml);
			} catch (Exception e) {
				e.printStackTrace();
			}
			String returnCode = map.get("return_code");
			if (returnCode.equalsIgnoreCase("FAIL")) {
				//支付失败
				System.err.println( map.get("return_msg"));
			} else if (returnCode.equalsIgnoreCase("SUCCESS")) {
				if (map.get("err_code") != null) {
					//支付失败
					System.err.println( map.get("err_code_des"));
				} else if (map.get("result_code").equalsIgnoreCase(
					"SUCCESS")) {
					//支付成功  paymentNo:微信付款单号  payment_time:付款成功时间
					String paymentNo = map.get("payment_no");
					String payment_time = map.get("payment_time");
					try {
						//如果是体现操作,在这里处理体现订单的状态,把状态转为提现成功

					} catch (Exception e) {
						e.printStackTrace();
					}
					System.err.println("返回到成功的页面");
				}
			}
		}
		System.err.println("返回通信失败的错误页面");
	}
举报

相关推荐

0 条评论