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代码:

 package com.karat.cn.util;
import org.apache.http.conn.ConnectTimeoutException; import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map; /**
* Created by blaketang on 2017/6/16.
*/
public class WXPayDomainSimpleImpl implements IWXPayDomain {
private WXPayDomainSimpleImpl(){}
private static class WxpayDomainHolder{
private static IWXPayDomain holder = new WXPayDomainSimpleImpl();
}
public static IWXPayDomain instance(){
return WxpayDomainHolder.holder;
} public synchronized void report(final String domain, long elapsedTimeMillis, final Exception ex) {
DomainStatics info = domainData.get(domain);
if(info == null){
info = new DomainStatics(domain);
domainData.put(domain, info);
} if(ex == null){ //success
if(info.succCount >= 2){ //continue succ, clear error count
info.connectTimeoutCount = info.dnsErrorCount = info.otherErrorCount = 0;
}else{
++info.succCount;
}
}else if(ex instanceof ConnectTimeoutException){
info.succCount = info.dnsErrorCount = 0;
++info.connectTimeoutCount;
}else if(ex instanceof UnknownHostException){
info.succCount = 0;
++info.dnsErrorCount;
}else{
info.succCount = 0;
++info.otherErrorCount;
}
} public synchronized DomainInfo getDomain(final WXPayConfig config) {
DomainStatics primaryDomain = domainData.get(WXPayConstants.DOMAIN_API);
if(primaryDomain == null ||
primaryDomain.isGood()) {
return new DomainInfo(WXPayConstants.DOMAIN_API, true);
} long now = System.currentTimeMillis();
if(switchToAlternateDomainTime == 0){ //first switch
switchToAlternateDomainTime = now;
return new DomainInfo(WXPayConstants.DOMAIN_API2, false);
}else if(now - switchToAlternateDomainTime < MIN_SWITCH_PRIMARY_MSEC){
DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);
if(alternateDomain == null ||
alternateDomain.isGood() ||
alternateDomain.badCount() < primaryDomain.badCount()){
return new DomainInfo(WXPayConstants.DOMAIN_API2, false);
}else{
return new DomainInfo(WXPayConstants.DOMAIN_API, true);
}
}else{ //force switch back
switchToAlternateDomainTime = 0;
primaryDomain.resetCount();
DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);
if(alternateDomain != null)
alternateDomain.resetCount();
return new DomainInfo(WXPayConstants.DOMAIN_API, true);
}
} static class DomainStatics {
final String domain;
int succCount = 0;
int connectTimeoutCount = 0;
int dnsErrorCount =0;
int otherErrorCount = 0; DomainStatics(String domain) {
this.domain = domain;
}
void resetCount(){
succCount = connectTimeoutCount = dnsErrorCount = otherErrorCount = 0;
}
boolean isGood(){ return connectTimeoutCount <= 2 && dnsErrorCount <= 2; }
int badCount(){
return connectTimeoutCount + dnsErrorCount * 5 + otherErrorCount / 4;
}
}
private final int MIN_SWITCH_PRIMARY_MSEC = 3 * 60 * 1000; //3 minutes
private long switchToAlternateDomainTime = 0;
private Map<String, DomainStatics> domainData = new HashMap<String, DomainStatics>();
}

WXPayConfigImpl代码:

 package com.karat.cn.util;

 import java.io.File;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream; public class WXPayConfigImpl extends WXPayConfig{ /**==========================================================================**/
private byte[] certData;
private static WXPayConfigImpl INSTANCE; private WXPayConfigImpl() throws Exception{
String certPath = WXPayConfigImpl.class.getClassLoader().getResource("").getPath();
File file = new File(certPath + "apiclient_cert.p12");
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
} public static WXPayConfigImpl getInstance() throws Exception{
if (INSTANCE == null) {
synchronized (WXPayConfigImpl.class) {
if (INSTANCE == null) {
INSTANCE = new WXPayConfigImpl();
}
}
}
return INSTANCE;
} /**==========================================================================**/
@Override
public String getAppID() {
// TODO Auto-generated method stub
return "小程序AppId";
} @Override
public String getMchID() {
// TODO Auto-generated method stub
return "商户号";
} @Override
public String getKey() {
// TODO Auto-generated method stub
return "商户密钥";
} @Override
public InputStream getCertStream() {
// TODO Auto-generated method stub
ByteArrayInputStream certBis;
certBis = new ByteArrayInputStream(this.certData);
return certBis;
} @Override
public IWXPayDomain getWXPayDomain() {
// TODO Auto-generated method stub
return WXPayDomainSimpleImpl.instance();
} }

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

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

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

 /********************************************/
