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

时间:2022-11-17 16:54:42

我们先来看看公众号发放现金红包的效果:

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

需要调用商户平台的接口,接口发放规则如下:

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

请求数据示例:

 

java" id="highlighter_82073">
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<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>

接口需要调用商户平台的证书,证书需要去商户平台下载:

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

然后在接口中使用证书,首先我们新建一个weixinssl 类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@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 请求加证书:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
@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 的参数签名:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* 红包参数实体类
 * @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;
  }
}

接下来是发送红包的控制器:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/**
 * 领红包控制器
 * @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

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 * 解析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 方法公众号就能向用户发送红包了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/u010088415/article/details/79942302