我们先来看看公众号发放现金红包的效果:
需要调用商户平台的接口,接口发放规则如下:
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