前一阵子做了个微信发放普通红包的功能,在这记录下开发思路
https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
发放规则:
注意事项:
◆ 红包金额大于200或者小于1元时,请求参数scene_id必传,参数说明见官网。
◆ 根据监管要求,新申请商户号使用现金红包需要满足两个条件:1、入驻时间超过90天 2、连续正常交易30天。
◆ 移动应用的appid无法使用红包接口。
◆ 当返回错误码为“SYSTEMERROR”时,请不要更换商户订单号,一定要使用原商户订单号重试,否则可能造成重复发放红包等资金风险。
◆ XML具有可扩展性,因此返回参数可能会有新增,而且顺序可能不完全遵循此文档规范,如果在解析回包的时候发生错误,请商户务必不要换单重试,请商户联系客服确认红包发放情况。如果有新回包字段,会更新到此API文档中。
◆ 因为错误代码字段err_code的值后续可能会增加,所以商户如果遇到回包返回新的错误码,请商户务必不要换单重试,请商户联系客服确认红包发放情况。如果有新的错误码,会更新到此API文档中。
◆ 错误代码描述字段err_code_des只供人工定位问题时做参考,系统实现时请不要依赖这个字段来做自动化处理。
发放红包方法
/**
* 普通红包发送
*/
public boolean addRedPack(SendredpackRequestBo sendredpackRequestBo) throws Exception {
//发放状态
boolean status = false;
// 微信红包地址
String requestUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
//key为商户平台设置的密钥key
String paykey = "XXXXXXXX";
//微信商户证书地址
String certPath = "XXXXXXXX";
//配置参数
SendredpackRequestBo param = new SendredpackRequestBo();
param.setNonce_str(UUID.randomUUID().toString().replaceAll("-", ""));
param.setMch_billno(param.getMch_billno());//商户订单号
param.setMch_id(param.getMch_id());//商户号
param.setWxappid("XXXXXXXXXX");//公众账号appid
param.setSend_name(sendredpackRequestBo.getSend_name());//商户名称
param.setRe_openid(sendredpackRequestBo.getRe_openid());//用户openid
param.setTotal_amount(sendredpackRequestBo.getTotal_amount());// 付款金额,单位:分
param.setTotal_num(1);//红包发放总人数
param.setWishing(sendredpackRequestBo.getWishing());//红包祝福语
param.setClient_ip(sendredpackRequestBo.getClient_ip());//Ip地址
param.setAct_name(sendredpackRequestBo.getAct_name());//活动名称
param.setRemark(sendredpackRequestBo.getRemark());//备注
param.setScene_id("PRODUCT_2");//场景id:红包金额大于200或者小于1元时,请求参数scene_id必传
param.setSign(WechatUtils.getWechatPaySign(param, paykey));//签名
// 发送请求
SendredpackResponseBo resp = null;
try {
resp = (SendredpackResponseBo) WechatUtils.httpsXMLPostPay(requestUrl, param, certPath, param.getMch_id());
status = true;
} catch (Exception e) {
logger.error("微信红包异常,请稍后再试!");
}
if (resp == null || "FAIL".equals(resp.getResult_code()) || "FAIL".equals(resp.getReturn_code())) {
String errCode = resp.getErr_code();
String tips = "";
switch (errCode) {
case "NO_AUTH":
tips = "微信账号异常,请联系客服";
break;
case "SENDNUM_LIMIT":
tips = "今日领取已达上限,请明天再试";
break;
case "NOTENOUGH":
tips = "红包当前领取人数过多,请稍后再试";
break;
case "FREQ_LIMIT":
tips = "红包当前领取人数过多,请稍后再试";
break;
case "PROCESSING":
tips = "红包正在发放中";
break;
case "SYSTEMERROR":
tips = "红包正在发放中";
break;
default:
tips = "系统繁忙,请稍后再试";
break;
}
logger.error(tips);
}
return status;
}
WechatUtils.java
下面所需要的XmlParseUtil:https://blog.csdn.net/cl11992/article/details/86623313
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.security.KeyStore;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
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.conn.ssl.SSLContexts;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.panpass.bo.SendredpackRequestBo;
import com.panpass.bo.SendredpackResponseBo;
public class WechatUtils {
private static Logger logger = LoggerFactory.getLogger(WechatUtils.class);
/**
* 获得支付签名(微信支付,现金红包)
*/
@SuppressWarnings("rawtypes")
public static String getWechatPaySign(SendredpackRequestBo bo, String payKey) throws IllegalArgumentException, IllegalAccessException {
SortedMap
SendredpackRequestBo.java
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
/**
* 发红包的参数
* @author cailong
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "xml")
public class SendredpackRequestBo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 签名 必填 String(32) 详见签名生成算法
*/
private String sign;
/**
* 商户订单号 必填 String(28) 商户订单号(每个订单号必须唯一。
* 取值范围:0~9,a~z,A~Z)接口根据商户订单号支持重入,如出现超时可再调用。
*/
private String mch_billno;
/**
* 商户号 必填 String(32) 微信支付分配的商户号
*/
private String mch_id;
/**
* 公众账号appid 必填 String(32) 微信分配的公众账号ID(企业号corpid即为此appId)。
* 接口传入的所有appid应该为公众号的appid
* (在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。
*/
private String wxappid;
/**
* 商户名称 必填 String(32) 红包发送者名称
*/
private String send_name;
/**
* 用户openid 必填 String(32) 接受红包的用户,用户在wxappid下的openid
*/
private String re_openid;
/**
* 付款金额 必填 int 付款金额,单位分
*/
private Integer total_amount;
/**
* 红包发放总人数 必填 int 红包发放总人数total_num=1
*/
private Integer total_num;
/**
* 红包祝福语 必填 String(128) 红包祝福语
*/
private String wishing;
/**
* Ip地址 必填 String(15) 调用接口的机器Ip地址
*/
private String client_ip;
/**
* 活动名称 必填 String(32) 活动名称
*/
private String act_name;
/**
* 备注 必填 String(25) 备注
*/
private String remark;
/**
* 场景id 非必填 String(32) 发放红包使用场景,红包金额大于200时必传 PRODUCT_1:商品促销 PRODUCT_2:抽奖
* PRODUCT_3:虚拟物品兑奖 PRODUCT_4:企业内部福利 PRODUCT_5:渠道分润 PRODUCT_6:保险回馈
* PRODUCT_7:彩票派奖 PRODUCT_8:税务刮奖
*/
private String scene_id;
/**
* 资金授权商户号 非必填 String(32) 服务商替特约商户发放时使用
*/
private String consume_mch_id;
/**
* 随机字符串 必填 String(32) 随机字符串,不长于32位
*/
private String nonce_str;
/**
* 活动信息 非必填 String(128) posttime:用户操作的时间戳 mobile:业务系统账号的手机号,国家代码-手机号。不需要+号
* deviceid :mac 地址或者设备唯一标识 clientversion
* :用户操作的客户端版本把值为非空的信息用key=value进行拼接,再进行urlencode urlencode(posttime=xx&
* mobile =xx&deviceid=xx)
*/
private String risk_info;
/**
* 随机字符串必填String(32)随机字符串,不长于32位
* @return the nonce_str
*/
public String getNonce_str() {
return nonce_str;
}
/**
* @param 随机字符串必填String(32)随机字符串,不长于32位 the nonce_str to set
*/
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
/**
* 签名必填String(32)详见签名生成算法
* @return the sign
*/
public String getSign() {
return sign;
}
/**
* @param 签名必填String(32)详见签名生成算法 the sign to set
*/
public void setSign(String sign) {
this.sign = sign;
}
/**
* 商户订单号必填String(28)商户订单号(每个订单号必须唯一。取值范围:0~9,a~z,A~Z)接口根据商户订单号支持重入,如出现超时可再调用。
* @return the mch_billno
*/
public String getMch_billno() {
return mch_billno;
}
/**
* @param 商户订单号必填String(28)商户订单号(每个订单号必须唯一。取值范围:0~9,a~z,A~Z)接口根据商户订单号支持重入,如出现超时可再调用。
*/
public void setMch_billno(String mch_billno) {
this.mch_billno = mch_billno;
}
/**
* 商户号必填String(32)微信支付分配的商户号
* @return the mch_id
*/
public String getMch_id() {
return mch_id;
}
/**
* @param 商户号必填String(32)微信支付分配的商户号 the mch_id to set
*/
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
/**
* 公众账号appid必填String(32)微信分配的公众账号ID(企业号corpid即为此appId)。
* 接口传入的所有appid应该为公众号的appid
* (在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。
* @return the wxappid
*/
public String getWxappid() {
return wxappid;
}
/**
* @param 公众账号appid必填String(32)微信分配的公众账号ID(企业号corpid即为此appId)。接口传入的所有appid应该为公众号的appid(
* 在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。
*/
public void setWxappid(String wxappid) {
this.wxappid = wxappid;
}
/**
* 商户名称必填String(32)红包发送者名称
* @return the send_name
*/
public String getSend_name() {
return send_name;
}
/**
* @param 商户名称必填String(32)红包发送者名称 the send_name to set
*/
public void setSend_name(String send_name) {
this.send_name = send_name;
}
/**
* 用户openid必填String(32)接受红包的用户用户在wxappid下的openid
* @return the re_openid
*/
public String getRe_openid() {
return re_openid;
}
/**
* @param 用户openid必填String(32)接受红包的用户用户在wxappid下的openid the re_openid to set
*/
public void setRe_openid(String re_openid) {
this.re_openid = re_openid;
}
/**
* 付款金额必填int付款金额,单位分
* @return the total_amount
*/
public Integer getTotal_amount() {
return total_amount;
}
/**
* @param 付款金额必填int付款金额,单位分 the total_amount to set
*/
public void setTotal_amount(Integer total_amount) {
this.total_amount = total_amount;
}
/**
* 红包发放总人数必填int红包发放总人数total_num=1
*/
public Integer getTotal_num() {
return total_num;
}
/**
* @param 红包发放总人数必填int红包发放总人数total_num =1 the 红包发放总人数必填int红包发放总人数total_num=1 to set
*/
public void setTotal_num(Integer total_num) {
this.total_num = total_num;
}
/**
* 红包祝福语必填String(128)红包祝福语
* @return the wishing
*/
public String getWishing() {
return wishing;
}
/**
* @param 红包祝福语必填String(128)红包祝福语 the wishing to set
*/
public void setWishing(String wishing) {
this.wishing = wishing;
}
/**
* Ip地址必填String(15)调用接口的机器Ip地址
* @return the client_ip
*/
public String getClient_ip() {
return client_ip;
}
/**
* @param Ip地址必填String(15)调用接口的机器Ip地址 the client_ip to set
*/
public void setClient_ip(String client_ip) {
this.client_ip = client_ip;
}
/**
* 活动名称必填String(32)活动名称
* @return the act_name
*/
public String getAct_name() {
return act_name;
}
/**
* @param 活动名称必填String(32)活动名称 the act_name to set
*/
public void setAct_name(String act_name) {
this.act_name = act_name;
}
/**
* 备注必填String(25)备注
* @return the remark
*/
public String getRemark() {
return remark;
}
/**
* @param 备注必填String(25)备注 the remark to set
*/
public void setRemark(String remark) {
this.remark = remark;
}
/**
* 场景id非必填String(32)发放红包使用场景,红包金额大于200时必传PRODUCT_1:商品促销PRODUCT_2:抽奖PRODUCT_3
* :虚拟物品兑奖PRODUCT_4:企业内部福利PRODUCT_5:渠道分润PRODUCT_6:保险回馈PRODUCT_7:
* 彩票派奖PRODUCT_8:税务刮奖
* @return the scene_id
*/
public String getScene_id() {
return scene_id;
}
/**
* @param 场景id非必填String(32)发放红包使用场景,红包金额大于200时必传
* PRODUCT_1:商品促销
* PRODUCT_2:抽奖
* PRODUCT_3:虚拟物品兑奖
* PRODUCT_4企业内部福利
* PRODUCT_5:渠道分润
* PRODUCT_6:保险回馈
* PRODUCT_7:彩票派奖
* PRODUCT_8:税务刮奖 the scene_id to set
*/
public void setScene_id(String scene_id) {
this.scene_id = scene_id;
}
/**
* 活动信息非必填String(128)posttime:用户操作的时间戳mobile:业务系统账号的手机号,国家代码-手机号。不需要+
* 号deviceid:mac地址或者设备唯一标识clientversion:用户操作的客户端版本把值为非空的信息用key=value进行拼接,
* 再进行urlencodeurlencode(posttime=xx&mobile=xx&deviceid=xx)
* @return the risk_info
*/
public String getRisk_info() {
return risk_info;
}
/**
* @param 活动信息非必填String(128)
* posttime:用户操作的时间戳
* mobile:业务系统账号的手机号,国家代码-手机号。不需要+号
* deviceid:mac地址或者设备唯一标识
* clientversion:用户操作的客户端版本把值为非空的信息用key=value进行拼接,再进行urlencodeurlencode(posttime=xx&mobile=xx&deviceid=xx)
*/
public void setRisk_info(String risk_info) {
this.risk_info = risk_info;
}
/**
* 资金授权商户号非必填String(32)服务商替特约商户发放时使用
* @return the consume_mch_id
*/
public String getConsume_mch_id() {
return consume_mch_id;
}
/**
* @param 资金授权商户号非必填String(32)服务商替特约商户发放时使用 the consume_mch_id to set
*/
public void setConsume_mch_id(String consume_mch_id) {
this.consume_mch_id = consume_mch_id;
}
}
SendredpackResponseBo.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "xml")
public class SendredpackResponseBo {
/**
* 返回状态码 必填 String(16) SUCCESS/FAIL 此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
*/
private String return_code;
/**
* 返回信息 非必填 String(128) 返回信息,如非空,为错误原因 签名失败 参数格式校验错误
*/
private String return_msg;
// 以下字段在return_code为SUCCESS的时候有返回
/**
* 签名 必填 String(32)
*/
private String sign;
/**
* 业务结果 必填 String(16) SUCCESS/FAIL
*/
private String result_code;
/**
* 错误代码 非必填 String(32) 错误码信息
*/
private String err_code;
/**
* 错误代码描述 非必填 String(128) 结果信息描述
*/
private String err_code_des;
// 以下字段在return_code和result_code都为SUCCESS的时候有返回
/**
* 商户订单号 必填 String(28) 商户订单号(每个订单号必须唯一) 组成:mch_id+yyyymmdd+10位一天内不能重复的数字
*/
private String mch_billno;
/**
* 商户号 必填 String(32) 微信支付分配的商户号
*/
private String mch_id;
/**
* 公众账号appid 必填 String(32) 微信分配的公众账号ID(企业号corpid即为此appId)。
* 接口传入的所有appid应该为公众号的appid
* (在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。
*/
private String wxappid;
/**
* 用户openid 必填 String(32) 接受红包的用户,用户在wxappid下的openid
*/
private String re_openid;
/**
* 付款金额 必填 int 付款金额,单位分
*/
private String total_amount;
/**
* 微信单号 必填 String(32) 红包订单的微信单号
*/
private String send_listid;
/**
* return_code
* @return the return_code
*/
public String getReturn_code() {
return return_code;
}
/**
* @param return_code the return_code to set
*/
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
/**
* return_msg
* @return the return_msg
*/
public String getReturn_msg() {
return return_msg;
}
/**
* @param return_msg the return_msg to set
*/
public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}
/**
* sign
* @return the sign
*/
public String getSign() {
return sign;
}
/**
* @param sign the sign to set
*/
public void setSign(String sign) {
this.sign = sign;
}
/**
* result_code
* @return the result_code
*/
public String getResult_code() {
return result_code;
}
/**
* @param result_code the result_code to set
*/
public void setResult_code(String result_code) {
this.result_code = result_code;
}
/**
* err_code
* @return the err_code
*/
public String getErr_code() {
return err_code;
}
/**
* @param err_code the err_code to set
*/
public void setErr_code(String err_code) {
this.err_code = err_code;
}
/**
* err_code_des
* @return the err_code_des
*/
public String getErr_code_des() {
return err_code_des;
}
/**
* @param err_code_des the err_code_des to set
*/
public void setErr_code_des(String err_code_des) {
this.err_code_des = err_code_des;
}
/**
* mch_billno
* @return the mch_billno
*/
public String getMch_billno() {
return mch_billno;
}
/**
* @param mch_billno the mch_billno to set
*/
public void setMch_billno(String mch_billno) {
this.mch_billno = mch_billno;
}
/**
* mch_id
* @return the mch_id
*/
public String getMch_id() {
return mch_id;
}
/**
* @param mch_id the mch_id to set
*/
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
/**
* wxappid
* @return the wxappid
*/
public String getWxappid() {
return wxappid;
}
/**
* @param wxappid the wxappid to set
*/
public void setWxappid(String wxappid) {
this.wxappid = wxappid;
}
/**
* re_openid
* @return the re_openid
*/
public String getRe_openid() {
return re_openid;
}
/**
* @param re_openid the re_openid to set
*/
public void setRe_openid(String re_openid) {
this.re_openid = re_openid;
}
/**
* total_amount
* @return the total_amount
*/
public String getTotal_amount() {
return total_amount;
}
/**
* @param total_amount the total_amount to set
*/
public void setTotal_amount(String total_amount) {
this.total_amount = total_amount;
}
/**
* send_listid
* @return the send_listid
*/
public String getSend_listid() {
return send_listid;
}
/**
* @param send_listid the send_listid to set
*/
public void setSend_listid(String send_listid) {
this.send_listid = send_listid;
}
}