微信企业付款到零钱(发红包)

最近在做微信用户提现功能用到了微信的企业付款到零钱,做简单记录
微信开发者文档->企业付款
开发之前需要获得的重要信息

  1. 商户号mchid:微信支付分配的商户号
  2. 商户账号appid
  3. 在有效期内的API证书:微信商户平台(pay.weixin.qq.com)–>账户中心–>账户设置–>API安全

开发步骤
在这里插入图片描述
在这里插入图片描述
使用的工具类,有获取签名和转换参数的方法



import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WxUtils {
	
	private static Logger logger = (Logger) LoggerFactory.getLogger(WxUtils.class);
	
	/**
	 * 生成随机数
	 * <p>
	 * 算法参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
	 * </p>
	 * 
	 * @return 随机数字符串
	 */
	public static String createNonceStr() {
		SecureRandom random = new SecureRandom();
		int randomNum = random.nextInt();
		return Integer.toString(randomNum);
	}

	/**
	 * 生成签名,用于在微信支付前,获取预支付时候需要使用的参数sign
	 * <p>
	 * 算法参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
	 * </p>
	 * 
	 * @param map 需要发送的所有数据设置为的Map
	 * @return 签名sign
	 */
	public static String createSign(Map<String, Object> map,String parKey) {
		String signValue = "";
		String stringSignTemp = "";
		String stringA = "";
		Map<String, Object> sortParams = new TreeMap<String, Object>(map);
		// 获得stringA
		Set<String> keys = sortParams.keySet();
		for (String key : keys) {
			stringA += (key + "=" + sortParams.get(key) + "&");
		}
		stringA = stringA.substring(0, stringA.length() - 1);
		// 获得stringSignTemp
		stringSignTemp = stringA + "&key=" + parKey;
		// 获得signValue
		signValue = encryptByMD5(stringSignTemp).toUpperCase();
		logger.debug("预支付签名:" + signValue);
		return signValue;
	}
	
	
	public static String createSignSha256(Map<String, Object> map,String parKey) {
		String signValue = "";
		String stringSignTemp = "";
		String stringA = "";
		Map<String, Object> sortParams = new TreeMap<String, Object>(map);
		// 获得stringA
		Set<String> keys = sortParams.keySet();
		for (String key : keys) {
			stringA += (key + "=" + sortParams.get(key) + "&");
		}
		stringA = stringA.substring(0, stringA.length() - 1);
		// 获得stringSignTemp
		stringSignTemp = stringA + "&key=" + parKey;
		// 获得signValue
		signValue = sha256_HMAC(stringSignTemp, parKey).toUpperCase();
		logger.debug("预支付签名:" + signValue);
		return signValue;
	}
	

	/**
	 * MD5加密
	 *
	 * @param sourceStr
	 * @return
	 */
	public static String encryptByMD5(String sourceStr) {
		String result = "";
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			try {
				md.update(sourceStr.getBytes("UTF-8"));
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			byte b[] = md.digest();
			int i;
			StringBuffer buf = new StringBuffer("");
			for (int offset = 0; offset < b.length; offset++) {
				i = b[offset];
				if (i < 0)
					i += 256;
				if (i < 16)
					buf.append("0");
				buf.append(Integer.toHexString(i));
			}
			result = buf.toString();
		} catch (NoSuchAlgorithmException e) {
			System.out.println(e);
		}
		return result;
	}
	
	/**
	 * 获取ip
	 * @return
	 */
	public static String getLocalIP() {   
        InetAddress addr = null;   
        try {
            addr = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }         
        byte[] ipAddr = addr.getAddress();   
        String ipAddrStr = "";   
        for (int i = 0; i < ipAddr.length; i++) {   
            if (i > 0) {   
                ipAddrStr += ".";   
            }   
            ipAddrStr += ipAddr[i] & 0xFF;   
        }   
        return ipAddrStr;   
    } 
	
	
	/*
     * 将SortedMap<Object,Object> 集合转化成 xml格式
     */
    public static String SortedMaptoXml(SortedMap<String,Object> parameters){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        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+">"+"<![CDATA["+v+"]]></"+k+">");
            }else {
                sb.append("<"+k+">"+v+"</"+k+">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }
	
    
    
    /**
     * 将加密后的字节数组转换成字符串
     *
     * @param b 字节数组
     * @return 字符串
     */
    public  static String byteArrayToHexString(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b!=null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1)
                hs.append('0');
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }
    /**
     * sha256_HMAC加密
     * @param message 消息
     * @param secret  秘钥
     * @return 加密后字符串
     */
    public static String sha256_HMAC(String message, String secret) {
        String hash = "";
        try {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
            hash = byteArrayToHexString(bytes);
        } catch (Exception e) {
            System.out.println("Error HmacSHA256 ===========" + e.getMessage());
        }
        return hash;
    }
    
	
	
	public static void main(String[] args) {
		Map<String, Object> map = new HashMap<>();
		map.put("appid", "wxd930ea5d5a258f4f");
		map.put("mch_id", "10000100");
		map.put("device_info", "1000");
		map.put("body", "test");
		map.put("nonce_str", "ibuaiVcKdpRxkhJA");
		System.out.println(WxUtils.createSignSha256(map, "192006250b4c09247ec02edce69f6a2d"));
	}
	
	
}

