微信摇一摇红包
1、说明
微信摇一摇红包官方说明地址:点击查看
官方的说明不在赘述,有几点需注意:
-
摇一摇分为2种:
1、普通红包,该红包只有1份,其中金额必须
大于1元
;如果小于1元,可以通过红包预下单
接口进行创建,但是,当创建红包活动
的时候是不能够正确的添加的,会显示9001090错误即(录入的所有ticket都是无效ticket,可能原因为ticket重复使用,过期或金额不在1-1000元之间);一个用户只能领取一个;
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;
}
}