微信摇一摇红包

微信摇一摇红包

1、说明

  • 微信摇一摇红包官方说明地址:点击查看

  • 官方的说明不在赘述,有几点需注意:

  1. 摇一摇分为2种:

    1、普通红包,该红包只有1份,其中金额必须大于1元;如果小于1元,可以通过 红包预下单接口进行创建,但是,当创建红包活动的时候是不能够正确的添加的,会显示9001090错误即(录入的所有ticket都是无效ticket,可能原因为ticket重复使用,过期或金额不在1-1000元之间);一个用户只能领取一个;
    2、裂变红包,该红包可以分享给其他好友,分享的份数就是通过红包预下单接口创建的个数;其他好友可以领取。

  2. 接口注意事项:

    1、红包预下单接口 该接口可以每个字段必须填写;
    2、创建红包活动 该接口中的total数量需要大于在红包预下单设定的值,一般将total的值设置大些,这样在后续添加方便;
    3、创建红包活动,每一个用户该活动下只能领取1个红包,如果在进行摇一摇,虽然可以摇到页面,但是不能够摇到钱;
    4 、 录入红包信息,该接口中,ticket的值,就是红包的分数,与红包预下单创建的红包个数无关;需要特别注意;当只有一个ticket的值,被A用户领取了,那么B用户将不能够领取;若想要有多个用户领取,那么需要调用多次红包预下单该接口,用来创建ticket值,并赋予到红包活动中;

2、 编写步骤

 1、编写`红包预下单接口`
 2、编写`创建红包活动`
 3、编写`录入红包信息`

3、红包预下单接口

