微信发现金红包(测试版本)

package cn.obp_code.common.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import javax.net.ssl.SSLContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
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.protocol.HTTP;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;




/**
 * 微信企业活动发红包工具类
 * 包含md5,获取随机字符串,签名,post请求等
 * @author ldb 2019年8月19日 下午2:01:24
 *
 */

@SuppressWarnings("deprecation")
public class WeChatPayUtils {
	
	public static void main(String[] args) {
//		String key = "";
//		String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
//		Map<String, String> map = new HashMap<String, String>();
//		map.put("nonce_str", getUUID());//32位随机字符串,微信端避免混淆作用。
//		map.put("mch_billno", "xxx");//商户订单号,如有需要会从前台传过来,不需要随机生成一个就行
//		map.put("mch_id", "xxxxxxxxxxxxxxxx");//商户号
//		map.put("wxappid", "xxx");//商户appid
//		map.put("send_name", "阿里巴巴以后的子公司");//用户名
//		map.put("re_openid", "oDcZ6uPput41yWYtf_ul3ylJc2kU");//用户openid
//		map.put("total_amount", "1");//付款金额单位分
//		map.put("total_num", "1");//红包发送总人数
//		map.put("wishing", "恭喜发财");//红包祝福语
//		map.put("client_ip", "127.0.0.1");//ip地址
//		map.put("act_name", "抽奖送现金红包");//活动名称
//		map.put("remark", "备注");//备注
////		map.put("sign", createSign(map));//签名
//		
////		Map<String, String> result = "";
//		try {
//			map = giveRedEnvelopes(url, "",map);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
	}
	
	/**
	 * 发红包主方法
	 * @param url   调用微信的地址
	 * @param appKey	你的密钥,
	 * @param map	官网上要求传入的必填的字段放入此map
	 * @return
	 */
	public static Map<String, String> giveRedEnvelopes(String url,String appKey,Map<String,String> map) {
		//加入随机数,微信为了要求保证每次签名不可预测,是32位随机的就行
		map.put("nonce_str", getUUID());
		//拼接参数
		String prestr = MD5.createLinkString(map); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
		//设置key
		appKey = "&key=" + appKey; // 商户支付密钥
		//MD5签名
		String mysign = MD5.sign(prestr, appKey, "utf-8").toUpperCase();
		String mysign1 = MD5.sign(prestr, appKey, "utf-8").toUpperCase();
		map.put("sign", mysign);
		//map转xml
		String mapXml = mapToXml(map);
//		System.out.println(mapXml);
		//开始发红包post请求微信
		Map<String, String> resultmap = new HashMap<String, String>();
		try {
			resultmap = doSendMoney(url, mapXml,map);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 返回状态码
		String result_code = resultmap.get("result_code");
		System.out.println("微信返回执行结果状态码:" + result_code);
		System.out.println("微信返回结果:" + resultmap);
		return resultmap;
	}

	/** 
     * 生成32位编码 
     * @return string 
     */  
    public static String getUUID(){  
        String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");  
        return uuid;  
    }  
      
	//map转xml,微信个别功能请求只支持xml参数
	public static String mapToXml(Map<String, String> map){
		String xml = "<xml>";
		Set<String> set = map.keySet();
		Iterator<String> i = set.iterator();
		while(i.hasNext()){
			String str = i.next();
			xml+="<"+str+">"+"<![CDATA["+map.get(str)+"]]>"+"</"+str+">";
		}
		xml+="</xml>";
		return xml;
	}

	//签名成功后发送post请求。
	public static Map<String, String> doSendMoney(String url, String data,Map<String,String> map) throws Exception {
		KeyStore keyStore  = KeyStore.getInstance("PKCS12");
		//文件存放位置和文件名,此文件为微信开发平台下载的密钥证书,微信发红包和微信查询红包发送状态要求使用此证书
		InputStream instream = WeChatPayUtils.class.getResourceAsStream("/wxpaycert/apiclient_cert.p12");  
        try {
//            keyStore.load(instream, mch_id.toCharArray());//这里写密码..默认是你的mch_id
            keyStore.load(instream, map.get("mch_id").toCharArray());//这里写密码..默认是你的mch_id
        } finally {
            instream.close();
        }
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, map.get("mch_id").toCharArray())//这里也是写密码的..默认是你的mch_id
                .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();
                Map<String, String> retMap = new HashMap<String, String>();
                if (entity != null) {
					// 从request中取得输入流
					InputStream inputStream = entity.getContent();
					// 读取输入流
					SAXReader reader = new SAXReader();
					Document document = reader.read(inputStream);
					// 得到xml根元素
					Element root = document.getRootElement();
					// 得到根元素的所有子节点
					List<Element> elementList = root.elements();
					// 遍历所有子节点
					for (Element e : elementList) {
						retMap.put(e.getName(), e.getText());
					}
					// 释放资源
					inputStream.close();
					inputStream = null;
				}
                
//                String jsonStr = toStringInfo(response.getEntity(),"UTF-8"); //返回值根据自己情况转成所需格式
//                System.out.println(jsonStr);
                //微信返回的报文时GBK,直接使用httpcore解析乱码
              //  String jsonStr = EntityUtils.toString(response.getEntity(),"UTF-8");
                EntityUtils.consume(entity);
               return retMap;
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
	}
	
