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. 11-24网页基础--Js框架及学习思路

    第一部分 基本语法: 1.数据类型(字符串.小数.整数.布尔.时间日期)var s="3.14" var n=parsefloat(s) s+=5;var s="abc3 ...

  2. node install webpack -cli webpack4.xxxx

    webpack 4.xx 版本 分离了 webpack-cli ; 安装webpack4.xx 需要再安装webpack-cli;

  3. 问题:oracle 计算年龄;结果:oracle中根据生日计算年龄的问题

    SELECT FLOOR(MONTHS_BETWEEN(SYSDATE,birthday)/12,1) FROM ltteacherinfo where name='朱雪东111'这个报错ORA 00 ...

  4. 【转】TinyMCE(富文本编辑器)

    效果预览:http://www.tinymce.com/tryit/full.php [转]TinyMCE(富文本编辑器)在Asp.Net中的使用方法 转自:http://www.cnblogs.co ...

  5. C++知识点总结(四)——面向对象的编程细节总结

    1.空类的默认函数 一般情况下,对于任意一个类A,如果程序员不显示的声明和定义上述函数,C++编译器将会自动的为A产生4个public inline(公有.内联)的默认函数,这4个函数最常见的形式为: ...

  6. transient关键字的理解

    谈到这个transient这个关键字,我们应该会立马想到序列化这个过程:什么是序列化?什么又是反序列化呢?序列化就是将对象转化内成二进制,而反序列化就是就二进制文件转换成对象的过程.一旦变量使用了tr ...

  7. 百度Apollo解析——1.总介绍

    1. 概括 Apollo源码主要是c++实现的,也有少量python,主要程序在apollo/modules目录中,共18个包,功能包17个: 其中每个模块的作用如下: apollo/modules/ ...

  8. 面试题: java面试经历 已看1 抢红包如何分配每个人抢到的钱 有用 难点的面试题

    2018.03.09 深圳乐唯科技 我看了下感觉这公司貌似挺不错的,面试官人也挺好的,氛围应该很不错,可惜我实力不足,唉,接续努力,下面把面试中印象较深的三个问题写一下. 面试问题1:数据库删除重复数 ...

  9. 关于MySQL隐式转换

    一.如果表定义的是varchar字段,传入的是数字,则会发生隐式转换. 1.表DDL 2.传int的sql 3.传字符串的sql 仔细看下表结构,rid的字段类型: 而用户传入的是int,这里会有一个 ...

  10. SDUT 2498 AOE网上的关键路径

    AOE网上的关键路径 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 一个无环的有向图称为无 ...