微信公支付开发之现金红包

标签: 公众号 微信 红包功能 支付
143人阅读 评论(0) 收藏 举报
分类:

我们先来看看公众号发放现金红包的效果:
这里写图片描述

需要调用商户平台的接口,接口发放规则如下:
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 方法公众号就能向用户发送红包了。

查看评论

微信公众号开发——现金红包、企业付款

先说现金红包微信商户平台配置设置基本就是如上图核心代码普通红包 /// /// 普通红包 目前支持向指定微信用户的openid发放指定金额红包 /// ...
  • u014742815
  • u014742815
  • 2016-10-21 09:08:34
  • 3136

Java微信开发之现金红包接口

1、接口文档https://pay.weixin.qq.com/wiki/doc/api/cash_coupon.php?chapter=13_52、证书下载及证书安装首先,商户调用微信红包接口时,服...
  • p_3er
  • p_3er
  • 2016-01-13 10:28:47
  • 10362

微信支付之公众号发红包和企业付款

微信现金红包,是微信支付商户平台提供的营销工具之一,上线以来深受广大商户与用户的喜爱。商户可以通过本平台向微信支付用户发放现金红包。用户领取红包后,资金到达用户微信支付零钱账户,在日常运营中为商户的营...
  • sinat_35861727
  • sinat_35861727
  • 2017-08-30 10:50:29
  • 3155

微信公众号开发----现金红包

以下有关微信支付中现金红包的开发参考自微信支付开发文档,网址为:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter...
  • qq_21429153
  • qq_21429153
  • 2017-02-06 11:45:52
  • 592

微信现金红包asp.net c#源码Demo

  • 2015年12月02日 19:51
  • 7.62MB
  • 下载

java调用微信现金红包接口的心得与体会

这几天看了下之前写的有关微信支付的博客,看的人还是挺多的,看了下留言不知道是因为博客写的不够细还是什么情况,大多都找我要源码,我觉得吧程序员还是需要有这么一个思考的过程,因此没直接给源码,俗话说“授人...
  • chenwill3
  • chenwill3
  • 2016-10-14 23:26:09
  • 5740

微信公众号可通过现金红包接口发放微信支付现金红包(附开发教程)

标签:   农历新年将至,支付宝红包打了一仗,微信在朋友圈屏蔽了它的分享,但单防守还不行,进攻才是最好的防守。昨日,微信支付现金红包接口正式开放,只需开通微信支付,即可接入现金红包。微信公众号也...
  • gavinyyb
  • gavinyyb
  • 2015-07-08 18:00:20
  • 2988

微信现金红包高级红包接口开发注意事项

本文介绍了微信现金红包高级红包接口开发注意事项。
  • Hiking_Tsang
  • Hiking_Tsang
  • 2016-10-14 15:15:28
  • 1094

微信现金红包开发(java)

最近在开发微信红包,和网友分享下。主要有两个注意点: 1. 请求发送微信红包的请求为ssl请求, 因此不能用普通的post请求开发。 2. 生成签名需要将所传的参数全部提交用来生成...
  • wangyan199366
  • wangyan199366
  • 2016-01-04 16:46:02
  • 1064

微信开发之现金红包

欢迎留言、转发 文章首发地址:http://www.jianshu.com/p/c06120bc1f5c 微信极速开发系列文章:点击这里 前几篇文章介绍了微信支付。 公众号支付、微信扫码支付、...
  • zyw_java
  • zyw_java
  • 2017-01-04 20:53:02
  • 3334
    个人资料
    等级:
    访问量: 2960
    积分: 111
    排名: 123万+