/**
     * 接口名称:红包预下单接口<br>
     * @param
     *  total_amount  总金额--分<br>
     *  total_num 红包发放总人数<br>
     *  wishing 红包祝福语<br>
     *  remark 备注信息<br>
     *  act_name 活动名称<br>
     *  send_name 商户号名称<br>
     * @auto thero
     */
    public String createRedPackage(Integer total_amount,Integer total_num,String wishing,String remark,String act_name,String send_name){
        ShakeRedPacakge shakeRedPacakge = new ShakeRedPacakge();
        //随机字符串
        shakeRedPacakge.setNonce_str(CommonUtil.getNonceStr());
        //商户号
        shakeRedPacakge.setMch_id("商户号");
        //商户订单号
        String mch_billno = "商户号"+DateHelper.getFormatStringyyyyMMddHHmmss(new Date()) + ShakeRedPackageInter.createCode().toString();
        shakeRedPacakge.setMch_billno(mch_billno);
        //公众账号appid
        shakeRedPacakge.setWxappid("这里填写appid");
        //商户号名称
        shakeRedPacakge.setSend_name(send_name);
        //红包类型 NORMAL-普通红包;GROUP-裂变红包(可分享红包给好友,无关注公众号能力)
        shakeRedPacakge.setHb_type("NORMAL");
        //总金额--分
        shakeRedPacakge.setTotal_amount(total_amount);
        //红包发放总人数
        shakeRedPacakge.setTotal_num(total_num);
        //红包金额设置方式--全部随机
        shakeRedPacakge.setAmt_type("ALL_RAND");
        //红包祝福语
        shakeRedPacakge.setWishing(wishing);
        //活动名称
        shakeRedPacakge.setAct_name(act_name);
        //备注信息
        shakeRedPacakge.setRemark(remark);
        //授权商户号
        shakeRedPacakge.setAuth_mchid("1000052601");
        //授权商户APPID
        shakeRedPacakge.setAuth_appid("wxbf42bd79c4391863");
        //风控设置
        shakeRedPacakge.setRisk_cntl("NORMAL");
        
        //拼接签名
        List<String> signParam = new ArrayList<String>();
        signParam.add("nonce_str");
        signParam.add("mch_billno");
        signParam.add("mch_id");
        signParam.add("wxappid");
        signParam.add("send_name");
        signParam.add("hb_type");
        signParam.add("total_amount");
        signParam.add("total_num");
        signParam.add("amt_type");
        signParam.add("wishing");
        signParam.add("act_name");
        signParam.add("remark");
        signParam.add("auth_mchid");
        signParam.add("auth_appid");
        signParam.add("risk_cntl");
        Collections.sort(signParam);
        StringBuffer sb = new StringBuffer();
        for(int i =0 ;i < signParam.size(); i++){
            String temp = signParam.get(i);
            sb.append(temp+"=");
            if("nonce_str".equals(temp)){
                sb.append(shakeRedPacakge.getNonce_str());
                sb.append("&");
                continue;
            }
            if("mch_billno".equals(temp)){
                sb.append(shakeRedPacakge.getMch_billno());
                sb.append("&");
                continue;
            }
            if("mch_id".equals(temp)){
                sb.append(shakeRedPacakge.getMch_id());
                sb.append("&");
                continue;
            }
            if("wxappid".equals(temp)){
                sb.append(shakeRedPacakge.getWxappid());
                sb.append("&");
                continue;
            }
            if("send_name".equals(temp)){
                sb.append(shakeRedPacakge.getSend_name());
                sb.append("&");
                continue;
            }
            if("hb_type".equals(temp)){
                sb.append(shakeRedPacakge.getHb_type());
                sb.append("&");
                continue;
            }
            if("total_amount".equals(temp)){
                sb.append(shakeRedPacakge.getTotal_amount());
                sb.append("&");
                continue;
            }
            if("total_num".equals(temp)){
                sb.append(shakeRedPacakge.getTotal_num());
                sb.append("&");
                continue;
            }
            if("amt_type".equals(temp)){
                sb.append(shakeRedPacakge.getAmt_type());
                sb.append("&");
                continue;
            }
            if("wishing".equals(temp)){
                sb.append(shakeRedPacakge.getWishing());
                sb.append("&");
                continue;
            }
            if("act_name".equals(temp)){
                sb.append(shakeRedPacakge.getAct_name());
                sb.append("&");
                continue;
            }
            if("remark".equals(temp)){
                sb.append(shakeRedPacakge.getRemark());
                sb.append("&");
                continue;
            }
            if("auth_mchid".equals(temp)){
                sb.append(shakeRedPacakge.getAuth_mchid());
                sb.append("&");
                continue;
            }
            if("auth_appid".equals(temp)){
                sb.append(shakeRedPacakge.getAuth_appid());
                sb.append("&");
                continue;
            }
            if("risk_cntl".equals(temp)){
                sb.append(shakeRedPacakge.getRisk_cntl());
                sb.append("&");
                continue;
            }
        }
        //加密
        sb = new StringBuffer(sb.toString().substring(0, sb.toString().length()-1));
        sb.append("&key=这里替换key值");
        System.out.println("要加密的密文为:"+sb.toString());
        String sign = MD5(sb.toString()).toUpperCase();
        shakeRedPacakge.setSign(sign);
        
        StringBuffer hbpreOrderxml = new StringBuffer();
        hbpreOrderxml.append("<xml>");
        hbpreOrderxml.append("<nonce_str><![CDATA["+shakeRedPacakge.getNonce_str()+"]]></nonce_str>");
        hbpreOrderxml.append("<sign><![CDATA["+shakeRedPacakge.getSign()+"]]></sign>");
        hbpreOrderxml.append("<mch_billno><![CDATA["+shakeRedPacakge.getMch_billno()+"]]></mch_billno>");
        hbpreOrderxml.append("<mch_id><![CDATA["+shakeRedPacakge.getMch_id()+"]]></mch_id>");
        hbpreOrderxml.append("<wxappid><![CDATA["+shakeRedPacakge.getWxappid()+"]]></wxappid>");
        hbpreOrderxml.append("<send_name><![CDATA["+shakeRedPacakge.getSend_name()+"]]></send_name>");
        hbpreOrderxml.append("<hb_type><![CDATA["+shakeRedPacakge.getHb_type()+"]]></hb_type>");
        hbpreOrderxml.append("<total_amount><![CDATA["+shakeRedPacakge.getTotal_amount()+"]]></total_amount>");
        hbpreOrderxml.append("<total_num><![CDATA["+shakeRedPacakge.getTotal_num()+"]]></total_num>");
        hbpreOrderxml.append("<amt_type><![CDATA["+shakeRedPacakge.getAmt_type()+"]]></amt_type>");
        hbpreOrderxml.append("<wishing><![CDATA["+shakeRedPacakge.getWishing()+"]]></wishing>");
        hbpreOrderxml.append("<act_name><![CDATA["+shakeRedPacakge.getAct_name()+"]]></act_name>");
        hbpreOrderxml.append("<remark><![CDATA["+shakeRedPacakge.getRemark()+"]]></remark>");
        hbpreOrderxml.append("<auth_mchid><![CDATA["+shakeRedPacakge.getAuth_mchid()+"]]></auth_mchid>");
        hbpreOrderxml.append("<auth_appid><![CDATA["+shakeRedPacakge.getAuth_appid()+"]]></auth_appid>");
        hbpreOrderxml.append("<risk_cntl><![CDATA["+shakeRedPacakge.getRisk_cntl()+"]]></risk_cntl>");
        hbpreOrderxml.append("</xml>");
        
        //发送请求
        String hbpreOrderResultXML = httpsRequestKeyStore(ShakeRedPackageConstants.HBPREORDER, HttpsRequestUtil.POST, new String(hbpreOrderxml.toString().getBytes()));
        return hbpreOrderResultXML;
    }

