我们先来看看公众号发放现金红包的效果:
需要调用商户平台的接口,接口发放规则如下:
1.发送频率限制——默认1800/min
2.发送个数上限——按照默认1800/min算
3.金额上限——根据传入场景id不同默认上限不同,可以在商户平台产品设置进行设置和申请,最大不大于4999元/个
4.其他的“量”上的限制还有哪些?——用户当天的领取上限次数,默认是10
5.如果量上满足不了我们的需求,如何提高各个上限?——金额上限和用户当天领取次数上限可以在商户平台进行设置
注意-红包金额大于200时,请求参数scene_id必传,参数说明见下文。
注意2-根据监管要求,新申请商户号使用现金红包需要满足两个条件:1、入驻时间超过90天 2、连续正常交易30天。
请求url https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
是否需要证书 是(证书及使用说明详见商户证书)
请求方式 post
请求数据示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<xml>
<sign><![cdata[e1ee61a91c8e90f299de6ae075d60a2d]]></sign>
<mch_billno><![cdata[ 0010010404201411170000046545 ]]></mch_billno>
<mch_id><![cdata[ 888 ]]></mch_id>
<wxappid><![cdata[wxcbda96de0b165486]]></wxappid>
<send_name><![cdata[send_name]]></send_name>
<re_openid><![cdata[onqojjmm1tad-3ropncn-yufa6ui]]></re_openid>
<total_amount><![cdata[ 200 ]]></total_amount>
<total_num><![cdata[ 1 ]]></total_num>
<wishing><![cdata[恭喜发财]]></wishing>
<client_ip><![cdata[ 127.0 . 0.1 ]]></client_ip>
<act_name><![cdata[新年红包]]></act_name>
<remark><![cdata[新年红包]]></remark>
<scene_id><![cdata[product_2]]></scene_id>
<consume_mch_id><![cdata[ 10000097 ]]></consume_mch_id>
<nonce_str><![cdata[50780e0cca98c8c8e814883e5caa672e]]></nonce_str>
<risk_info>posttime%3d123123412%26clientversion%3d234134%26mobile%3d122344545%26deviceid%3dios</risk_info>
</xml>
|
接口需要调用商户平台的证书,证书需要去商户平台下载:
然后在接口中使用证书,首先我们新建一个weixinssl 类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
@component
public class weixinssl {
/**
* 证书类型
*/
@value ( "${werchant.storekey}" )
private string storekey;
/**
* 文件路径
*/
@value ( "${werchant.sslfile}" )
private string sslfile;
/**
* 商户号
*/
@value ( "${werchant.merchantnumber}" )
private string merchantnumber;
public string getstorekey() {
return storekey;
}
public void setstorekey(string storekey) {
this .storekey = storekey;
}
public string getsslfile() {
return sslfile;
}
public void setsslfile(string sslfile) {
this .sslfile = sslfile;
}
public string getmerchantnumber() {
return merchantnumber;
}
public void setmerchantnumber(string merchantnumber) {
this .merchantnumber = merchantnumber;
}
}
|
封装httpclientssl 类实现 https 请求加证书:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
@component
public class httpclientssl {
@autowired
private weixinssl weixinssl;
// 请求超时时间(毫秒) 5秒
public static requestconfig requestconfig;
// 响应超时时间(毫秒) 60秒
public static int http_response_timeout = 60 * 1000 ;
// httpclient字符编码
public static string encoding = "utf-8" ;
public static requestconfig getrequestconfig() {
return requestconfig.custom().setconnecttimeout( 5 * 1000 )
.setconnectionrequesttimeout(http_response_timeout).build();
}
public static void setrequestconfig(requestconfig requestconfig) {
httpclientssl.requestconfig = requestconfig;
}
/**
* https请求伪造证书
* @return
*/
public closeablehttpclient defaultsslclient() {
sslcontext sslcontext = null ;
try {
new sslcontextbuilder().loadtrustmaterial( null , new truststrategy(){
@override
public boolean istrusted(x509certificate[] chain, string authtype)
throws java.security.cert.certificateexception {
return false ;
}
});
} catch (nosuchalgorithmexception | keystoreexception e) {
e.printstacktrace();
}
sslconnectionsocketfactory factory = new sslconnectionsocketfactory(sslcontext);
return httpclients.custom().setsslsocketfactory(factory).build();
}
/**
* https请求加证书
* @return
*/
public closeablehttpclient defaultsslclientfile() {
if ( this .weixinssl == null ){
return this .defaultsslclient();
}
fileinputstream inputstream = null ;
keystore keystore = null ;
try {
// ssl类型
keystore = keystore.getinstance(weixinssl.getstorekey());
// ssl文件
inputstream = new fileinputstream(weixinssl.getsslfile());
// 设置ssl密码
keystore.load(inputstream,weixinssl.getmerchantnumber().tochararray());
} catch (keystoreexception | nosuchalgorithmexception | certificateexception | ioexception e1) {
e1.printstacktrace();
} finally {
try {
inputstream.close();
} catch (ioexception e) {
e.printstacktrace();
}
}
sslcontext sslcontext = null ;
try {
sslcontext = sslcontexts.custom().loadkeymaterial(keystore,weixinssl.getmerchantnumber().tochararray()).build();
} catch (unrecoverablekeyexception | nosuchalgorithmexception | keystoreexception | keymanagementexception e) {
e.printstacktrace();
}
sslconnectionsocketfactory factory = new sslconnectionsocketfactory(sslcontext, new string[] { "tlsv1" }, null ,
sslconnectionsocketfactory.browser_compatible_hostname_verifier);
return httpclients.custom().setsslsocketfactory(factory).build();
}
/**
* 封装发送请求的方法
* @throws unsupportedencodingexception
*/
public string send(string url, string data, closeablehttpclient closeablehttpclient)
throws unsupportedencodingexception {
closeablehttpclient client = closeablehttpclient;
httppost httppost = new httppost(urldecoder.decode(url, encoding));
httppost.addheader( "connection" , "keep-alive" );
httppost.addheader( "accept" , "*/*" );
httppost.addheader( "content-type" , "application/x-www-form-urlencoded; charset=utf-8" );
httppost.addheader( "host" , "api.mch.weixin.qq.com" );
httppost.addheader( "x-requested-with" , "xmlhttprequest" );
httppost.addheader( "cache-control" , "max-age=0" );
httppost.addheader( "user-agent" , "mozilla/4.0 (compatible; msie 8.0; windows nt 6.0) " );
httppost.setconfig( this .getrequestconfig()); // 设置超时时间
closeablehttpresponse response = null ;
// 参数放入
stringentity entity = new stringentity(data, encoding);
entity.setcontentencoding(encoding);
entity.setcontenttype( "application/xml" );
httppost.setentity(entity);
try {
response = client.execute(httppost);
if (response.getstatusline().getstatuscode() == 200 ) {
httpentity httpentity = (httpentity) response.getentity();
if (response != null ) {
return entityutils.tostring(httpentity,encoding);
}
}
} catch (ioexception e) {
e.printstacktrace();
}
return null ;
}
}
|
这样我们就封装了一个https请求加证书的实体类,接下来我们生成请求微信红包接口:
https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack 的参数签名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/**
* 红包参数实体类
* @throws unsupportedencodingexception
*/
@component
public class sendredpack implements serializable{
/**
*
*/
private static final long serialversionuid = -1000489228099916099l;
private string nonce_str; // 随机字符串
private string sign; // 签名
private string mch_billno; // 商户订单号
private string mch_id; // 商户号
private string wxappid; // 公众账号
private string send_name; // 商户名称
private string re_openid; // 用户
private int total_amount; // 付款金额 单位:分
private int total_num; // 红包发放总人数
private string wishing; // 红包祝福语
private string client_ip; // ip地址
private string act_name; // 活动名称
private string remark; // 备注
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 getre_openid() {
return re_openid;
}
public void setre_openid(string re_openid) {
this .re_openid = re_openid;
}
public int gettotal_amount() {
return total_amount;
}
public void settotal_amount( int total_amount) {
this .total_amount = total_amount;
}
public int gettotal_num() {
return total_num;
}
public void settotal_num( int total_num) {
this .total_num = total_num;
}
public string getwishing() {
return wishing;
}
public void setwishing(string wishing) {
this .wishing = wishing;
}
public string getclient_ip() {
return client_ip;
}
public void setclient_ip(string client_ip) {
this .client_ip = client_ip;
}
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;
}
}
|
接下来是发送红包的控制器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
/**
* 领红包控制器
* @author zengliang
*/
@controller
@requestmapping (value= "/redenvelopesreceive" )
public class redenvelopesreceivecontroller {
//微信唯一标识
@value ( "${weixin.appid}" )
private string appid;
//微信开发者密码标识
@value ( "${weixin.appsecret}" )
public string appsecret;
@autowired
private sendredpack sendredpack;
@autowired
private httpclientssl httpclientssl;
/**
* 发送xml参数
* @author zengliang
*/
@responsebody
@requestmapping (value= "/sendxml" )
public string sendxml(string openid, long redenvelopes_id
,string mch_billno){
redenvelopes redenve = redenvelopesservice.findone(redenvelopes_id);
xmlutil xmlutil= new xmlutil();
sendredpack.setact_name(redenve.getact_name());
sendredpack.setnonce_str(xmlutil.random());
sendredpack.setre_openid(openid);
sendredpack.setclient_ip(redenve.getclient_ip());
sendredpack.setmch_billno(mch_billno);
sendredpack.setmch_id(redenve.getmch_id());
string xx = redenve.getremark();
sendredpack.setremark(stringutils.isempty(xx) == false ?xx: "空" );
sendredpack.setsend_name(redenve.getsend_name());
sendredpack.settotal_amount(redenve.gettotal_amount());
sendredpack.settotal_num(redenve.gettotal_num());
sendredpack.setwishing(redenve.getwishing());
sendredpack.setwxappid(redenve.getwxappidxx());
//生成签名
string params = this .createsendredpackordersign(sendredpack,redenve.getstore_key());
sendredpack.setsign(params);
xmlutil.xstream().alias( "xml" ,sendredpack.getclass());
//扩展xstream,使其支持cdata块
string requestxml = xmlutil.xstream().toxml(sendredpack);
string result;
try {
result = httpclientssl.send( "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack" ,requestxml,httpclientssl.defaultsslclientfile());
system.out.println( "成功返回值" +result);
return result;
} catch (unsupportedencodingexception e) {
e.printstacktrace();
}
return null ;
}
/**
* 生成签名
* @param redpack
* @return
*/
public string createsendredpackordersign(sendredpack redpack,string storekey){
stringbuffer sign = new stringbuffer();
sign.append( "act_name=" ).append(redpack.getact_name());
sign.append( "&client_ip=" ).append(redpack.getclient_ip());
sign.append( "&mch_billno=" ).append(redpack.getmch_billno());
sign.append( "&mch_id=" ).append(redpack.getmch_id());
sign.append( "&nonce_str=" ).append(redpack.getnonce_str());
sign.append( "&re_openid=" ).append(redpack.getre_openid());
sign.append( "&remark=" ).append(redpack.getremark());
sign.append( "&send_name=" ).append(redpack.getsend_name());
sign.append( "&total_amount=" ).append(redpack.gettotal_amount());
sign.append( "&total_num=" ).append(redpack.gettotal_num());
sign.append( "&wishing=" ).append(redpack.getwishing());
sign.append( "&wxappid=" ).append(redpack.getwxappid());
sign.append( "&key=" ).append(storekey);
return digestutils.md5hex(sign.tostring()).touppercase();
}
}
|
然后我们需要用一个解析xml的工具类实现解析微信返回的xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
/**
* 解析xml工具类
* @author zengliang
*/
@component
public class xmlutil {
/**
* 解析微信返回的xml
* @param xml
* @return
* @throws exception
*/
@suppresswarnings ( "unchecked" )
public map<string, string> parsexml(string xml) throws exception {
map<string,string> map = new hashmap<string,string>();
document doc = null ;
try {
doc = documenthelper.parsetext(xml); // 将字符串转为xml
element rootelt = doc.getrootelement(); // 获取根节点
list<element> list = rootelt.elements(); //获取根节点下所有节点
for (element element : list) { //遍历节点
map.put(element.getname(), element.gettext()); //节点的name为map的key,text为map的value
}
} catch (documentexception e) {
e.printstacktrace();
} catch (exception e) {
e.printstacktrace();
}
return map;
}
/**
* 扩展xstream,使其支持cdata块
*/
private xstream xstream = new xstream( new xppdriver( new nonamecoder()) {
@override
public hierarchicalstreamwriter createwriter(writer out) {
return new prettyprintwriter(out) {
// 对所有xml节点的转换都增加cdata标记
boolean cdata = true ;
@override
@suppresswarnings ( "rawtypes" )
public void startnode(string name, class clazz) {
super .startnode(name, clazz);
}
@override
public string encodenode(string name) {
return name;
}
@override
protected void writetext(quickwriter writer, string text) {
if (cdata) {
writer.write( "<![cdata[" );
writer.write(text);
writer.write( "]]>" );
} else {
writer.write(text);
}
}
};
}
});
private xstream inclueunderlinexstream = new xstream( new domdriver( null , new xmlfriendlynamecoder( "_-" , "_" )));
public xstream getxstreaminclueunderline() {
return inclueunderlinexstream;
}
public xstream xstream() {
return xstream;
}
/**
* 生成随机数
* @return
*/
public string random(){
string random = uuid.randomuuid().tostring().replace( "-" , "" );
return random;
}
}
|
然后我们调用 sendxml 方法公众号就能向用户发送红包了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u010088415/article/details/79942302