微信公众平台开发之微信红包的实现

首先需要了解一下微信红包的规则:
1、发送频率规则

    ◆ 每分钟发送红包数量不得超过1800个;
    ◆ 同一个商户号,每分钟最多给同一个用户发送一个红包;

2、红包规则

    ◆ 单个红包金额介于[1.00元,200.00元]之间;
    ◆ 同一个红包只能发送给一个用户;(如果以上规则不满足您的需求,请发邮件至wxhongbao@tencent.com获取升级指引)

以及商户侧调用红包接口流程

    1.◆ 下载证书
    商户调用微信红包接口时,服务器会进行证书验证,请在商户平台下载证书
    2.◆ 充值
    发放现金红包将扣除商户的可用余额,请注意,可用余额并不是微信支
    付交易额,需要预先充值,确保可用余额充足。查看可用余额、充值、
    提现请登录微信支付商户平台,进入“资金管理”菜单,进行操作

微信红包接口调用流程
◆ 后台API调用:待进入联调过程时与开发进行详细沟通;
◆ 告知服务器:告知服务器接收微信红包的用户openID,告知服务器该用户获得的金额;
◆ 从商务号扣款:服务器获取信息后从对应的商务号扣取对应的金额;
◆ 调用失败:因不符合发送规则,商务号余额不足等原因造成调用失败,反馈至调用方;
◆ 发送成功:以微信红包公众账号发送对应红包至对应用户;

这里写图片描述

这里写图片描述
这里写图片描述

首先编写调用该接口所需要的工具类

package com.beitian.eshop.wx;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
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.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

/**
 * 微信开发工具类
 * <p>作者:Afan</p>
 * <p>电子邮箱:fan.zt@qq.com</p>
 * <p>创建时间:2016-5-3 上午11:14:32</p>
 */
public class WxFanztUtils {

    /**
     * sign签名
     * <p>Afan</p>
     * <p>2016-4-29 下午4:28:29</p>
     * @param map
     * @param key
     * @return
     */
    public static String getSign(Map<String, String> map, String key) {
        String sign = "";
        Collection<String> keyset = map.keySet();
        List<String> list = new ArrayList<String>(keyset);
        // 对key键值按字典升序排序
        Collections.sort(list);
        String stringA = "";
        for (int i = 0; i < list.size(); i++) {
            if (null == map.get(list.get(i)) || "".equals(map.get(list.get(i)))) {
                continue;
            }
            stringA += list.get(i) + "=" + map.get(list.get(i)) + "&";
        }
        stringA += "key=" + key;
        sign = MD5(stringA).toUpperCase();
        return sign;
    }

    /**
     * MD5
     * <p>Afan</p>
     * <p>2016-5-3 上午9:53:01</p>
     * @param s
     * @return
     */
    public  static String MD5(String s) {
        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};       
        try {
            byte[] btInput = s.getBytes("UTF-8");
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            mdInst.update(btInput);
            byte[] md = mdInst.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) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 生成随机字符
     * @param iLen :长度
     * @param iType:0--表示仅获得数字随机数,1--表示仅获得字符随机数,2--表示获得数字字符混合随机数
     * @return
     */
    public static String BuildRadom(int iLen, int iType) {
        String strRandom = "";// 随机字符串
        Random rnd = new Random();
        if (iLen < 0) {
            iLen = 5;
        }
        if ((iType > 2) || (iType < 0)) {
            iType = 2;
        }
        switch (iType) {
        case 0:
            for (int iLoop = 0; iLoop < iLen; iLoop++) {
                strRandom += Integer.toString(rnd.nextInt(10));
            }
            break;
        case 1:
            for (int iLoop = 0; iLoop < iLen; iLoop++) {
                // 将得到的10到35之间的数字转成36进制表示,即a到z的表示
                strRandom += Integer.toString((10 + rnd.nextInt(26)), 36);
            }
            break;
        case 2:
            for (int iLoop = 0; iLoop < iLen; iLoop++) {
                strRandom += Integer.toString(rnd.nextInt(36), 36);
            }
            break;
        }
        return strRandom;
    }

    /**
     * 参数map转xml格式
     * 
     * @param params
     * @return
     */
    public static String paramsToXml(SortedMap<String, String> params) {
        Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement("xml");
        Set<Entry<String, String>> es = params.entrySet();
        Iterator<Entry<String, String>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) it
                    .next();
            String tmpKey = (String) entry.getKey();
            String tmpValue = (String) entry.getValue();
            if (!StringUtils.isEmpty(tmpValue)) {
                root.addElement(tmpKey).addText(tmpValue);
            }
        }
        return doc.asXML();
    }
}

实现发红红包的代码:

package com.beitian.eshop.wx;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.net.ssl.SSLContext;
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.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

/**
 * 微信开发-->微信现金红包
 * <p>作者:Afan</p>
 * <p>电子邮箱:fan.zt@qq.com</p>
 * <p>创建时间:2016-5-3 上午11:14:32</p>
 */
public class WxRedPackageHelper {

    private final static String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";

    @SuppressWarnings("deprecation")
    public static void main(String[] args) throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        map.put("nonce_str", WxFanztUtils.BuildRadom(32,2));//随机字符串
        map.put("mch_billno", "10000098201411111234567890");
        map.put("mch_id", WxConfig.WX_MERCH_ID);//商户号
        map.put("wxappid", WxConfig.WX_APPID);//公众账号appid
        map.put("send_name", "安鑫宝");//商户名
        map.put("re_openid", "oA5zmtxy5NAuYF-Y_q9m5U--V4sE");//用户openid
        map.put("total_amount", "100");//金额,单位分
        map.put("total_num", "1");//数量
        map.put("wishing", "感谢您参加猜灯谜活动,祝您元宵节快乐!");//红包祝福语
        map.put("client_ip", "192.168.0.1");
        map.put("act_name", "猜灯谜抢红包活动");//活动名称
        map.put("remark", "猜越多得越多,快来抢!");//备注
        String sign =  WxFanztUtils.getSign(map, WxConfig.WX_MERCH_API_KEY);//key
        map.put("sign", sign);
        SortedMap<String, String> map2 = new TreeMap<String, String>(map);
        String postXml =  WxFanztUtils.paramsToXml(map2);

         KeyStore keyStore  = KeyStore.getInstance("PKCS12");
         FileInputStream instream = new FileInputStream(new File("E:/Afan/weixin/apiclient_cert.p12"));
         try {
             keyStore.load(instream, WxConfig.WX_MERCH_ID.toCharArray());//WxConfig.WX_MERCH_ID//商户号
         } finally {
             instream.close();
         }
         SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WxConfig.WX_MERCH_ID.toCharArray()).build();
         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(postXml, "utf-8"));
             CloseableHttpResponse response = httpclient.execute(httpost);
             try {
                 HttpEntity entity = response.getEntity();
                 System.out.println("----------------------------------------");
                 System.out.println(response.getStatusLine());
                 if (entity != null) {
                     System.out.println("Response content length: " + entity.getContentLength());
                     BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                     String text;
                        while ((text = bufferedReader.readLine()) != null) {
                            System.out.println(text);
                        }
                    }
                    EntityUtils.consume(entity);
                } finally {
                    response.close();
                }
            }finally {
                httpclient.close();
            }
    }

}

需要注意的是调用微信红包接口需要再本地导入证书,证书的下载微信商户平台(pay.weixin.qq.com)–>账户设置–>API安全–>证书下载 。证书文件有四个:
这里写图片描述

双击导入apiclient_cert.p12,密码为你的商户号

运行main方法,服务器返回:
这里写图片描述

打开微信,收取红包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值