项目描述:基于微信浏览器的H5页面,接入微信支付接口和微信红包接口
一、接入前准备条件
需要基于已认证的微信公众号承载该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 }
三、总结