4、 创建红包活动

    public JSONObject addlotteryinfo(JSONObject param){
        String token = AccessToken.getTokenFromDB();
        String url = ShakeRedPackageConstants.ADDLOTTERYINFO.replace("ACCESSTOKEN", token);
        JSONObject result = HttpsRequestUtil.httpsRequest(url, HttpsRequestUtil.POST, param.toString());
        log.info("@@@@@@@@@@@@@@@@@@创建红包活动:"+result);
        return result;
    }

5、红包查询接口

    /**
     * 接口名称:红包查询接口<br>
     * @auto thero
     */
    public JSONObject querylottery(String lotteryid){
        String token = AccessToken.getTokenFromDB();
        String url = ShakeRedPackageConstants.QUERYLOTTERY.replace("ACCESSTOKEN", token).replace("LOTTERYID", lotteryid);
        JSONObject result = HttpsRequestUtil.httpsRequest(url, HttpsRequestUtil.GET, null);
        log.info("@@@@@@@@@@@@@@@@@@查询红包信息为:"+result);
        return result;
    }

4、辅助工具类

   /**
    * 创建随机数,用来补充商户订单号补足的位数
     * @return
     */
public static String createCode(){
        char[] codeSequence={'0','1','2','3','4','5','6','7','8','9' };
        Random random = new Random(); 
              String rand ="";
        for (int i = 0; i < 2; i++) {
                int r = random.nextInt(10);
                rand+= codeSequence[r];
        }
        return rand;
   }
   /**
    * md5加密
 * @param s
 * @return
 */
public final 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();
           // 获得MD5摘要算法的 MessageDigest 对象
           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;
       }
   }
   /**
     * 需要证书,并发送https请求
     * 
     * @param requestUrl
     * @param requestMethod
     * @param outputStr
     * @return
     */
    public static String httpsRequestKeyStore(String requestUrl,
            String requestMethod, String outputStr) {
        StringBuffer buffer = new StringBuffer();
        KeyStore keyStore = null;
        CloseableHttpClient httpclient = null;
        try {
            keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(
                    "D:\byc\work4\weixin\security\apiclient_cert.p12"));
            keyStore.load(instream, "这里填写商户号".toCharArray());
            instream.close();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            log.debug("HTTPS request data set to :{}.", outputStr);
            // SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            SSLContext sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, "这里填写商户号".toCharArray())
                    .build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[] { "TLSv1" },
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            httpclient = HttpClients.custom().setSSLSocketFactory(sslsf)
                    .build();

            HttpPost httpPost = new HttpPost(requestUrl);
              StringEntity  reqEntity  = new StringEntity(outputStr,"UTF-8");
             // 设置类型
             reqEntity.setContentType("application/x-www-form-urlencoded");
             httpPost.setEntity(reqEntity);

            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(entity.getContent(), "UTF-8"));
                String text;
                while ((text = bufferedReader.readLine()) != null) {
                    buffer.append(text);
                }

            }
            EntityUtils.consume(entity);
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyStoreException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return buffer.toString();
    }

5、实体bean以及常量类

