微信小程序-商户号转账到微信余额

使用条件

 1、商户号(或同主体其他非服务商商户号)已入驻90日

  2、截止今日回推30天,商户号(或同主体其他非服务商商户号)连续不间断保持有交易

  3、 登录微信支付商户平台-产品中心,开通企业付款。

需要去商户平台配置

  1,企业付款到零钱需要证书,需要下载证书

  2,需要设置支付白名单,放开一下ip地址,ip地址是要外网ip,域名不行,只能是ip地址,配置的方法是:账户中心》api安全,把你的外网ip写进去就ok了。

下面直接上代码了。

企业付款到零钱支付常量类,这里需要注意的是证书,证书的位置可以放在,如图所示,这个位置,这样就可以读取到了

微信小程序-商户号转账到微信余额_第1张图片

 

支付常类,企业付款到零钱没有回调地址,可以不写。支付要用到,这里的配置这样写不太好,正确的写发是放在配置文件里面,然后去读配置文件,这里就先这样写了

package com.util;
/**
 * 支付常量类
 */

public class WXPayConstant {
	
	/**
	 * 小程序 appId
	 */
	public static final String APP_ID = "";
	/**
	 * 商户id
	 */
	public static final String MCH_ID = "";
	/**
	 * 支付密钥
	 */
	public static final String PAY_APP_SECRET = "";

	/**
	 * 支付回调地址
	 */
	public static final String PAY_NOTIFY_URL = "";
	
	/**
	 * 统一下单API接口链接
	 */
	public static final String PAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
	/**
	 * 证书名字
	 */
	public static final String CLIENT_CERT_NAME = "cart/apiclient_cert.p12";

	/**
	 * 微信退款接口
	 */
	public static final String WEIXIN_REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";

}

 

 

