我们先来看看公众号发放现金红包的效果:
需要调用商户平台的接口,接口发放规则如下:
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 方法公众号就能向用户发送红包了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍php微信公众号开发之现金红包,包括了php微信公众号开发之现金红包的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了php微信公众号之现金红包的具体代码,供大家参考,具体内容如下 以下有关微信支付中现金红包的开发参考自微信支付开发文档,如下图所示。 现金红包,是微信支付商户平台提供的营销工具之一,上线以来深受广大商户与用户的喜爱。商户可以通过本平台向微信支付用户发放现金
本文向大家介绍nodejs微信公众号支付开发,包括了nodejs微信公众号支付开发的使用技巧和注意事项,需要的朋友参考一下 odeJs 微信公众号功能开发,移动端 H5页面调用微信的支付功能。这几天根据公司的需要使用 node 和 h5页面调用微信的支付功能完成支付需求。现在把开发过程重新捋一遍,以帮助更多的开发者顺利的完成微信支付功能的开发。(微信暂时还没有提供 node 的支付功能) 一.请求
上一篇我们介绍了在h5 app 开发微信支付, 这篇我们说一说在微信公众号开发支付。 目录 环境准备 1 需要一个有支付能力的公众号 2 wex5 3.3 及以上版本 3 备案好的域名 4 微信web开发者工具 开发步骤 1 取得参数 2 编译Baas 3 基本URL配置 4 JS接口安全域名、授权回调页域名配置 5 开发UI 5.1 修改参数 5.2 修改代码二 6 配置微信支付授权目录 7
本文向大家介绍Java版微信公众号支付开发全过程,包括了Java版微信公众号支付开发全过程的使用技巧和注意事项,需要的朋友参考一下 一、微信官方文档微信支付开发流程(公众号支付) 首先我们到微信支付的官方文档的开发步骤部分查看一下需要的设置。 [图片上传失败...(image-5eb825-1531014079742)] 因为微信支付需要较高的权限,只有认证了得服务号才有使用微信支付接口的权限,我
本文向大家介绍PHP微信公众号开发之微信红包实现方法分析,包括了PHP微信公众号开发之微信红包实现方法分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP微信公众号开发之微信红包实现方法。分享给大家供大家参考,具体如下: 这几天遇到了一个客户 要给他们的微信公众平台上添加微信现金红包功能,是个二次开发的功能,顺手百度一下,原来不复杂。就着手开发功能了。现将开发的过程和需求贴出来分享一
本文向大家介绍java微信公众号支付示例详解,包括了java微信公众号支付示例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了java微信公众号支付示例代码,供大家参考,具体内容如下 开始之前,先准备好:appid、商家号、商户密匙。 工具类: MD5Util.java SapUtils.java UnifiedOrderRequest.java UnifiedOrderResp