微信公众平台普通红包发放 发表于 2017-04-25 | 分类于 java | 0 Comments | 阅读次数: 业务需求:在后台管理系统为微信用户发放红包,弄了好几天总算搞定了,需要注意的是获取签名部分,流程大体如下:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210//红包业务方法public int sendRedpack(HttpServletRequest request,UserAverage userAverage) throws Exception { WechatInfo wechat = getWechatInfo(request); WechatInfo wechatInfo = wechatInfoService.queryWechatinfo(wechat.getAppid()); String sendName =wechatInfo.getWxname(); //微信证书路径 String certPath =this.getClass().getResource("/").getPath()+"xxxxx/apiclient_cert.p12"; certPath = URLDecoder.decode(certPath,"UTF-8");//证书路径解码 logger.info("证书路径:"+certPath); //商户id String wxappid = wechatInfo.getAppid(); // 微信支付分配的商户号 String partner = wechatInfo.getPartnerid(); //API密钥 String paternerKey =wechatInfo.getPartnerkey(); /** * 发送普通红包 */ boolean isSend = sendredpack(wechatInfo,request, "100", "1", "恭喜您获得竞赛奖金!", "竞赛答题活动", "竞赛奖金", userAverage.getOpenid(), partner, wxappid, sendName, paternerKey, certPath); if(!isSend){ return 0; } return 1;}// 主封装方法// * @param request 获取IP// * @param total_amount 付款现金(单位分)// * @param total_num 红包发放总人数// * @param wishing 红包祝福语// * @param act_name 活动名称// * @param remark 备注// * @param reOpenid 用户openid// * @param partner 商户号// * @param wxappid 公众账号appid// * @param sendName 商户名称// * @param paternerKey 商户签名key// * @param certPath 证书路径// * @return// */ public static boolean sendredpack(WechatInfo wechatInfo,HttpServletRequest request,String total_amount,String total_num,String wishing,String act_name,String remark,String reOpenid,String partner,String wxappid,String sendName,String paternerKey,String certPath) throws Exception{ // 商户订单号 String mchBillno = RedPackUtil.createBillNo(wechatInfo); String ip ="xxx.xx.xxx.xx";//服务器IP Map<String, String> params = new HashMap<String, String>(); // 随机字符串 params.put("nonce_str", RedPackUtil.createNonce_str()); // 商户订单号 params.put("mch_billno", mchBillno); // 商户号 params.put("mch_id", partner); // 公众账号ID params.put("wxappid", wxappid); // 商户名称 params.put("send_name", sendName); // 用户OPENID params.put("re_openid", reOpenid); // 付款现金(单位分) params.put("total_amount", total_amount); // 红包发放总人数 params.put("total_num", total_num); // 红包祝福语 params.put("wishing", wishing); // 终端IP params.put("client_ip", ip); // 活动名称 params.put("act_name", act_name); // 备注 params.put("remark", remark); //创建签名 String sign = RedPackUtil.redSignal(params, paternerKey); logger.info("md5签名:"+sign); params.put("sign", sign); String xmlResult = RedPackUtil.sendRedPack(params, certPath, partner);//执行发送红包 logger.info("发送红包返回结果:"+xmlResult.toString()); Map<String, String> result = XMLUtil.xml2Map(xmlResult); logger.info("红包参数:"+result.toString()); //此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断 String return_code = result.get("return_code"); //业务结果 String result_code = result.get("result_code"); if (StringUtils.isNotBlank(return_code) && "SUCCESS".equals(return_code)) { logger.info("通信成功return_code:"+return_code); if (StringUtils.isNotBlank(result_code) && "SUCCESS".equals(result_code)) { logger.info("发送成功result_code:"+result_code); return true; }else{ logger.info("发送失败result_code:"+result_code); } }else{ logger.info("通信失败return_code:"+return_code); } return false; } /** * 生成商户订单号 * @param mch_id 商户号 * @param userId 该用户的userID * @return */public static String createBillNo(WechatInfo wechatInfo){ //组成: mch_id+yyyymmdd+10位一天内不能重复的数字 //10位一天内不能重复的数字实现方法如下: //因为每个用户绑定了userId,他们的userId不同,加上随机生成的(10-length(userId))可保证这10位数字不一样 Date dt=new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyymmdd"); String nowTime= df.format(dt); int length = 10 ; return wechatInfo.getPartnerid() + nowTime + getRandomNum(length);}/** * 生成红包参数随机数nonce_str * @return */public static String createNonce_str(){ return System.currentTimeMillis()/1000+getRandomNum(5);}/** * 生成特定位数的随机数字 * @param length * @return */public static String getRandomNum(int length) { String val = ""; Random random = new Random(); for (int i = 0; i < length; i++) { val += String.valueOf(random.nextInt(10)); } return val;}/*** @Title: redSignal * @Description: 发送红包签名生成* @param @param params* @param @return 设定文件 * @return String 返回类型 * @throws*/public static String redSignal(Map<String, String> params,String paternerKey) {SortedMap<String, String> packageParams = new TreeMap<String, String>();for (Map.Entry<String, String> m : params.entrySet()) {packageParams.put(m.getKey(), m.getValue().toString());}StringBuffer sb = new StringBuffer();Set<?> es = packageParams.entrySet();Iterator<?> it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (!StringUtils.isEmpty(v) && !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + paternerKey);System.out.println("未加密签名:"+sb.toString());String sign = MD5Util.MD5Encode(sb.toString(),"UTF-8").toUpperCase();return sign;}private static String sendRedPackUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";/** * 发送红包 * @param params 请求参数 * @param certPath 证书文件目录 * @param partner 证书密码 * @return {String} * @throws Exception */public static String sendRedPack(Map<String, String> params, String certPath, String partner) throws Exception { return doSend(sendRedPackUrl, XMLUtil.map2Xmlstring(params), certPath, partner);}public static String doSend(String url, String data , String certPath , String partner) throws Exception { KeyStore keyStore = KeyStore.getInstance("PKCS12"); FileInputStream instream = new FileInputStream(new File(certPath));//P12文件目录 try { keyStore.load(instream, partner.toCharArray());//这里写密码..默认是你的MCHID } finally { instream.close(); } SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, partner.toCharArray())//这里也是写密码的 .build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); try { HttpPost httpost = new HttpPost(url); // 设置响应头信息 httpost.addHeader("Connection", "keep-alive"); httpost.addHeader("Accept", "*/*"); httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); httpost.addHeader("Host", "api.mch.weixin.qq.com"); httpost.addHeader("X-Requested-With", "XMLHttpRequest"); httpost.addHeader("Cache-Control", "max-age=0"); httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) "); httpost.setEntity(new StringEntity(data, "UTF-8")); CloseableHttpResponse response = httpclient.execute(httpost); try { HttpEntity entity = response.getEntity(); String jsonStr = toStringInfo(response.getEntity(),"UTF-8"); EntityUtils.consume(entity); return jsonStr; } finally { response.close(); } } finally { httpclient.close(); } }