将证书放在自定义目录中(当前win7)
封装参数调用接口

public static void wxSendWallet(Map<String, Object> map) {
		
		
		String openid = map.get("openid").toString();     //openid
		double money =   Double.valueOf(map.get("double").toString());
//		String openid = "";
		BigDecimal df = new BigDecimal(money+"");
		df = df.multiply(new BigDecimal("100"));
     	int fee = df.intValue();
     	
     	//创建一个唯一订单号
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String time = sdf.format(new Date());
     	String orderId = "T"+time + (int)(Math.random()*1000);
     	
     	String nonceStr = RandomUtil.getRandomString(32);
        //SortedMap接口主要提供有序的Map实现,默认的排序是根据key值进行升序排序
        SortedMap<String,Object> parameters = new TreeMap<String,Object>();
        parameters.put("mch_appid", appid);
        parameters.put("mchid", mchid);
        parameters.put("nonce_str", nonceStr);
        parameters.put("partner_trade_no", orderId);
        parameters.put("openid", openid);
        parameters.put("check_name", "NO_CHECK");   //不进行实名认证
        parameters.put("amount", String.valueOf(fee));
        parameters.put("spbill_create_ip", WxUtils.getLocalIP());
        parameters.put("desc", "福利红包");
        //签名
        parameters.put("sign", WxUtils.createSign(parameters,key));
        String xml =WxUtils.SortedMaptoXml(parameters);
     	
        System.out.println(xml);
        try {
        	//指定读取证书格式为PKCS12
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            //windows系统
            FileInputStream instream = new FileInputStream(new File("F:\\cert\\apiclient_cert.p12"));
            //linux系统,读取本机存放的PKCS12证书文件
            //FileInputStream instream = new FileInputStream(new File("/alidata/opt/paycert/apiclient_cert.p12"));
            try {
            	//指定PKCS12的密码(商户ID)
                //keyStore.load(instream, accountUtil.getWxPartnerId().toCharArray());
            	keyStore.load(instream, mchid.toCharArray());
            }finally {
                instream.close();
            }
         // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchid.toCharArray()).build();
        	//指定TLS版本, Allow TLSv1 protocol only
           
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            
            //设置httpclient的SSLSocketFactory
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
        	//这里要设置编码,不然xml中有中文的话会提示签名失败或者展示乱码
            httppost.addHeader("Content-Type", "text/xml");
            StringEntity se = new StringEntity(xml,"UTF-8");
            httppost.setEntity(se);
            CloseableHttpResponse responseEntry = httpclient.execute(httppost);
            try {
                HttpEntity entity = responseEntry.getEntity();
                if (entity != null) {
                    System.out.println("响应内容长度 : "+ entity.getContentLength());
                    SAXReader saxReader = new SAXReader();
                    Document document = saxReader.read(entity.getContent());
                    Element rootElt = document.getRootElement();
                    String resultCode = rootElt.elementText("result_code");
                    System.out.println(WeixinUtil.doc2String(document));
                    /*****************************记录日志**************************************/
                    PayLog log = new PayLog();
                	log.setId(RandomUtil.getRandomString(32));
                	log.setCode("WX_SEND_WALL");
                	log.setInXml(xml);
                	log.setOutXml(WeixinUtil.doc2String(document));
                	log.setCreateDate(new Date());
                	log.setOrderNo(orderId);
                    if(resultCode.equals("SUCCESS")){
                    	//处理业务逻辑
                    }else{
                    	System.out.println(rootElt.elementText("err_code_des"));
                    }
                }
                EntityUtils.consume(entity);
            }catch(Exception e){
            	System.out.println("请求失败");
            }
            finally {
                responseEntry.close();
            }
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

过程中遇到了一下错误
在这里插入图片描述
检查证书位置和引入名称
在这里插入图片描述
在这里插入图片描述
成功

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值