	/**
	 * 查询红包主方法,目前与发红包的一样,就是把需要的参数传进来,然后拼接,签名,发post请求,无其他特殊逻辑
	 * @param url
	 * @param appKey
	 * @param map
	 * @return
	 */
	public static Map<String, String> queryRedEnvelopes(String url,String appKey,Map<String,String> map){
		//加入随机数,微信为了要求保证每次签名不可预测,是32位随机的就行
		map.put("nonce_str", getUUID());
		//拼接参数
		String prestr = MD5.createLinkString(map); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
		//设置key
		appKey = "&key=" + appKey; // 商户支付密钥
		//MD5签名
		String mysign = MD5.sign(prestr, appKey, "utf-8").toUpperCase();
		String mysign1 = MD5.sign(prestr, appKey, "utf-8").toUpperCase();
		map.put("sign", mysign);
		//map转xml
		String mapXml = mapToXml(map);
		System.out.println(mapXml);
		//开始发红包post请求微信
		Map<String, String> resultmap = new HashMap<String, String>();
		try {
			resultmap = doSendMoney(url, mapXml,map);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 返回状态码
		String return_code = resultmap.get("return_code");
		
		System.out.println("微信返回执行结果状态码:" + return_code);
		System.out.println("微信返回结果:" + resultmap);
		return resultmap;
		
	}
}


1,按微信开发文档https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3 准备好参数

      类似此图。

2,调用上边的类

3,接到返回值然后就可以根据返回发送红包的结果处理相应的逻辑了

下边为上边发红包方法中需要的一个MD5工具类:(加个密,拼接个字符串,生成个随机数啥的)

package cn.obp_code.common.utils;

import java.io.UnsupportedEncodingException;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.digest.DigestUtils;


public class MD5 {
	 /**
     * 签名字符串
     * @param text 需要签名的字符串
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static String sign(String text, String key, String input_charset) {
    	text = text + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }
    
    /**
     * 签名字符串
     * @param text 需要签名的字符串
     * @param sign 签名结果
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String key, String input_charset) {
	    text = text + key;
	    String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
	    if(mysign.equals(sign)) {
	    	return true;
	    }
	    else {
	    	return false;
	    }
    }
 
    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException 
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }

     
	/**
	 * 生成6位或10位随机数
	 * param codeLength(多少位)
	 * @return
	 */
	public static String createCode(int codeLength) {
		String code="";
		for(int i=0; i<codeLength; i++) {
			code += (int)(Math.random() * 9);
		}
		return code;
	}
 
	/** 
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {
 
        Map<String, String> result = new HashMap<String, String>();
 
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
                || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }
 
 
    /** 
     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {
 
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
 
        String prestr = "";
 
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
 
 
            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
 
        return prestr;
    }
 
}
发布了66 篇原创文章 · 获赞 8 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/qq_37889636/article/details/100139613
今日推荐