// 企业付款
public String transfers(Map<String, String> reqData) throws Exception {
return this.transfers(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
public String transfers(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = WXPayConstants.SANDBOX_TRANSFERS_URL_SUFFIX;
}
else {
url = WXPayConstants.TRANSFERS_URL_SUFFIX;
}
return this.requestWithCert(url, this.transfersRequestData(reqData), connectTimeoutMs, readTimeoutMs);
}
// 企业付款
public Map<String, String> transfersRequestData(Map<String, String> reqData) throws Exception {
// 商户号绑定的appid(小程序的appid)
reqData.put("mch_appid", config.getAppID());
// 商户号
reqData.put("mchid", config.getMchID());
// 随机字符串
reqData.put("nonce_str", WXPayUtil.generateUUID());
reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
return reqData;
} /********************************************/

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

 package com.karat.cn.wxCommon;

 import java.util.Map;

 import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document; /**
* 订单表
* @author 开发
*
*/
@Document(collection = "wxWithdrawOrder")
public class WxWithdrawOrder {
/**
* id
*/
@Id
private String id;
/**
* 会员id
*/
@Indexed
private String memberId;
/**
* 订单号
*/
@Indexed(unique = true)
private String orderNo;
/**
* 提现金额(分)
*/
private int money;
/**
* 提现时间
*/
private String createDate;
/**
* 订单状态(0:申请失败或异常 1:已申请成功)
*/
private String orderStatus;
/**
* 扩展
*/
private Map<String, String> remark;
/**
* 扩展2
*/
private String remark2; public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMemberId() {
return memberId;
}
public void setMemberId(String memberId) {
this.memberId = memberId;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getCreateDate() {
return createDate;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
public Map<String, String> getRemark() {
return remark;
}
public void setRemark(Map<String, String> remark) {
this.remark = remark;
}
public String getRemark2() {
return remark2;
}
public void setRemark2(String remark2) {
this.remark2 = remark2;
}
public String getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(String orderStatus) {
this.orderStatus = orderStatus;
}
}
 package com.karat.cn.vo;
/**
* 调用微信支付相关信息
* @author 开发
*
*/
public class VoUnifiedOrderWx {
// 时间戳
private String timeStamp;
// 随机串
private String nonceStr;
// 数据包
private String packageValue;
// 签名
private String sign; public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String getPackageValue() {
return packageValue;
}
public void setPackageValue(String packageValue) {
this.packageValue = packageValue;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
} }

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

 package com.karat.cn.wxCommon;

 import java.text.ParseException;
import java.util.Date; public class BaseToolsUtil {
/**
* 获取系统时间long
*
* @return
* @throws ParseException
*/
public static long systemtimeLong() {
return new Date().getTime();
}
}

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

Java实现微信小程序支付(准备)的更多相关文章

  1. Java 后端微信小程序支付demo (网上说的坑里面基本上都有)

    Java 后端微信小程序支付 一.遇到的问题 1. 商户号该产品权限未开通,请前往商户平台>产品中心检查后重试 2.签名错误 3.已经调起微信统一下单接口,可以拿到预支付ID,但是前端支付的时候 ...

  2. Java实现微信小程序支付(完整版)

    在开发微信小程序支付的功能前,我们先熟悉下微信小程序支付的业务流程图: 不熟悉流程的建议还是仔细阅读微信官方的开发者文档. 一,准备工作 事先需要申请企业版小程序,并开通“微信支付”(即商户功能).并 ...

  3. Java实现微信小程序支付(支付,提现,退款)

    1.添加WXpayCommon类用以具体实现功能,代码如下: package com.karat.cn.wxCommon; import java.io.IOException; import jav ...

  4. 【原创】微信小程序支付java后台案例(公众号支付同适用)(签名错误问题)

    前言 1.微信小程序支付官方接口文档:[点击查看微信开放平台api开发文档]2.遇到的坑:预支付统一下单签名结果返回[签名错误]失败,建议用官方[签名验证工具]检查签名是否存在问题.3.遇到的坑:签名 ...

  5. 微信小程序支付开发之申请退款

    微信小程序支付跟微信公众号支付类似,这里不另做记录,如果没有开发过支付,可以查看我关于微信支付的文章 重点记录微信小程序申请退款开发过程中遇到一些坑. 退款接口比支付接口接口多了一个 双向证书 证书介 ...

  6. SpringBoot2.0微信小程序支付多次回调问题

    SpringBoot2.0微信小程序支付多次回调问题 WxJava - 微信开发 Java SDK(开发工具包); 支持包括微信支付.开放平台.公众号.企业微信/企业号.小程序等微信功能的后端开发. ...

  7. 微信小程序支付步骤

    http://blog.csdn.net/wangsf789/article/details/53419781 最近开发微信小程序进入到支付阶段,一直以来从事App开发,所以支付流程还是熟记于心的.但 ...

  8. 微信小程序支付及退款流程详解

    微信小程序的支付和退款流程 近期在做微信小程序时,涉及到了小程序的支付和退款流程,所以也大概的将这方面的东西看了一个遍,就在这篇博客里总结一下. 首先说明一下,微信小程序支付的主要逻辑集中在后端,前端 ...

  9. php对接微信小程序支付

    前言:这里我就假装你已经注册了微信小程序,并且基本的配置都已经好了.注: 个人注册小程序不支持微信支付,所以我还是假装你是企业或者个体工商户的微信小程序,其他的商户号注册,二者绑定,授权,支付开通,就 ...

随机推荐

  1. Solaris11修改主机名

    在Solaris10中,主机名的修改是通过修改相关的配置文件实现的.在Solaris11中,主机名的配置信息已经转移到SMF配置库中,因此修改主机名的方式与Solaris10完全不同.以下是修改Sol ...

  2. Oracle 11g oracle 用户密码过期问题 (ZT)

    http://www.blogjava.net/freeman1984/archive/2013/04/23/398301.html Oracle 11g 之前默认的用户时是没有密码过期的限制的,在O ...

  3. linux下mysql 最新版安装图解教程

    1.查看当前安装的linux版本 命令:lsb_release -a 如下图所示 通过上图中的数据可以看出安装的版本为RedHat5.4,所以我们需要下载RedHat5.4对应的mysql安装包 2. ...

  4. xftp的简单使用

    1.下载并安装Xftp工具.打开Xftp工具,点击“新建”. 2.在“新建会话属性”中选择“名称”为主机命名,在“主机”栏输入主机IP,“协议”和“端口号”使用sftp和22,在“用户名”和“密码“栏 ...

  5. 学习计划Python-转载

    作者:闲谈后链接:https://www.zhihu.com/question/29775447/answer/145395619来源:知乎著作权归作者所有,转载请联系作者获得授权. 不过需要说明的是 ...

  6. 向linux内核增加一个系统调用-1

    验证编辑编译内核的流程,并增加新的系统调用 注意:需要/目录至少10GB空间,/boot目录500MB空间 下载内核并解压 kernel下载 百度云搬运 密码: qc8b 进入 /usr/src目录 ...

  7. jQuery-图片的放大镜显示效果(不需要大小图)

    问题:当页面高度很大时,放大图片的图层不会跟随着 1.demo.html ;display:none;}          #tip s   {position:absolute;top:40px;l ...

  8. js面试题知识点全解(一闭包)

    闭包使用场景:1.函数作为返回值,如下场景 function F1(){ var a = 100 //自由变量 //返回一个函数(函数作为返回值) return function(){ console ...

  9. SpringBoot10 整合JSP

    1 整合JSP 1.1 导入相关依赖 JSP依赖.JSTL依赖 <?xml version="1.0" encoding="UTF-8"?> < ...

  10. 【转】mysql.sock文件的作用

    Mysql有两种连接方式: (1),TCP/IP (2),socket 对mysql.sock来说,其作用是程序与mysqlserver处于同一台机器,发起本地连接时可用. (如果程序跟mysql在同 ...