Lottery 活动对象
package com.xunclouds.shake.domain;


public class Lottery {
    /**
     * 抽奖活动名称(选择使用模板时,也作为摇一摇消息主标题),最长6个汉字,12个英文字母。
     * */
    private String title;
    /**
     * 抽奖活动描述(选择使用模板时,也作为摇一摇消息副标题),最长7个汉字,14个英文字母。
     * */
    private String desc;
    /**
     * 抽奖开关。0关闭,1开启,默认为1
     * */
    private Integer onoff;
    /**
     *抽奖活动开始时间,unix时间戳,单位秒
     * */
    private Long begin_time;
    
    /**
     * 抽奖活动结束时间,unix时间戳,单位秒,红包活动有效期最长为91天
     */
    private Long expire_time;
    /**
     * 红包提供商户公众号的appid,需与预下单中的公众账号appid(wxappid)一致
     */
    private String sponsor_appid;
    /**
     * 红包总数,红包总数是录入红包ticket总数的上限,因此红包总数应该大于等于预下单时红包ticket总数。
     */
    private Long  total;
    /**
     * 红包关注界面后可以跳转到第三方自定义的页面
     */
    private String jump_url;
    /**
     * 开发者自定义的key,用来生成活动抽奖接口的签名参数,长度32位。使用方式见sign生成规则
     */
    private String key;
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public Integer getOnoff() {
        return onoff;
    }
    public void setOnoff(Integer onoff) {
        this.onoff = onoff;
    }
    public Long getBegin_time() {
        return begin_time;
    }
    public void setBegin_time(Long begin_time) {
        this.begin_time = begin_time;
    }
    public Long getExpire_time() {
        return expire_time;
    }
    public void setExpire_time(Long expire_time) {
        this.expire_time = expire_time;
    }
    public String getSponsor_appid() {
        return sponsor_appid;
    }
    public void setSponsor_appid(String sponsor_appid) {
        this.sponsor_appid = sponsor_appid;
    }
    public Long getTotal() {
        return total;
    }
    public void setTotal(Long total) {
        this.total = total;
    }
    public String getJump_url() {
        return jump_url;
    }
    public void setJump_url(String jump_url) {
        this.jump_url = jump_url;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    
}
  PrizeBucket 录入红包对象
package com.xunclouds.shake.domain;


import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class PrizeBucket {
    /**
     * 红包抽奖id,来自addlotteryinfo返回的lottery_id
     */
    private String lottery_id;
    /**
     * 红包提供者的商户号,,需与预下单中的商户号mch_id一致
     */
    private String mchid;
    /**
     * 红包提供商户公众号的appid,需与预下单中的公众账号appid(wxappid)一致
     */
    private String sponsor_appid;
    /**
     * 红包ticket列表,如果红包数较多,可以一次传入多个红包,批量调用该接口设置红包信息。每次请求传入的红包个数上限为100
     */
    private JSONArray prize_info_list;
    
    public String getLottery_id() {
        return lottery_id;
    }
    public void setLottery_id(String lottery_id) {
        this.lottery_id = lottery_id;
    }
    public String getMchid() {
        return mchid;
    }
    public void setMchid(String mchid) {
        this.mchid = mchid;
    }
    public String getSponsor_appid() {
        return sponsor_appid;
    }
    public void setSponsor_appid(String sponsor_appid) {
        this.sponsor_appid = sponsor_appid;
    }
    public JSONArray getPrize_info_list() {
        return prize_info_list;
    }
    public void setPrize_info_list(JSONArray prize_info_list) {
        this.prize_info_list = prize_info_list;
    }
    
}

