微信小程序支付(基于Java实现微信JSAPI支付):SDK与DEMO下载整理

时间:2024-02-26 10:22:48

Java语言开发微信小程序支付功能:

1.通过https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1路径到官方下载Java的支付SDK。

2.下载后将pom文件中需要用到的jar包导入自己的项目中,将demo全部导入到自己的工具包中,需导入的demo如下图:

3.此时缺少IWXPayDomain与WXPayConfig抽象类的具体实现,新建WXPayDomainSimpleImpl与WXPayConfigImpl来分别实现抽象类,代码如下:

WXPayDomainSimpleImpl代码:

 1 package com.karat.cn.util;
 2 import org.apache.http.conn.ConnectTimeoutException;
 3 
 4 import java.net.UnknownHostException;
 5 import java.util.HashMap;
 6 import java.util.Map;
 7 
 8 /**
 9  * Created by blaketang on 2017/6/16.
10  */
11 public class WXPayDomainSimpleImpl implements IWXPayDomain {
12     private WXPayDomainSimpleImpl(){}
13     private static class WxpayDomainHolder{
14         private static IWXPayDomain holder = new WXPayDomainSimpleImpl();
15     }
16     public static IWXPayDomain instance(){
17         return WxpayDomainHolder.holder;
18     }
19 
20     public synchronized void report(final String domain, long elapsedTimeMillis, final Exception ex) {
21         DomainStatics info = domainData.get(domain);
22         if(info == null){
23             info = new DomainStatics(domain);
24             domainData.put(domain, info);
25         }
26 
27         if(ex == null){ //success
28             if(info.succCount >= 2){    //continue succ, clear error count
29                 info.connectTimeoutCount = info.dnsErrorCount = info.otherErrorCount = 0;
30             }else{
31                 ++info.succCount;
32             }
33         }else if(ex instanceof ConnectTimeoutException){
34             info.succCount = info.dnsErrorCount = 0;
35             ++info.connectTimeoutCount;
36         }else if(ex instanceof UnknownHostException){
37             info.succCount = 0;
38             ++info.dnsErrorCount;
39         }else{
40             info.succCount = 0;
41             ++info.otherErrorCount;
42         }
43     }
44 
45     public synchronized DomainInfo getDomain(final WXPayConfig config) {
46         DomainStatics primaryDomain = domainData.get(WXPayConstants.DOMAIN_API);
47         if(primaryDomain == null ||
48                 primaryDomain.isGood()) {
49             return new DomainInfo(WXPayConstants.DOMAIN_API, true);
50         }
51 
52         long now = System.currentTimeMillis();
53         if(switchToAlternateDomainTime == 0){   //first switch
54             switchToAlternateDomainTime = now;
55             return new DomainInfo(WXPayConstants.DOMAIN_API2, false);
56         }else if(now - switchToAlternateDomainTime < MIN_SWITCH_PRIMARY_MSEC){
57             DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);
58             if(alternateDomain == null ||
59                 alternateDomain.isGood() ||
60                 alternateDomain.badCount() < primaryDomain.badCount()){
61                 return new DomainInfo(WXPayConstants.DOMAIN_API2, false);
62             }else{
63                 return new DomainInfo(WXPayConstants.DOMAIN_API, true);
64             }
65         }else{  //force switch back
66             switchToAlternateDomainTime = 0;
67             primaryDomain.resetCount();
68             DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);
69             if(alternateDomain != null)
70                 alternateDomain.resetCount();
71             return new DomainInfo(WXPayConstants.DOMAIN_API, true);
72         }
73     }
74 
75     static class DomainStatics {
76         final String domain;
77         int succCount = 0;
78         int connectTimeoutCount = 0;
79         int dnsErrorCount =0;
80         int otherErrorCount = 0;
81 
82         DomainStatics(String domain) {
83             this.domain = domain;
84         }
85         void resetCount(){
86             succCount = connectTimeoutCount = dnsErrorCount = otherErrorCount = 0;
87         }
88         boolean isGood(){ return connectTimeoutCount <= 2 && dnsErrorCount <= 2; }
89         int badCount(){
90             return connectTimeoutCount + dnsErrorCount * 5 + otherErrorCount / 4;
91         }
92     }
93     private final int MIN_SWITCH_PRIMARY_MSEC = 3 * 60 * 1000;  //3 minutes
94     private long switchToAlternateDomainTime = 0;
95     private Map<String, DomainStatics> domainData = new HashMap<String, DomainStatics>();
96 }
View Code

