java微信公众号支付开发之现金红包
我们先来看看公众号发放现金红包的效果:
需要调用商户平台的接口,接口发放规则如下:
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
请求数据示例:
<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 类
@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 请求加证书:
@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 的参数签名:
/** * 红包参数实体类 * @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; } }
接下来是发送红包的控制器:
/** * 领红包控制器 * @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
/** * 解析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 方法公众号就能向用户发送红包了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。