  ShakeRedPacakge 录入红包对象
package com.xunclouds.shake.domain;


/**
 * 红包预下单接口 实体bean
 * @author thero
 *
 */
public class ShakeRedPacakge {
    /**
     * 参数:随机字符串
     * 备注:随机字符串,不长于32位
     * */
    private String nonce_str;
    /**
     * 签名
     * 生成签名方式查看签名算法
     * */
    private String sign;
    /**
     * 商户订单号
     * 商户订单号(每个订单号必须唯一)组成: mch_id+yyyymmdd+10位一天内不能重复的数字。接口根据商户订单号支持重入, 如出现超时可再调用。
     * */
    private String mch_billno;
    /**
     * 商户号
     * 红包提供者的商户号(微信支付分配的商户号)
     * */
    private String mch_id;
    /**
     * 公众账号appid
     * 红包提供者公众号的appid,对应头像展示在红包页面
     * */
    private String wxappid;
    /**
     * 商户名称
     * 红包提供者名称,展示在红包页面
     * */
    private String send_name;
    /**
     *红包类型
     *NORMAL-普通红包;GROUP-裂变红包(可分享红包给好友,无关注公众号能力)。
     * */
    private String hb_type;
    /**
     * 总金额
     * 总付款金额,单位分
     * */
    private Integer total_amount;
    /**
     * 红包发放总人数
     * 红包发放总人数,即总共有多少人可以领到该组红包(包括分享者)。普通红包填1,裂变红包必须大于1。
     * */
    private Integer total_num;
    /**
     * 红包金额设置方式
     * 红包金额设置方式,只对裂变红包生效。ALL_RAND—全部随机
     * */
    private String amt_type;
    /**
     * 红包祝福语
     * 红包祝福语,展示在红包页面
     * */
    private String wishing;
    /**
     * 活动名称
     * 活动名称,在不支持原生红包的微信版本中展示在红包消息
     * */
    private String act_name;
    /**
     * 备注
     * 备注信息,在不支持原生红包的微信版本中展示在红包消息
     * */
    private String remark;
    /**
     * 授权商户号
     * 用于发红包时微信支付识别摇周边红包,所有开发者统一填写摇周边平台的商户号:1000052601
     * */
    private String auth_mchid;
    /**
     * 授权商户APPID
     * 用于发红包时微信支付识别摇周边红包,所有开发者统一填写摇周边平台的appid:wxbf42bd79c4391863
     * */
    private String auth_appid;
    /**
     * 风控设置
     * 用于管控接口风险。具体值如下:NORMAL—正常情况;IGN_FREQ_LMT—忽略防刷限制,强制发放;IGN_DAY_LMT—忽略单用户日限额限制,强制发放;IGN_FREQ_DAY_LMT—忽略防刷和单用户日限额限制,强制发放;如无特殊要求,请设为NORMAL。若忽略某项风险控制,可能造成资金损失,请谨慎使用。
     * */
    private String risk_cntl;
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getMch_billno() {
        return mch_billno;
    }
    public void setMch_billno(String mch_billno) {
        this.mch_billno = mch_billno;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getWxappid() {
        return wxappid;
    }
    public void setWxappid(String wxappid) {
        this.wxappid = wxappid;
    }
    public String getSend_name() {
        return send_name;
    }
    public void setSend_name(String send_name) {
        this.send_name = send_name;
    }
    public String getHb_type() {
        return hb_type;
    }
    public void setHb_type(String hb_type) {
        this.hb_type = hb_type;
    }
    public Integer getTotal_amount() {
        return total_amount;
    }
    public void setTotal_amount(Integer total_amount) {
        this.total_amount = total_amount;
    }
    public Integer getTotal_num() {
        return total_num;
    }
    public void setTotal_num(Integer total_num) {
        this.total_num = total_num;
    }
    public String getAmt_type() {
        return amt_type;
    }
    public void setAmt_type(String amt_type) {
        this.amt_type = amt_type;
    }
    public String getWishing() {
        return wishing;
    }
    public void setWishing(String wishing) {
        this.wishing = wishing;
    }
    public String getAct_name() {
        return act_name;
    }
    public void setAct_name(String act_name) {
        this.act_name = act_name;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    public String getAuth_mchid() {
        return auth_mchid;
    }
    public void setAuth_mchid(String auth_mchid) {
        this.auth_mchid = auth_mchid;
    }
    public String getAuth_appid() {
        return auth_appid;
    }
    public void setAuth_appid(String auth_appid) {
        this.auth_appid = auth_appid;
    }
    public String getRisk_cntl() {
        return risk_cntl;
    }
    public void setRisk_cntl(String risk_cntl) {
        this.risk_cntl = risk_cntl;
    }
    
}

原文地址:https://www.cnblogs.com/babyhhcsy/p/4516632.html