WXPayConfigImpl代码:

 1 package com.karat.cn.util;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.ByteArrayInputStream;
 6 import java.io.InputStream;
 7 
 8 
 9 public class WXPayConfigImpl extends WXPayConfig{
10 
11     /**==========================================================================**/
12     private byte[] certData;
13     private static WXPayConfigImpl INSTANCE;
14 
15     private WXPayConfigImpl() throws Exception{
16         String certPath = WXPayConfigImpl.class.getClassLoader().getResource("").getPath();
17         File file = new File(certPath + "apiclient_cert.p12");
18         InputStream certStream = new FileInputStream(file);
19         this.certData = new byte[(int) file.length()];
20         certStream.read(this.certData);
21         certStream.close();
22     }
23 
24     public static WXPayConfigImpl getInstance() throws Exception{
25         if (INSTANCE == null) {
26             synchronized (WXPayConfigImpl.class) {
27                 if (INSTANCE == null) {
28                     INSTANCE = new WXPayConfigImpl();
29                 }
30             }
31         }
32         return INSTANCE;
33     }
34     
35     /**==========================================================================**/
36     @Override
37     public String getAppID() {
38         // TODO Auto-generated method stub
39         return "小程序AppId";
40     }
41 
42     @Override
43     public String getMchID() {
44         // TODO Auto-generated method stub
45         return "商户号";
46     }
47 
48     @Override
49     public String getKey() {
50         // TODO Auto-generated method stub
51         return "商户密钥";
52     }
53 
54     @Override
55     public InputStream getCertStream() {
56         // TODO Auto-generated method stub
57         ByteArrayInputStream certBis;
58         certBis = new ByteArrayInputStream(this.certData);
59         return certBis;
60     }
61 
62     @Override
63     public IWXPayDomain getWXPayDomain() {
64         // TODO Auto-generated method stub
65         return WXPayDomainSimpleImpl.instance();
66     }
67 
68 }
View Code

4.向WXPayConstants.java中添加常量:

1 public static final String TRANSFERS_URL_SUFFIX = "/mmpaymkttransfers/promotion/transfers";
2 public static final String SANDBOX_SENDREDPACK_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/sendredpack";
3 public static final String SANDBOX_TRANSFERS_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/promotion/transfers";