业务处理类,退款需要2个参数,一个是appendid(openid),一个是money


	
	@Autowired
	private RedisTemplate redisTemplate;
	
	public Object Presentation(String appendid, String money) {
		String key = WXPayConstant.PAY_APP_SECRET;
 
		// 1.0 拼凑企业支付需要的参数
		String appid = WXPayConstant.APP_ID; // 微信公众号的appid
		String mch_id = WXPayConstant.MCH_ID; // 商户号
		//String nonce_str = CreateRandomUtil.getRandom(20);// 随机字符串
		String nonce_str =CreateRandomUtil.getRandom(20);// 随机字符串
		String partner_trade_no="";
		synchronized (this) {
			 partner_trade_no = orderNo("T");// 商户订单号
		}
		String openid = appendid; // 支付给用户openid
		String check_name = "NO_CHECK"; // 是否验证真实姓名呢
		String re_user_name = "KOLO"; // 收款用户姓名(非必须)
		
		BigDecimal tmoney=new BigDecimal("100");
		BigDecimal newtmoney=new BigDecimal(money);
		money=newtmoney.multiply(tmoney).toString();
		
		Integer aaaaaaa= newtmoney.multiply(tmoney).intValue();
		String amount = aaaaaaa.toString(); // 企业付款金额,最少为100,单位为分
		
		String desc = "恭喜你,提现成功"; // 企业付款操作说明信息。必填。
		String spbill_create_ip = "127.0.0.1"; // 用户的ip地址
		// 2.0 生成map集合
	    SortedMap packageParams = new TreeMap();    
		//Map packageParams = new HashMap();
		packageParams.put("mch_appid", appid); // 微信公众号的appid
		packageParams.put("mchid", mch_id); // 商务号
		packageParams.put("nonce_str", nonce_str); // 随机生成后数字,保证安全性
		packageParams.put("partner_trade_no", partner_trade_no); // 生成商户订单号
		packageParams.put("openid", openid); // 支付给用户openid
		packageParams.put("check_name", check_name); // 是否验证真实姓名呢
		packageParams.put("re_user_name", re_user_name);// 收款用户姓名
		packageParams.put("amount", amount); // 企业付款金额,单位为分
		packageParams.put("desc", desc); // 企业付款操作说明信息。必填。
		packageParams.put("spbill_create_ip", spbill_create_ip); // 调用接口的机器Ip地址
 
		try {
            //3.0 签名
		    String sign = XMLUtil.createSign("UTF-8", packageParams,key);  //获取签名  
			packageParams.put("sign", sign);
			// 5.0将当前的map结合转化成xml格式
			//String xml = WXPayUtil.mapToXml(packageParams);
			String xml = XMLUtil.getRequestXml(packageParams);//将请求参数转换成xml类型    
			//String xml = MessageUtil.messageToXML(packageParams);// 打包要发送的xml
			// 6.0获取需要发送的url地址
			String wxUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // 获取退款的api接口
			System.out.println("发送前的xml为:" + xml);
			// 7,向微信发送请求转账请求
			String returnXml = CertHttpUtil.postData(wxUrl, xml, WXPayConstant.MCH_ID, WXPayConstant.CLIENT_CERT_NAME);
			System.out.println("返回的returnXml为:" + returnXml);
			// 8,将微信返回的xml结果转成map格式
			Map returnMap = XMLUtil.doXMLParse(returnXml); 
			
			
			if (returnMap.get("return_code").equals("SUCCESS")&&returnMap.get("return_msg").equals("")) {
				//写你要处理的逻辑,一般是操作数据库,写公司的业务逻辑
				return "退款成功 ";
			
			}
			return "退款失败 ";
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	

/**
	 * 生成订单号
	 * 
	 * @param type
	 *            订单类型
	 * @return
	 */
	private String orderNo(String type) {
		String yyMMdd = type + new SimpleDateFormat("yyMMdd").format(new Date());
		if (!redisTemplate.hasKey(yyMMdd)) {
			redisTemplate.opsForValue().set(yyMMdd, "0", 60 * 60 * 24, TimeUnit.SECONDS);
		}
		Long num = redisTemplate.opsForValue().increment(yyMMdd, 1);
		return yyMMdd + String.format("%05d", num);
	}


 

发送请求转账消息 和加载证书 的util: CertHttpUtil

package com.util;

import java.io.IOException;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
 
import javax.net.ssl.SSLContext;
 
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
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 org.springframework.core.io.ClassPathResource;


public class CertHttpUtil {
	
	//写了
	
	 private static int socketTimeout = 10000;// 连接超时时间,默认10秒
     private static int connectTimeout = 30000;// 传输超时时间,默认30秒
     private static RequestConfig requestConfig;// 请求器的配置
     private static CloseableHttpClient httpClient;// HTTP请求器
  
     /**
      * 通过Https往API post xml数据
      *
      * @param url API地址
      * @param xmlObj 要提交的XML数据对象
     * @param mchId 商户ID
     * @param certPath 证书位置
      * @return
      */
     public static String postData(String url, String xmlObj, String mchId, String certPath) {
         // 加载证书
         try {
             initCert(mchId, certPath);
         } catch (Exception e) {
             e.printStackTrace();
         }
         String result = null;
         HttpPost httpPost = new HttpPost(url);
         // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
         StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
         httpPost.addHeader("Content-Type", "text/xml");
         httpPost.setEntity(postEntity);
         // 根据默认超时限制初始化requestConfig
         requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
         // 设置请求器的配置
         httpPost.setConfig(requestConfig);
         try {
             HttpResponse response = null;
             try {
                 response = httpClient.execute(httpPost);
             } catch (IOException e) {
                 e.printStackTrace();
             }
             HttpEntity entity = response.getEntity();
             try {
                 result = EntityUtils.toString(entity, "UTF-8");
             } catch (IOException e) {
                 e.printStackTrace();
             }
         } finally {
             httpPost.abort();
         }
         return result;
     }
  
     /**
      * 加载证书
      *
      * @param mchId 商户ID
      * @param certPath 证书位置
      * @throws Exception
      */
     private static void initCert(String mchId, String certPath) throws Exception {
         // 证书密码,默认为商户ID
         String key = mchId;
         // 证书的路径
         String path = certPath;
         // 指定读取证书格式为PKCS12
         KeyStore keyStore = KeyStore.getInstance("PKCS12");
         // 读取本机存放的PKCS12证书文件  
         ClassPathResource cp = new ClassPathResource(WXPayConstant.CLIENT_CERT_NAME);
         InputStream instream = cp.getInputStream();
         try {
             // 指定PKCS12的密码(商户ID)
             keyStore.load(instream, key.toCharArray());
         } finally {
             instream.close();
         }
         SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
         SSLConnectionSocketFactory sslsf =
                 new SSLConnectionSocketFactory(sslcontext, new String[] {"TLSv1"}, null,
                         SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
         httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
     }



}

获取随机数的util :

package com.util;

import java.util.Random;

public class CreateRandomUtil {
	public static final String numberChar ="0123456789";

	/**
	 * 根据系统时间获得指定位数的随机数
	*
	 * @return 获得的随机数
	*/
	public static String getRandom() {
	
		Long seed = System.currentTimeMillis();// 获得系统时间,作为生成随机数的种子
	
		StringBuffer sb = new StringBuffer();// 装载生成的随机数
	
		Random random = new Random(seed);// 调用种子生成随机数
	
		for (int i = 0; i < 16; i++) {
	
		sb.append(numberChar.charAt(random.nextInt(numberChar.length())));
		}
	
		return sb.toString();

	}
	public static String getRandom(int w) {
		
		Long seed = System.currentTimeMillis();// 获得系统时间,作为生成随机数的种子
		
		StringBuffer sb = new StringBuffer();// 装载生成的随机数
		
		Random random = new Random(seed);// 调用种子生成随机数
		
		for (int i = 0; i < w; i++) {
			
			sb.append(numberChar.charAt(random.nextInt(numberChar.length())));
		}
		
		return sb.toString();
		
	}

}

MD5加密解密util

package com.util;

import java.security.MessageDigest;

public class MD5Util {
	

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

        return resultSb.toString();    
    }    

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

    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;    
    }    
    
    
    public final static String getMessageDigest(byte[] buffer) {
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(buffer);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }

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



}

XMLUtil

package com.util;

import java.io.ByteArrayInputStream;  
import java.io.IOException;  
import java.io.InputStream;
import java.io.StringReader;
import java.util.HashMap;  
import java.util.Iterator;  
import java.util.List;  
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.xml.sax.InputSource;
import org.jdom2.Document;  
import org.jdom2.Element;  


public class XMLUtil {
	
	 /**  
     * @author chenp 
     * @Description:sign签名  
     * @param characterEncoding  
     *            编码格式  
     * @param parameters  
     *            请求参数  
     * @return  
     */    
    public static String createSign(String characterEncoding, SortedMap packageParams, String API_KEY) {    
        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=" + API_KEY);    
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();    
        return sign;    
    }   
    
    

    /**  
     * @author chenp 
     * @Description:将请求参数转换为xml格式的string  
     * @param parameters  
     *            请求参数  
     * @return  
     */    
    public static String getRequestXml(SortedMap parameters) {    
        StringBuffer sb = new StringBuffer();    
        sb.append("");    
        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 + ">" + "");    
            } else {    
                sb.append("<" + k + ">" + v + "");    
            }    
        }    
        sb.append("");    
        return sb.toString();    
    }    

    
	

	
	/**  
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。  
     * @param strxml  
     * @return  
     * @throws JDOMException  
     * @throws IOException  
     */    
    public static Map doXMLParse(String strxml)  {    
    	
    	try {
    		   strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");    

    	        if(null == strxml || "".equals(strxml)) {    
    	            return null;    
    	        }    

    	        Map m = new HashMap();    
    	        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));    
    	        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 = XMLUtil.getChildrenText(children);    
    	            }    

    	            m.put(k, v);    
    	        }    

    	        //关闭流    
    	        in.close();    

    	        return m;    
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
    	return null;
     
    }
    
    
    
	/**
 * description: 解析微信通知xml
 * 
 * @param xml
 * @return
 * @author ex_yangxiaoyi
 * @see
 */
@SuppressWarnings({ "unused", "rawtypes", "unchecked" })
public static Map parseXmlToList(String xml) {
    Map retMap = new HashMap();
    try {
        StringReader read = new StringReader(xml);
        // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
        InputSource source = new InputSource(read);
        // 创建一个新的SAXBuilder
        SAXBuilder sb = new SAXBuilder();
        // 通过输入源构造一个Document
        Document doc = (Document) sb.build(source);
        Element root = doc.getRootElement();// 指向根节点
        List es = root.getChildren();
        if (es != null && es.size() != 0) {
            for (Element element : es) {
                retMap.put(element.getName(), element.getValue());
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return retMap;

}

    
    /**  
     * 获取子结点的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(XMLUtil.getChildrenText(list));    
                }    
                sb.append(value);    
                sb.append("");    
            }    
        }    

        return sb.toString();    
    }    



}

 

你可能感兴趣的:(java,第三方支付,小程序)