diff --git a/README.md b/README.md
index 20fc53846085dad11a90c429715b5e7ee428aba6..4886488fdb1033ec79ca688456f0adb89449bc1d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-全能第三方支付对接Java开发工具包.优雅的轻量级支付模块集成支付对接支付整合(微信,支付宝,银联,友店,富友,跨境支付paypal,payoneer(P卡派安盈)易极付)app,扫码,网页支付刷卡付条码付刷脸付转账红包服务商模式、支持多种支付类型多支付账户,支付与业务完全剥离,简单几行代码即可实现支付,简单快速完成支付模块的开发,可轻松嵌入到任何系统里 目前仅是一个开发工具包(即SDK),只提供简单Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种支付相关的功能
+全能第三方支付对接Java开发工具包.优雅的轻量级支付模块集成支付对接支付整合(微信,支付宝,银联,友店,富友,跨境支付paypal,payoneer(P卡派安盈)易极付)app,扫码,网页支付刷卡付条码付刷脸付转账红包服务商模式,微信分账,合并支付、支持多种支付类型多支付账户,支付与业务完全剥离,简单几行代码即可实现支付,简单快速完成支付模块的开发,可轻松嵌入到任何系统里 目前仅是一个开发工具包(即SDK),只提供简单Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种支付相关的功能
### 特性
@@ -8,9 +8,10 @@
4. 简单快速完成支付模块的开发
5. 支持多种支付类型多支付账户扩展
-### 本项目包含 3 个部分:
+### 本项目包含 4 个部分:
1. pay-java-common 公共lib,支付核心与规范定义
+ 2. pay-java-web-support web支持包,目前已实现回调相关
2. pay-java-demo 具体的支付demo
3. pay-java-* 具体的支付实现库
@@ -21,7 +22,7 @@
com.egzosn
{module-name}
- 2.13.2
+ 2.14.7
```
@@ -41,6 +42,9 @@
###### 支付教程
* [基础模块支付宝微信讲解](https://gitee.com/egzosn/pay-java-parent/wikis/Home)
+ * [微信V3,查看demo/WxV3PayController](pay-java-demo?dir=1&filepath=pay-java-demo)
+ * [微信合并支付,查看demo/WxV3CombinePayController](pay-java-demo?dir=1&filepath=pay-java-demo)
+ * [微信分账,查看demo/WxV3ProfitSharingController](pay-java-demo?dir=1&filepath=pay-java-demo)
* [银联](pay-java-union?dir=1&filepath=pay-java-union)
* [payoneer](pay-java-payoneer?dir=1&filepath=pay-java-payoneer)
* [paypal](pay-java-paypal?dir=1&filepath=pay-java-paypal)
@@ -57,14 +61,24 @@ android 例子 [pay-java-android](https://gitee.com/egzosn/pay-java-android)
## 交流
很希望更多志同道合友友一起扩展新的的支付接口。
-这里感谢[ouyangxiangshao](https://github.com/ouyangxiangshao),[ZhuangXiong](https://github.com/ZhuangXiong) 与[Actinian](http://git.oschina.net/Actinia517) 所提交的安卓例子或者分支
+开发者
+[ouyangxiangshao](https://github.com/ouyangxiangshao)、[ZhuangXiong](https://github.com/ZhuangXiong) 、[Actinian](http://gitee.com/Actinia517) 、[Menjoe](https://gitee.com/menjoe-z)
也感谢各大友友同学帮忙进行接口测试
非常欢迎和感谢对本项目发起Pull Request的同学,不过本项目基于git flow开发流程,因此在发起Pull Request的时候请选择develop分支。
-E-Mail:egzosn@gmail.com
+作者公众号(未来输出)
+
-QQ群:542193977
+E-Mail:egan@egzosn.com
-微信群: 
+ **QQ群:**
+
+1. pay-java(1群): 542193977(已满)
+2. pay-java(2群):766275051
+
+
+微信群: 加我前拜托伸个小手关注公众号
+
+
diff --git a/pay-java-ali/README.md b/pay-java-ali/README.md
index e7a2f5eafb3126054fdd3b6a3f32669c4dddd2bc..d48313c4692b67efe3bcec6a4dac6accd36edfb7 100644
--- a/pay-java-ali/README.md
+++ b/pay-java-ali/README.md
@@ -3,13 +3,14 @@
## 支付宝支付简单例子
#### 支付配置
-
+##### 普通公钥
```java
-
-
+
+
AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
aliPayConfigStorage.setPid("合作者id");
- aliPayConfigStorage.setAppid("应用id");
+ aliPayConfigStorage.setAppId("应用id");
+// aliPayConfigStorage.setAppAuthToken("ISV代商户代用,指定appAuthToken");
aliPayConfigStorage.setKeyPublic("支付宝公钥");
aliPayConfigStorage.setKeyPrivate("应用私钥");
aliPayConfigStorage.setNotifyUrl("异步回调地址");
@@ -21,6 +22,31 @@
aliPayConfigStorage.setTest(true);
```
+##### 证书公钥
+```java
+
+
+ AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
+ aliPayConfigStorage.setPid("合作者id");
+ aliPayConfigStorage.setAppId("应用id");
+// aliPayConfigStorage.setAppAuthToken("ISV代商户代用,指定appAuthToken");
+ aliPayConfigStorage.setKeyPrivate("应用私钥");
+ //设置为证书方式
+ aliPayConfigStorage.setCertSign(true);
+ //设置证书存储方式,这里为路径
+ aliPayConfigStorage.setCertStoreType(CertStoreType.PATH);
+ aliPayConfigStorage.setMerchantCert("请填写您的应用公钥证书文件路径,例如:d:/appCertPublicKey_2019051064521003.crt");
+ aliPayConfigStorage.setAliPayCert("请填写您的支付宝公钥证书文件路径,例如:d:/alipayCertPublicKey_RSA2.crt");
+ aliPayConfigStorage.setAliPayRootCert("请填写您的支付宝根证书文件路径,例如:d:/alipayRootCert.crt");
+ aliPayConfigStorage.setNotifyUrl("异步回调地址");
+ aliPayConfigStorage.setReturnUrl("同步回调地址");
+ aliPayConfigStorage.setSignType("签名方式");
+ aliPayConfigStorage.setSeller("收款账号");
+ aliPayConfigStorage.setInputCharset("utf-8");
+ //是否为测试账号,沙箱环境
+ aliPayConfigStorage.setTest(true);
+
+```
#### 网络请求配置
@@ -85,7 +111,7 @@
```java
//支付订单基础信息
- PayOrder payOrder = new PayOrder("订单title", "摘要", new BigDecimal(0.01) , UUID.randomUUID().toString().replace("-", ""));
+ PayOrder payOrder = new PayOrder("订单title", "摘要", BigDecimal.valueOf(0.01) , UUID.randomUUID().toString().replace("-", ""));
```
@@ -236,14 +262,21 @@
RefundOrder order = new RefundOrder("支付宝单号", "我方系统单号", "退款金额", "订单总金额");
//非必填, 根据业务需求而定,可用于多次退款
order.setRefundNo("退款单号")
- Map result = service.refund(order);
+ AliRefundResult result = service.refund(order);
```
#### 查询退款
```java
- Map result = service.refundquery("支付宝单号", "我方系统单号");
+ RefundOrder order = new RefundOrder();
+ order.setOutTradeNo("我方系统商户单号");
+ order.setTradeNo("支付宝单号");
+ //退款金额
+ order.setRefundAmount(new BigDecimal(1));
+ order.setRefundNo("退款单号");
+ order.setDescription("");
+ Map result = service.refundquery();
```
@@ -256,15 +289,17 @@
#### 转账
```java
- TransferOrder order = new TransferOrder();
- order.setOutNo("商户转账订单号");
- order.setPayeeAccount("收款方账户,支付宝登录号,支持邮箱和手机号格式");
- order.setAmount(new BigDecimal(10));
- order.setPayerName("付款方姓名, 非必填");
- order.setPayeeName("收款方真实姓名, 非必填");
+ order.setOutBizNo("转账单号");
+ order.setTransAmount(new BigDecimal(10));
+ order.setOrderTitle("转账业务的标题");
+ order.setIdentity("参与方的唯一标识");
+ order.setIdentityType("参与方的标识类型,目前支持如下类型:");
+ order.setName("参与方真实姓名");
order.setRemark("转账备注, 非必填");
- //收款方账户类型 ,默认值 ALIPAY_LOGONID:支付宝登录号,支持邮箱和手机号格式。
- order.setTransferType(AliTransferType.ALIPAY_LOGONID);
+ //单笔无密转账到支付宝账户
+ order.setTransferType(AliTransferType.TRANS_ACCOUNT_NO_PWD);
+ //单笔无密转账到银行卡
+// order.setTransferType(AliTransferType.TRANS_BANKCARD_NO_PWD);
Map result = service.transfer(order);
```
diff --git a/pay-java-ali/pom.xml b/pay-java-ali/pom.xml
index e279f8e3d45e97d43bb99571f4fb364707ce83e7..9985ca214df92a4e127d092321758096caec8011 100644
--- a/pay-java-ali/pom.xml
+++ b/pay-java-ali/pom.xml
@@ -5,7 +5,7 @@
pay-java-parent
com.egzosn
- 2.13.3-SNAPSHOT
+ 2.14.8
4.0.0
pay-java-ali
@@ -19,7 +19,10 @@
pay-java-common
-
+
+ org.bouncycastle
+ bcprov-jdk15on
+
diff --git a/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayConfigStorage.java b/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayConfigStorage.java
index 3eef8c4b7ae2d1698ed462ce1b92766fe7c77871..2acb5a656b038eff3adaf3145b512835cd9a10ee 100644
--- a/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayConfigStorage.java
+++ b/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayConfigStorage.java
@@ -1,21 +1,34 @@
package com.egzosn.pay.ali.api;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.egzosn.pay.ali.bean.CertEnvironment;
import com.egzosn.pay.common.api.BasePayConfigStorage;
+import com.egzosn.pay.common.api.CertStore;
+import com.egzosn.pay.common.bean.result.PayException;
+import com.egzosn.pay.common.exception.PayErrorException;
/**
* 支付配置存储
*
* @author egan
- *
- * email egzosn@gmail.com
- * date 2016-5-18 14:09:01
+ *
+ * email egzosn@gmail.com
+ * date 2016-5-18 14:09:01
+ *
+ * 以下证书签名相关触发前提是 {@link BasePayConfigStorage#isCertSign}等于true的情况。不然走的就是普通的方式
*/
public class AliPayConfigStorage extends BasePayConfigStorage {
+ /**
+ * ISV代商户代用,指定appAuthToken
+ */
+ private String appAuthToken;
/**
* 商户应用id
*/
- private String appid;
+ private String appId;
/**
* 商户签约拿到的pid,partner_id的简称,合作伙伴身份等同于 partner
*/
@@ -27,15 +40,63 @@ public class AliPayConfigStorage extends BasePayConfigStorage {
private String seller;
- public void setAppid(String appid) {
- this.appid = appid;
+ /**
+ * 应用公钥证书
+ */
+ private Object merchantCert;
+
+ /**
+ * 支付宝公钥证书
+ */
+ private Object aliPayCert;
+ /**
+ * 支付宝CA证书,根证书
+ */
+ private Object aliPayRootCert;
+
+ /**
+ * 证书存储类型
+ */
+ private CertStore certStoreType;
+
+ /**
+ * 证书信息
+ */
+ private CertEnvironment certEnvironment;
+
+
+ public String getAppAuthToken() {
+ return appAuthToken;
+ }
+
+ public void setAppAuthToken(String appAuthToken) {
+ this.appAuthToken = appAuthToken;
+ }
+
+ public void setAppid(String appId) {
+ this.appId = appId;
}
@Override
+ @Deprecated
public String getAppid() {
- return appid;
+ return appId;
+ }
+
+ /**
+ * 应用id
+ * 纠正名称
+ *
+ * @return 应用id
+ */
+ @Override
+ public String getAppId() {
+ return appId;
}
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
@Override
public String getPid() {
@@ -55,5 +116,62 @@ public class AliPayConfigStorage extends BasePayConfigStorage {
this.seller = seller;
}
+ public Object getMerchantCert() {
+ return merchantCert;
+ }
+
+ public void setMerchantCert(Object merchantCert) {
+ this.merchantCert = merchantCert;
+ }
+
+ public Object getAliPayCert() {
+ return aliPayCert;
+ }
+
+ public void setAliPayCert(Object aliPayCert) {
+ this.aliPayCert = aliPayCert;
+ }
+
+ public Object getAliPayRootCert() {
+ return aliPayRootCert;
+ }
+
+ public void setAliPayRootCert(Object aliPayRootCert) {
+ this.aliPayRootCert = aliPayRootCert;
+ }
+
+ public CertStore getCertStoreType() {
+ return certStoreType;
+ }
+
+ public void setCertStoreType(CertStore certStoreType) {
+ this.certStoreType = certStoreType;
+ }
+
+ public CertEnvironment getCertEnvironment() {
+ return certEnvironment;
+ }
+
+ public void setCertEnvironment(CertEnvironment certEnvironment) {
+ this.certEnvironment = certEnvironment;
+ }
+
+ /**
+ * 初始化证书信息
+ */
+ public void loadCertEnvironment() {
+ if (!isCertSign() || null != this.certEnvironment) {
+ return;
+ }
+ try (InputStream merchantCertStream = certStoreType.getInputStream(merchantCert);
+ InputStream aliPayCertStream = certStoreType.getInputStream(aliPayCert);
+ InputStream aliPayRootCertStream = certStoreType.getInputStream(aliPayRootCert)) {
+ this.certEnvironment = new CertEnvironment(merchantCertStream, aliPayCertStream, aliPayRootCertStream);
+ }
+ catch (IOException e) {
+ throw new PayErrorException(new PayException("读取证书异常", e.getMessage()));
+ }
+ }
+
}
diff --git a/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java b/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java
index 9b7aa7d4e08e502a426d57489933a26fababec74..41ba432f4ded7478c5ccb0ae3e59a817253e77e8 100644
--- a/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java
+++ b/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java
@@ -1,73 +1,75 @@
package com.egzosn.pay.ali.api;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import static com.egzosn.pay.ali.bean.AliPayConst.ALIPAY_CERT_SN_FIELD;
+import static com.egzosn.pay.ali.bean.AliPayConst.APP_AUTH_TOKEN;
+import static com.egzosn.pay.ali.bean.AliPayConst.BIZ_CONTENT;
+import static com.egzosn.pay.ali.bean.AliPayConst.CODE;
+import static com.egzosn.pay.ali.bean.AliPayConst.DBACK_AMOUNT;
+import static com.egzosn.pay.ali.bean.AliPayConst.HTTPS_REQ_URL;
+import static com.egzosn.pay.ali.bean.AliPayConst.NOTIFY_URL;
+import static com.egzosn.pay.ali.bean.AliPayConst.PASSBACK_PARAMS;
+import static com.egzosn.pay.ali.bean.AliPayConst.PAYEE_INFO;
+import static com.egzosn.pay.ali.bean.AliPayConst.PRODUCT_CODE;
+import static com.egzosn.pay.ali.bean.AliPayConst.RETURN_URL;
+import static com.egzosn.pay.ali.bean.AliPayConst.SIGN;
+import static com.egzosn.pay.ali.bean.AliPayConst.SUCCESS_CODE;
+
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
+import com.egzosn.pay.ali.bean.AliPayBillType;
+import com.egzosn.pay.ali.bean.AliPayConst;
import com.egzosn.pay.ali.bean.AliPayMessage;
+import com.egzosn.pay.ali.bean.AliRefundResult;
import com.egzosn.pay.ali.bean.AliTransactionType;
import com.egzosn.pay.ali.bean.AliTransferType;
+import com.egzosn.pay.ali.bean.CertEnvironment;
import com.egzosn.pay.ali.bean.OrderSettle;
import com.egzosn.pay.common.api.BasePayService;
-import com.egzosn.pay.common.bean.*;
+import com.egzosn.pay.common.api.TransferService;
+import com.egzosn.pay.common.bean.AssistOrder;
+import com.egzosn.pay.common.bean.BillType;
+import com.egzosn.pay.common.bean.MethodType;
+import com.egzosn.pay.common.bean.NoticeParams;
+import com.egzosn.pay.common.bean.Order;
+import com.egzosn.pay.common.bean.OrderParaStructure;
+import com.egzosn.pay.common.bean.PayMessage;
+import com.egzosn.pay.common.bean.PayOrder;
+import com.egzosn.pay.common.bean.PayOutMessage;
+import com.egzosn.pay.common.bean.RefundOrder;
+import com.egzosn.pay.common.bean.TransactionType;
+import com.egzosn.pay.common.bean.TransferOrder;
+import com.egzosn.pay.common.bean.TransferType;
import com.egzosn.pay.common.bean.result.PayException;
import com.egzosn.pay.common.exception.PayErrorException;
import com.egzosn.pay.common.http.HttpConfigStorage;
import com.egzosn.pay.common.http.UriVariables;
import com.egzosn.pay.common.util.DateUtils;
import com.egzosn.pay.common.util.Util;
+import com.egzosn.pay.common.util.sign.SignTextUtils;
import com.egzosn.pay.common.util.sign.SignUtils;
import com.egzosn.pay.common.util.str.StringUtils;
-import java.util.*;
-
/**
* 支付宝支付服务
*
* @author egan
- *
- * email egzosn@gmail.com
- * date 2017-2-22 20:09
+ *
+ * email egzosn@gmail.com
+ * date 2017-2-22 20:09
*/
-public class AliPayService extends BasePayService {
-
- /**
- * 正式测试环境
- */
- private static final String HTTPS_REQ_URL = "https://openapi.alipay.com/gateway.do";
- /**
- * 沙箱测试环境账号
- */
- private static final String DEV_REQ_URL = "https://openapi.alipaydev.com/gateway.do";
-
- private static final String SIGN = "sign";
+public class AliPayService extends BasePayService implements TransferService, AliPayServiceInf {
- private static final String SUCCESS_CODE = "10000";
-
- private static final String CODE = "code";
- /**
- * 附加参数
- */
- private static final String PASSBACK_PARAMS = "passback_params";
- /**
- * 产品代码
- */
- private static final String PRODUCT_CODE = "product_code";
- /**
- * 返回地址
- */
- private static final String RETURN_URL = "return_url";
/**
- * 请求内容
- */
- private static final String BIZ_CONTENT = "biz_content";
- /**
- * 应用授权概述
+ * api服务地址,默认为国内
*/
- private static final String APP_AUTH_TOKEN = "app_auth_token";
- /**
- * 收款方信息
- */
- private static final String PAYEE_INFO = "payee_info";
+ private String apiServerUrl;
/**
* 获取对应的请求地址
@@ -76,8 +78,12 @@ public class AliPayService extends BasePayService {
*/
@Override
public String getReqUrl(TransactionType transactionType) {
- return payConfigStorage.isTest() ? DEV_REQ_URL : HTTPS_REQ_URL;
+ if (StringUtils.isNotEmpty(apiServerUrl)) {
+ return apiServerUrl;
+ }
+ return payConfigStorage.isTest() ? AliPayConst.DEV_REQ_URL : HTTPS_REQ_URL;
}
+
/**
* 获取对应的请求地址
*
@@ -88,12 +94,24 @@ public class AliPayService extends BasePayService {
}
+ /**
+ * 设置支付配置
+ *
+ * @param payConfigStorage 支付配置
+ */
+ @Override
+ public AliPayService setPayConfigStorage(AliPayConfigStorage payConfigStorage) {
+ payConfigStorage.loadCertEnvironment();
+ super.setPayConfigStorage(payConfigStorage);
+ return this;
+ }
+
public AliPayService(AliPayConfigStorage payConfigStorage, HttpConfigStorage configStorage) {
super(payConfigStorage, configStorage);
}
public AliPayService(AliPayConfigStorage payConfigStorage) {
- super(payConfigStorage);
+ this(payConfigStorage, null);
}
@@ -103,18 +121,30 @@ public class AliPayService extends BasePayService {
* @param params 回调回来的参数集
* @return 签名校验 true通过
*/
+ @Deprecated
@Override
public boolean verify(Map params) {
+ return verify(new NoticeParams(params));
+ }
+ /**
+ * 回调校验
+ *
+ * @param noticeParams 回调回来的参数集
+ * @return 签名校验 true通过
+ */
+ @Override
+ public boolean verify(NoticeParams noticeParams) {
+ final Map params = noticeParams.getBody();
if (params.get(SIGN) == null) {
- LOG.debug("支付宝支付异常:params:" + params);
+ LOG.debug("支付宝支付异常:params:{}", params);
return false;
}
- return signVerify(params, (String) params.get(SIGN)) && verifySource((String) params.get("notify_id"));
-
+ return signVerify(params, (String) params.get(SIGN));
}
+
/**
* 根据反馈回来的信息,生成签名结果
*
@@ -122,36 +152,45 @@ public class AliPayService extends BasePayService {
* @param sign 比对的签名结果
* @return 生成的签名结果
*/
- @Override
public boolean signVerify(Map params, String sign) {
if (params instanceof JSONObject) {
for (Map.Entry entry : params.entrySet()) {
- if (SIGN.equals(entry.getKey())) {
+ if (SIGN.equals(entry.getKey()) || ALIPAY_CERT_SN_FIELD.equals(entry.getKey())) {
continue;
}
- TreeMap response = new TreeMap((Map )entry.getValue());
+ TreeMap response = new TreeMap((Map) entry.getValue());
LinkedHashMap