5.向WXPay.java中添加如下代码:

 1 /********************************************/
 2     // 企业付款
 3     public String transfers(Map<String, String> reqData) throws Exception {
 4         return this.transfers(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
 5     }
 6     public String transfers(Map<String, String> reqData,  int connectTimeoutMs, int readTimeoutMs) throws Exception {
 7         String url;
 8         if (this.useSandbox) {
 9             url = WXPayConstants.SANDBOX_TRANSFERS_URL_SUFFIX;
10         }
11         else {
12             url = WXPayConstants.TRANSFERS_URL_SUFFIX;
13         }
14         return this.requestWithCert(url, this.transfersRequestData(reqData), connectTimeoutMs, readTimeoutMs);
15     }
16     // 企业付款
17     public Map<String, String> transfersRequestData(Map<String, String> reqData) throws Exception {
18         // 商户号绑定的appid(小程序的appid)
19         reqData.put("mch_appid", config.getAppID());
20         // 商户号
21         reqData.put("mchid", config.getMchID());
22         // 随机字符串
23         reqData.put("nonce_str", WXPayUtil.generateUUID());
24         reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
25         return reqData;
26     }
27     
28     /********************************************/
View Code

6.创建订单表以及返回给小程序端的参数vo

  1 package com.karat.cn.wxCommon;
  2 
  3 import java.util.Map;
  4 
  5 import org.springframework.data.annotation.Id;
  6 import org.springframework.data.mongodb.core.index.Indexed;
  7 import org.springframework.data.mongodb.core.mapping.Document;
  8 
  9 /**
 10  * 订单表
 11  * @author 开发
 12  *
 13  */
 14 @Document(collection = "wxWithdrawOrder")
 15 public class WxWithdrawOrder {
 16     /**
 17      * id
 18      */
 19     @Id
 20     private String id;
 21     /**
 22      * 会员id
 23      */
 24     @Indexed
 25     private String memberId;
 26     /**
 27      * 订单号
 28      */
 29     @Indexed(unique = true)
 30     private String orderNo;
 31     /**
 32      * 提现金额(分)
 33      */
 34     private int money;
 35     /**
 36      * 提现时间
 37      */
 38     private String createDate;
 39     /**
 40      * 订单状态(0:申请失败或异常 1:已申请成功)
 41      */
 42     private String orderStatus;
 43     /**
 44      * 扩展
 45      */
 46     private Map<String, String> remark;
 47     /**
 48      * 扩展2
 49      */
 50     private String remark2;
 51     
 52     
 53     public String getId() {
 54         return id;
 55     }
 56     public void setId(String id) {
 57         this.id = id;
 58     }
 59     public String getMemberId() {
 60         return memberId;
 61     }
 62     public void setMemberId(String memberId) {
 63         this.memberId = memberId;
 64     }
 65     public String getOrderNo() {
 66         return orderNo;
 67     }
 68     public void setOrderNo(String orderNo) {
 69         this.orderNo = orderNo;
 70     }
 71     public int getMoney() {
 72         return money;
 73     }
 74     public void setMoney(int money) {
 75         this.money = money;
 76     }
 77     public String getCreateDate() {
 78         return createDate;
 79     }
 80     public void setCreateDate(String createDate) {
 81         this.createDate = createDate;
 82     }
 83     public Map<String, String> getRemark() {
 84         return remark;
 85     }
 86     public void setRemark(Map<String, String> remark) {
 87         this.remark = remark;
 88     }
 89     public String getRemark2() {
 90         return remark2;
 91     }
 92     public void setRemark2(String remark2) {
 93         this.remark2 = remark2;
 94     }
 95     public String getOrderStatus() {
 96         return orderStatus;
 97     }
 98     public void setOrderStatus(String orderStatus) {
 99         this.orderStatus = orderStatus;
100     }
101 }
View Code
 1 package com.karat.cn.vo;
 2 /**
 3  *  调用微信支付相关信息
 4  * @author 开发
 5  *
 6  */
 7 public class VoUnifiedOrderWx {
 8     // 时间戳
 9     private String timeStamp;
10     // 随机串
11     private String nonceStr;
12     // 数据包
13     private String packageValue;
14     // 签名
15     private String sign;
16     
17     public String getTimeStamp() {
18         return timeStamp;
19     }
20     public void setTimeStamp(String timeStamp) {
21         this.timeStamp = timeStamp;
22     }
23     public String getNonceStr() {
24         return nonceStr;
25     }
26     public void setNonceStr(String nonceStr) {
27         this.nonceStr = nonceStr;
28     }
29     public String getPackageValue() {
30         return packageValue;
31     }
32     public void setPackageValue(String packageValue) {
33         this.packageValue = packageValue;
34     }
35     public String getSign() {
36         return sign;
37     }
38     public void setSign(String sign) {
39         this.sign = sign;
40     }
41     
42 }
View Code

7.创建工具类(获取系统时间)

 1 package com.karat.cn.wxCommon;
 2 
 3 import java.text.ParseException;
 4 import java.util.Date;
 5 
 6 public class BaseToolsUtil {
 7     /**
 8      * 获取系统时间long
 9      * 
10      * @return
11      * @throws ParseException
12      */
13     public static long systemtimeLong() {
14         return new Date().getTime();
15     }
16 }
View Code

8.准备工作完毕,开始实现小程序支付,退款,提现功能。