微信企业红包api接入

  项目描述:基于微信浏览器的H5页面,接入微信支付接口和微信红包接口

一、接入前准备条件

1.微信公众号

  需要基于已认证的微信公众号承载该H5页面。该条件默认已具备,本文重点为红包接口。

2.微信支付商户平台

2.1官方api文档,发放前准备事项,详细阅读!

https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_3&index=2

2.2重点内容解读

  1、在满足开通红包权限的前提条件下,在开通该权限时,微信支付平台需要操作人下载对应安全控件及证书,保证操作环境安全性!

  2、充值微信支付账号,大概意思是将银行中的钱预存到平台作为红包金池,已发放的红包金额将从该池中扣减。操作步骤见api文档。

  3、openid是微信用户在该公众号下的唯一标识,与微信号1对1映射,微信出于用户隐私考虑,使用虚拟id去关联微信用户,所以无法获取微信号。有这方面想法的同学趁早放弃...所以我们支付或发送红包使用openid即可。

  4、本文使用红包接口调用的方式实现红包发放功能,api文档中第五条相关参数设置可以略过!

二、红包api接入

1.官方api文档,发放普通红包

https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3

2.重点内容解读

2.1证书问题

  根据证书使用说明.txt中的描述,JAVA后端为例,使用的证书是.p12格式

  

  windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户ID(如:10010000),在发送POST请求时一定要携带该证书的信息在请求中,具体见代码:

 1 /**
 2      *  url 请求url       
 3         xmlParam 请求参数       
 4         keyStorePath  本地证书路径
 5      */
 6     public static Map getMwebUrl(String url, String xmlParam, String keyStorePath) {
 7          StringBuffer message = new StringBuffer();
 8          String jsonStr = null;
 9           Map map = new HashMap();   
10          try {
11                 //商户id,证书的默认密码
12                 String mchId = PropertyUtil.MERID;
13                 KeyStore keyStore  = KeyStore.getInstance("PKCS12");
14                //本地证书
15                 FileInputStream instream = new FileInputStream(new File(keyStorePath));
16                 keyStore.load(instream, mchId.toCharArray());
17                 SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
18                 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
19                 CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
20                 //注意这里是post
21                 HttpPost httpost = new HttpPost(url);
22                 httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
23                 System.out.println("executing request" + httpost.getRequestLine());
24                 CloseableHttpResponse response = httpclient.execute(httpost);
25                
26                 try {
27                     HttpEntity entity = response.getEntity();
28                     System.out.println(response.getStatusLine());
29                     if (entity != null) {
30                         System.out.println("Response content length: " + entity.getContentLength());
31                         BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
32                         //以下为返回参数的处理,根据需求自行修改
33                         String text;
34                         while ((text = bufferedReader.readLine()) != null) {
35                             message.append(text);
36                         }
37                         jsonStr = message.toString();
38                         map = XMLUtils.parseXmlToList(jsonStr);
39                     }
40                     EntityUtils.consume(entity);
41                 } catch (IOException e) {
42                     e.printStackTrace();
43                 } finally {
44                     response.close();
45                 }
46             } catch (Exception e1) {
47                 e1.printStackTrace();
48             } 
49             return map;
50     }

2.2请求参数问题

  2019年8月该api请求必填参数为12个,详见api文档,这里只有签名sign字段需要说明,其余字段非常直观!

签名

详见签名生成算法,以下为sign参数生成代码,仅供参考

 1 /**
 2     parameters 将所有非空参数装载进SortedMap
 3 */
 4 public static String createSign(SortedMap<String,Object> parameters){
 5         StringBuffer sb = new StringBuffer();
 6         //所有参与传参的参数按照accsii排序(升序)
 7         Set es = parameters.entrySet();
 8         Iterator it = es.iterator();
 9         while(it.hasNext()) {
10             Map.Entry entry = (Map.Entry)it.next();
11             String k = (String)entry.getKey();
12             Object v = entry.getValue();
13             //不能包含sign属性及key属性,不需要CDATA模板
14             if(null != v && !"".equals(v)
15                     && !"sign".equals(k) && !"key".equals(k)) {
16                 sb.append(k + "=" + v + "&");
17             }
18         }
19         //商户平台设置的密钥key
20         //◆ key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
21         sb.append("key=" + PropertyUtil.SIGNKEY );
22         String sign = "";
23         try {
24             //MD5加密及中文支持,并转换成全大写
25             sign = MD5Utils.getMessageDigest(sb.toString().getBytes("utf-8")).toUpperCase();
26         } catch (UnsupportedEncodingException e) {
27             e.printStackTrace();
28         }
29         return sign;
30     }

  补充 :nonce_str参数,随机字符串的生成算法

 1 import java.security.MessageDigest;
 2 public class MD5Utils {
 3     public final static String getMessageDigest(byte[] buffer) {
 4         char hexDigits[] = 
 5         { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 6         try {
 7             MessageDigest mdTemp = MessageDigest.getInstance("MD5");
 8             mdTemp.update(buffer);
 9             byte[] md = mdTemp.digest();
10             int j = md.length;
11             char str[] = new char[j * 2];
12             int k = 0;
13             for (int i = 0; i < j; i++) {
14                 byte byte0 = md[i];
15                 str[k++] = hexDigits[byte0 >>> 4 & 0xf];
16                 str[k++] = hexDigits[byte0 & 0xf];
17             }
18             return new String(str);
19         } catch (Exception e) {
20             return null;
21         }
22     }
23 }

三、总结

  在接触微信系列的内容之前,接收各种对微信api的吐槽,但是接触了之后发现,他们说的还真对...(甩梗,咳咳)相较阿里的api腾讯的参数描述、步骤指引等不够明确,但仍在可接受的范围之内,退一步讲,以前我没得选,现在也没得选!

posted @ 2019-08-28 10:40  2JZ  阅读(592)  评论(0编辑  收藏  举报