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 }
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 }
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 /********************************************/
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 }
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 }
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 }
8.准备工作完毕,开始实现小程序支付,退款,提现功能。