mirror of
https://github.com/dromara/payment-spring-boot.git
synced 2026-03-13 21:33:41 +08:00
Compare commits
14 Commits
1.0.4.RELE
...
1.0.5.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc9496e1ad | ||
|
|
145f182641 | ||
|
|
5404c91402 | ||
|
|
57a7ba71fb | ||
|
|
e595855554 | ||
|
|
1f21f14c17 | ||
|
|
0d93361f6b | ||
|
|
49bf3d3d50 | ||
|
|
dc9933e1e8 | ||
|
|
0bab0b987d | ||
|
|
82b7293e32 | ||
|
|
ab63beb7d9 | ||
|
|
f96c03884d | ||
|
|
23eee4094e |
@@ -11,7 +11,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.felord</groupId>
|
||||
<artifactId>payment-spring-boot-starter</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -45,4 +45,4 @@
|
||||
## QQ交流群
|
||||
为了交流解惑,新建QQ群,可通过扫码进入。
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
- 实现微信支付V3 代金券
|
||||
- 实现微信支付V3 微信支付分
|
||||
- 实现微信支付V3 先享卡
|
||||
- 实现微信支付V3 商家券
|
||||
|
||||
## Maven 中央仓库坐标
|
||||
> 推荐使用最新版本
|
||||
@@ -33,7 +34,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.felord</groupId>
|
||||
<artifactId>payment-spring-boot-starter</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
```
|
||||
## 采用技术
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
## 1.0.3.RELEASE
|
||||
## 1.0.5.RELEASE
|
||||
- 微信支付
|
||||
- feat: 支持微信支付商家券
|
||||
- feat: 代金券功能增加发放消费卡接口`WechatMarketingBusiFavorApi`
|
||||
- refactor: 一些代码优化
|
||||
- refactor: 现在app支付、小程序支付返回所有客户端拉起支付的参数,不再需要用户再进行签名操作了
|
||||
- build: SDK开发环境 Spring Boot 版本升级到2.4.2
|
||||
- fix: 支付分RiskFund下枚举无法使用的问题(#2)
|
||||
- feat:增加V2 退款接口
|
||||
- feat:增加V2 企业付款到零钱接口
|
||||
- feat:增加V2 红包接口
|
||||
- refactor:优化了一些底层功能
|
||||
- refactor:整了支付配置Spring注入的顺序
|
||||
- refactor:JCE由SPI提供,不再使用JDK内置
|
||||
- fix: 关单接口调用异常[(#4)](https://github.com/NotFound403/payment-spring-boot/issues/4)
|
||||
|
||||
## 1.0.4.RELEASE
|
||||
- 微信支付
|
||||
- feat: 增加微信支付商家券相关接口`WechatMarketingBusiFavorApi`,商家券请阅读相关产品文档。
|
||||
- feat: 代金券功能增加发放消费卡接口。
|
||||
- refactor: 现在app支付、小程序支付返回所有客户端拉起支付的参数,不再需要用户再进行签名操作了。
|
||||
- refactor: 其它一些代码优化。
|
||||
- build: SDK开发环境 Spring Boot 版本升级到2.4.2。
|
||||
- fix: 支付分`RiskFund`下枚举无法使用的问题[(#2)](https://github.com/NotFound403/payment-spring-boot/issues/2)。
|
||||
|
||||
## 1.0.3.RELEASE
|
||||
- 微信支付
|
||||
- feat: 完善合单支付账单
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<dependency>
|
||||
<groupId>cn.felord</groupId>
|
||||
<artifactId>payment-spring-boot-starter</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
```
|
||||
> 基于 **Spring Boot 2.4.1**
|
||||
> 基于 **Spring Boot 2.x**
|
||||
|
||||
## Spring Boot 版本适配
|
||||
|
||||
@@ -50,7 +50,7 @@ wechat:
|
||||
<tentantID>:
|
||||
# 应用appId 必填
|
||||
app-id: xxxxxxxx
|
||||
# api 密钥 可不填
|
||||
# v2 api 密钥 1.0.5版本以后如果用到V2的接口时必填
|
||||
app-secret: xxxxxxxxxxx
|
||||
# api v3 密钥 必填
|
||||
app-v3-secret: xxxxxxxx
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
<parent>
|
||||
<groupId>cn.felord</groupId>
|
||||
<artifactId>payment-spring-boot</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>payment-spring-boot-autoconfigure</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
<packaging>jar</packaging>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -56,6 +56,16 @@
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -34,7 +34,7 @@ import java.util.Map;
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Conditional(WechatPayConfiguredCondition.class)
|
||||
@EnableConfigurationProperties(WechatPayProperties.class)
|
||||
public class WechatPayConfiguration {
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
@@ -37,6 +38,7 @@ import java.util.stream.Collectors;
|
||||
* @author felord.cn
|
||||
* @since 1.0.3.RELEASE
|
||||
*/
|
||||
@Order
|
||||
public class WechatPayConfiguredCondition extends SpringBootCondition {
|
||||
|
||||
/**
|
||||
@@ -57,7 +59,8 @@ public class WechatPayConfiguredCondition extends SpringBootCondition {
|
||||
}
|
||||
|
||||
private Map<String, WechatPayProperties.V3> getV3(Environment environment) {
|
||||
return Binder.get(environment).bind("wechat.pay.v3", STRING_WECHAT_V3_MAP)
|
||||
return Binder.get(environment)
|
||||
.bind("wechat.pay.v3", STRING_WECHAT_V3_MAP)
|
||||
.orElse(Collections.emptyMap());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2;
|
||||
|
||||
import cn.felord.payment.wechat.WechatPayProperties;
|
||||
import cn.felord.payment.wechat.v2.model.GroupRedpackModel;
|
||||
import cn.felord.payment.wechat.v2.model.RedpackInfoModel;
|
||||
import cn.felord.payment.wechat.v2.model.RedpackModel;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* 现金红包
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
public class WechatPayRedpackApi {
|
||||
private final WechatV2Client wechatV2Client;
|
||||
|
||||
/**
|
||||
* Instantiates a new Wechat pay redpack api.
|
||||
*
|
||||
* @param wechatV2Client the wechat v 2 client
|
||||
*/
|
||||
public WechatPayRedpackApi(WechatV2Client wechatV2Client) {
|
||||
this.wechatV2Client = wechatV2Client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发放随机红包
|
||||
*
|
||||
* @param redpackModel the redpack model
|
||||
* @return the json node
|
||||
*/
|
||||
public JsonNode sendRedpack(RedpackModel redpackModel) {
|
||||
|
||||
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
|
||||
redpackModel.setWxappid(v3.getAppId());
|
||||
redpackModel.setMchId(v3.getMchId());
|
||||
return wechatV2Client.wechatPayRequest(redpackModel,
|
||||
HttpMethod.POST,
|
||||
"https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack");
|
||||
}
|
||||
|
||||
/**
|
||||
* 发放裂变红包
|
||||
*
|
||||
* @param groupRedpackModel the group redpack model
|
||||
* @return the json node
|
||||
*/
|
||||
public JsonNode sendRedpack(GroupRedpackModel groupRedpackModel) {
|
||||
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
|
||||
groupRedpackModel.setWxappid(v3.getAppId());
|
||||
groupRedpackModel.setMchId(v3.getMchId());
|
||||
return wechatV2Client.wechatPayRequest(groupRedpackModel,
|
||||
HttpMethod.POST,
|
||||
"https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询红包信息
|
||||
*
|
||||
* @param redpackInfoModel the redpack info model
|
||||
* @return the json node
|
||||
*/
|
||||
public JsonNode redpackInfo(RedpackInfoModel redpackInfoModel) {
|
||||
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
|
||||
redpackInfoModel.setAppid(v3.getAppId());
|
||||
redpackInfoModel.setMchId(v3.getMchId());
|
||||
return wechatV2Client.wechatPayRequest(redpackInfoModel,
|
||||
HttpMethod.POST,
|
||||
"https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2;
|
||||
|
||||
import cn.felord.payment.wechat.WechatPayProperties;
|
||||
import cn.felord.payment.wechat.v2.model.RefundModel;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* 退款相关API.
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
public class WechatPayRefundApi {
|
||||
private final WechatV2Client wechatV2Client;
|
||||
|
||||
/**
|
||||
* Instantiates a new Wechat pay refund api.
|
||||
*
|
||||
* @param wechatV2Client the wechat v 2 client
|
||||
*/
|
||||
public WechatPayRefundApi(WechatV2Client wechatV2Client) {
|
||||
this.wechatV2Client = wechatV2Client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*
|
||||
* @param refundModel the refund model
|
||||
* @return json node
|
||||
*/
|
||||
public JsonNode transfer(RefundModel refundModel) {
|
||||
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
|
||||
refundModel.setAppid(v3.getAppId());
|
||||
refundModel.setMchId(v3.getMchId());
|
||||
return wechatV2Client.wechatPayRequest(refundModel,
|
||||
HttpMethod.POST,
|
||||
"https://api.mch.weixin.qq.com/secapi/pay/refund");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2;
|
||||
|
||||
import cn.felord.payment.wechat.WechatPayProperties;
|
||||
import cn.felord.payment.wechat.v2.model.TransferInfoModel;
|
||||
import cn.felord.payment.wechat.v2.model.TransferModel;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* 企业付款
|
||||
* <p>
|
||||
* TODO 暂时没有企业付款到银行卡
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
public class WechatPayTransfersApi {
|
||||
private final WechatV2Client wechatV2Client;
|
||||
|
||||
/**
|
||||
* Instantiates a new Wechat pay transfers api.
|
||||
*
|
||||
* @param wechatV2Client the wechat v 2 client
|
||||
*/
|
||||
public WechatPayTransfersApi(WechatV2Client wechatV2Client) {
|
||||
this.wechatV2Client = wechatV2Client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业付款到零钱
|
||||
*
|
||||
* @param transferModel the transfer model
|
||||
* @return json node
|
||||
*/
|
||||
public JsonNode transfer(TransferModel transferModel) {
|
||||
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
|
||||
transferModel.setMchAppid(v3.getAppId());
|
||||
transferModel.setMchid(v3.getMchId());
|
||||
return wechatV2Client.wechatPayRequest(transferModel,
|
||||
HttpMethod.POST,
|
||||
"https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询企业付款
|
||||
*
|
||||
* @param transferModel the transfer model
|
||||
* @return the json node
|
||||
*/
|
||||
public JsonNode transferInfo(TransferInfoModel transferModel) {
|
||||
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
|
||||
transferModel.setAppid(v3.getAppId());
|
||||
transferModel.setMchId(v3.getMchId());
|
||||
return wechatV2Client.wechatPayRequest(transferModel,
|
||||
HttpMethod.POST,
|
||||
"https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2;
|
||||
|
||||
import cn.felord.payment.wechat.WechatPayProperties;
|
||||
import cn.felord.payment.wechat.v2.model.BaseModel;
|
||||
import cn.felord.payment.wechat.v3.WechatMetaBean;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* 微信支付V2 客户端
|
||||
* <p>
|
||||
* V3接口不完善的临时性解决方案
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
public class WechatV2Client {
|
||||
private final WechatMetaBean wechatMetaBean;
|
||||
|
||||
public WechatV2Client(WechatMetaBean wechatMetaBean) {
|
||||
this.wechatMetaBean = wechatMetaBean;
|
||||
}
|
||||
|
||||
public <M extends BaseModel> JsonNode wechatPayRequest(M model, HttpMethod method, String url) {
|
||||
WechatPayProperties.V3 v3 = wechatMetaBean.getV3();
|
||||
return model
|
||||
.appSecret(v3.getAppSecret())
|
||||
.request(v3.getMchId(), method, url);
|
||||
}
|
||||
|
||||
public WechatMetaBean getWechatMetaBean() {
|
||||
return wechatMetaBean;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
|
||||
import cn.felord.payment.PayException;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.digests.MD5Digest;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.util.AlternativeJdkIdGenerator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.IdGenerator;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
/**
|
||||
* The type Base model.
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
@Getter
|
||||
public abstract class BaseModel {
|
||||
private static final XmlMapper XML_MAPPER = new XmlMapper();
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
static {
|
||||
// 忽略null
|
||||
XML_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
// 属性使用 驼峰首字母小写
|
||||
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
|
||||
OBJECT_MAPPER.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
|
||||
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
|
||||
}
|
||||
|
||||
|
||||
private static final IdGenerator ID_GENERATOR = new AlternativeJdkIdGenerator();
|
||||
private final String nonceStr = ID_GENERATOR.generateId()
|
||||
.toString()
|
||||
.replaceAll("-", "");
|
||||
private String sign;
|
||||
@JsonIgnore
|
||||
private String appSecret;
|
||||
|
||||
|
||||
public BaseModel appSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Xml string.
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
@SneakyThrows
|
||||
private String xml() {
|
||||
String link = link(this);
|
||||
this.sign = this.md5(link);
|
||||
return XML_MAPPER.writer()
|
||||
.withRootName("xml")
|
||||
.writeValueAsString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* md5摘要.
|
||||
*
|
||||
* @param src the src
|
||||
* @return the string
|
||||
*/
|
||||
private String md5(String src) {
|
||||
Digest digest = new MD5Digest();
|
||||
byte[] bytes = src.getBytes(StandardCharsets.UTF_8);
|
||||
digest.update(bytes, 0, bytes.length);
|
||||
byte[] md5Bytes = new byte[digest.getDigestSize()];
|
||||
digest.doFinal(md5Bytes, 0);
|
||||
return Hex.toHexString(md5Bytes).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照格式拼接参数以生成签名
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param t the t
|
||||
* @return the map
|
||||
*/
|
||||
@SneakyThrows
|
||||
private <T> String link(T t) {
|
||||
Assert.hasText(appSecret, "wechat pay appSecret is required");
|
||||
return OBJECT_MAPPER
|
||||
.writer()
|
||||
.writeValueAsString(t)
|
||||
.replaceAll("\":\"", "=")
|
||||
.replaceAll("\",\"", "&")
|
||||
.replaceAll("\\{\"", "")
|
||||
.replaceAll("\"}", "")
|
||||
.concat("&key=").concat(this.appSecret);
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public JsonNode request(String mchId, HttpMethod method, String url) {
|
||||
String xml = this.xml();
|
||||
RequestEntity<String> body = RequestEntity.method(method, UriComponentsBuilder.fromHttpUrl(url)
|
||||
.build()
|
||||
.toUri())
|
||||
.contentType(MediaType.valueOf("application/x-www-form-urlencoded;charset=UTF-8"))
|
||||
.body(xml);
|
||||
ResponseEntity<String> responseEntity = this.getRestTemplateClientAuthentication(mchId)
|
||||
.exchange(url, method, body, String.class);
|
||||
|
||||
if (!responseEntity.getStatusCode().is2xxSuccessful()) {
|
||||
throw new PayException("wechat pay v2 error ");
|
||||
}
|
||||
String result = responseEntity.getBody();
|
||||
|
||||
return XML_MAPPER.readTree(result);
|
||||
}
|
||||
|
||||
|
||||
private RestTemplate getRestTemplateClientAuthentication(String mchId)
|
||||
throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException,
|
||||
KeyStoreException, KeyManagementException {
|
||||
ClassPathResource resource = new ClassPathResource("wechat/apiclient_cert.p12");
|
||||
|
||||
char[] pem = mchId.toCharArray();
|
||||
|
||||
KeyStore store = KeyStore.getInstance("PKCS12");
|
||||
store.load(resource.getInputStream(), pem);
|
||||
|
||||
// Trust own CA and all self-signed certs
|
||||
SSLContext sslcontext = SSLContextBuilder.create()
|
||||
.loadKeyMaterial(store, pem)
|
||||
.build();
|
||||
// Allow TLSv1 protocol only
|
||||
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"},
|
||||
null, hostnameVerifier);
|
||||
|
||||
CloseableHttpClient httpclient = HttpClients.custom()
|
||||
.setSSLSocketFactory(sslsf)
|
||||
.build();
|
||||
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpclient);
|
||||
return new RestTemplate(clientHttpRequestFactory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class GroupRedpackModel extends BaseModel {
|
||||
|
||||
private String wxappid;
|
||||
private String mchId;
|
||||
private String mchBillno;
|
||||
private String sendName;
|
||||
private String reOpenid;
|
||||
private String totalAmount;
|
||||
private String totalNum;
|
||||
private String amtType = "ALL_RAND";
|
||||
private String wishing;
|
||||
private String clientIp;
|
||||
private String actName;
|
||||
private String remark;
|
||||
private String sceneId;
|
||||
private String riskInfo;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class RedpackInfoModel extends BaseModel {
|
||||
|
||||
private String appid;
|
||||
private String mchId;
|
||||
private String mchBillno;
|
||||
private String billType = "MCHT";
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class RedpackModel extends BaseModel {
|
||||
|
||||
private String wxappid;
|
||||
private String mchId;
|
||||
private String mchBillno;
|
||||
private String sendName;
|
||||
private String reOpenid;
|
||||
private String totalAmount;
|
||||
private String totalNum;
|
||||
private String wishing;
|
||||
private String clientIp;
|
||||
private String actName;
|
||||
private String remark;
|
||||
private String sceneId;
|
||||
private String riskInfo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author felord.cn
|
||||
* @since 1.0.4.RELEASE
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class RefundModel extends BaseModel {
|
||||
|
||||
private String appid;
|
||||
private String mchId;
|
||||
private String signType="MD5";
|
||||
private String transactionId;
|
||||
private String outTradeNo;
|
||||
private String outRefundNo;
|
||||
private Integer totalFee;
|
||||
private Integer refundFee;
|
||||
private String refundFeeType="CNY";
|
||||
private String refundDesc;
|
||||
private String refundAccount;
|
||||
private String notifyUrl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
/**
|
||||
* @author felord.cn
|
||||
* @since 1.0.4.RELEASE
|
||||
*/
|
||||
public class RefundQueryModel {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2019-2021 felord.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* Website:
|
||||
* https://felord.cn
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class TransferInfoModel extends BaseModel {
|
||||
private String appid;
|
||||
private String mchId;
|
||||
private String partnerTradeNo;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.felord.payment.wechat.v2.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class TransferModel extends BaseModel{
|
||||
private String mchAppid;
|
||||
private String mchid;
|
||||
private String deviceInfo;
|
||||
private String partnerTradeNo;
|
||||
private String openid;
|
||||
private String checkName;
|
||||
private String reUserName;
|
||||
private String amount;
|
||||
private String desc;
|
||||
private String spbillCreateIp;
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.AlternativeJdkIdGenerator;
|
||||
import org.springframework.util.Base64Utils;
|
||||
@@ -85,6 +86,12 @@ public class SignatureProvider {
|
||||
* 微信平台证书容器 key = 序列号 value = 证书对象
|
||||
*/
|
||||
private static final Map<String, Certificate> CERTIFICATE_MAP = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 加密算法提供方 - BouncyCastle
|
||||
*/
|
||||
private static final String BC_PROVIDER = "BC";
|
||||
|
||||
|
||||
/**
|
||||
* The Rest operations.
|
||||
*/
|
||||
@@ -100,6 +107,8 @@ public class SignatureProvider {
|
||||
* @param wechatMetaContainer the wechat meta container
|
||||
*/
|
||||
public SignatureProvider(WechatMetaContainer wechatMetaContainer) {
|
||||
Provider bouncyCastleProvider = new BouncyCastleProvider();
|
||||
Security.addProvider(bouncyCastleProvider);
|
||||
this.wechatMetaContainer = wechatMetaContainer;
|
||||
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
|
||||
}
|
||||
@@ -144,7 +153,7 @@ public class SignatureProvider {
|
||||
*/
|
||||
@SneakyThrows
|
||||
public String doRequestSign(PrivateKey privateKey, String... orderedComponents) {
|
||||
Signature signer = Signature.getInstance("SHA256withRSA");
|
||||
Signature signer = Signature.getInstance("SHA256withRSA",BC_PROVIDER);
|
||||
signer.initSign(privateKey);
|
||||
final String signatureStr = createSign(orderedComponents);
|
||||
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
||||
@@ -243,7 +252,7 @@ public class SignatureProvider {
|
||||
*/
|
||||
public String decryptResponseBody(String tenantId, String associatedData, String nonce, String ciphertext) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", BC_PROVIDER);
|
||||
String apiV3Key = wechatMetaContainer.getWechatMeta(tenantId).getV3().getAppV3Secret();
|
||||
SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));
|
||||
@@ -258,8 +267,7 @@ public class SignatureProvider {
|
||||
throw new PayException(e);
|
||||
}
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException |
|
||||
InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
|
||||
throw new PayException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
*/
|
||||
package cn.felord.payment.wechat.v3;
|
||||
|
||||
import cn.felord.payment.wechat.v2.WechatPayRedpackApi;
|
||||
import cn.felord.payment.wechat.v2.WechatPayTransfersApi;
|
||||
import cn.felord.payment.wechat.v2.WechatV2Client;
|
||||
|
||||
/**
|
||||
* 微信支付工具.
|
||||
*
|
||||
@@ -118,4 +122,34 @@ public class WechatApiProvider {
|
||||
return new WechatPayCallback(wechatPayClient.signatureProvider(), tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 现金红包,基于V2
|
||||
*
|
||||
* @param tenantId the tenant id
|
||||
* @return wechat pay redpack api
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
public WechatPayRedpackApi redpackApi(String tenantId) {
|
||||
WechatMetaBean wechatMeta = wechatPayClient.signatureProvider()
|
||||
.wechatMetaContainer()
|
||||
.getWechatMeta(tenantId);
|
||||
WechatV2Client wechatV2Client = new WechatV2Client(wechatMeta);
|
||||
return new WechatPayRedpackApi(wechatV2Client);
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业付款到零钱,目前不包括到银行卡,基于V2
|
||||
*
|
||||
* @param tenantId the tenant id
|
||||
* @return wechat pay redpack api
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
public WechatPayTransfersApi transfersApi(String tenantId) {
|
||||
WechatMetaBean wechatMeta = wechatPayClient.signatureProvider()
|
||||
.wechatMetaContainer()
|
||||
.getWechatMeta(tenantId);
|
||||
WechatV2Client wechatV2Client = new WechatV2Client(wechatMeta);
|
||||
return new WechatPayTransfersApi(wechatV2Client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ import java.net.URI;
|
||||
import java.security.PrivateKey;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -253,11 +255,10 @@ public class WechatDirectPayApi extends AbstractApi {
|
||||
private RequestEntity<?> closeByOutTradeNoFunction(WechatPayV3Type type, String outTradeNo) {
|
||||
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
|
||||
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("mchid", v3.getMchId());
|
||||
Map<String, String> queryParams = new HashMap<>(1);
|
||||
queryParams.put("mchid", v3.getMchId());
|
||||
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
|
||||
.queryParams(queryParams)
|
||||
.build()
|
||||
.expand(outTradeNo)
|
||||
.toUri();
|
||||
|
||||
@@ -262,7 +262,7 @@ public class WechatPayClient {
|
||||
responseConsumer.accept(responseEntity);
|
||||
}
|
||||
} else {
|
||||
throw new PayException("wechat pay signature failed, Request-ID " + requestId);
|
||||
throw new PayException("wechat pay signature verify failed, Request-ID " + requestId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@ import lombok.Data;
|
||||
@Data
|
||||
public class Amount {
|
||||
/**
|
||||
* The Total.
|
||||
* 金额,单位【分】。
|
||||
*/
|
||||
private int total;
|
||||
/**
|
||||
* The Currency.
|
||||
* 货币单位,固定为 CNY 。
|
||||
*/
|
||||
private String currency = "CNY";
|
||||
}
|
||||
|
||||
@@ -29,54 +29,58 @@ import lombok.Data;
|
||||
@Data
|
||||
public class CallbackParams {
|
||||
/**
|
||||
* The Id.
|
||||
* 通知Id
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* The Create time.
|
||||
* 通知创建时间
|
||||
*/
|
||||
private String createTime;
|
||||
/**
|
||||
* The Event type.
|
||||
* 通知类型
|
||||
* @see cn.felord.payment.wechat.v3.WechatPayCallback
|
||||
*/
|
||||
private String eventType;
|
||||
/**
|
||||
* The Resource type.
|
||||
* 通知数据类型
|
||||
*/
|
||||
private String resourceType;
|
||||
/**
|
||||
* The Summary.
|
||||
* 回调摘要
|
||||
*/
|
||||
private String summary;
|
||||
/**
|
||||
* The Resource.
|
||||
* 通知数据
|
||||
*/
|
||||
private Resource resource;
|
||||
|
||||
|
||||
/**
|
||||
* The type Resource.
|
||||
* 通知数据
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
*/
|
||||
@Data
|
||||
public static class Resource {
|
||||
/**
|
||||
* The Algorithm.
|
||||
* 对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM。
|
||||
*/
|
||||
private String algorithm;
|
||||
/**
|
||||
* The Ciphertext.
|
||||
* Base64编码后的开启/停用结果数据密文。
|
||||
*/
|
||||
private String ciphertext;
|
||||
/**
|
||||
* The Associated data.
|
||||
* 附加数据。
|
||||
*/
|
||||
private String associatedData;
|
||||
/**
|
||||
* The Nonce.
|
||||
* 加密使用的随机串。
|
||||
*/
|
||||
private String nonce;
|
||||
/**
|
||||
* The Original type.
|
||||
* 原始回调类型。
|
||||
*/
|
||||
private String originalType;
|
||||
}
|
||||
|
||||
@@ -32,22 +32,22 @@ import java.util.List;
|
||||
public class ConsumeInformation {
|
||||
|
||||
/**
|
||||
* The Consume mchid.
|
||||
* 核销商户号
|
||||
*/
|
||||
private String consumeMchid;
|
||||
|
||||
/**
|
||||
* The Consume time.
|
||||
* 核销时间 YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE
|
||||
*/
|
||||
private String consumeTime;
|
||||
|
||||
/**
|
||||
* The Goods detail.
|
||||
* 商户下单接口传的单品信息
|
||||
*/
|
||||
private List<GoodsDetail> goodsDetail;
|
||||
|
||||
/**
|
||||
* The Transaction id.
|
||||
* 核销订单号
|
||||
*/
|
||||
private String transactionId;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package cn.felord.payment.wechat.v3.model;
|
||||
|
||||
import cn.felord.payment.wechat.enumeration.CouponStatus;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -30,67 +31,68 @@ import lombok.Data;
|
||||
public class CouponConsumeData {
|
||||
|
||||
/**
|
||||
* The Available begin time.
|
||||
* 可用开始时间 YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE
|
||||
*/
|
||||
private String availableBeginTime;
|
||||
/**
|
||||
* The Available end time.
|
||||
* 可用结束时间 YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE
|
||||
*/
|
||||
private String availableEndTime;
|
||||
/**
|
||||
* The Consume information.
|
||||
* 实扣代金券信息
|
||||
*/
|
||||
private ConsumeInformation consumeInformation;
|
||||
/**
|
||||
* The Coupon id.
|
||||
* 代金券id
|
||||
*/
|
||||
private String couponId;
|
||||
/**
|
||||
* The Coupon name.
|
||||
* 代金券名称
|
||||
*/
|
||||
private String couponName;
|
||||
/**
|
||||
* The Coupon type.
|
||||
* 代金券类型
|
||||
*/
|
||||
private CouponType couponType;
|
||||
/**
|
||||
* The Create time.
|
||||
* 领券时间
|
||||
*/
|
||||
private String createTime;
|
||||
/**
|
||||
* The Description.
|
||||
* 代金券描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* The Discount to.
|
||||
* 减至优惠特定信息
|
||||
*/
|
||||
private DiscountTo discountTo;
|
||||
/**
|
||||
* The No cash.
|
||||
* 是否无资金流
|
||||
*/
|
||||
private Boolean noCash;
|
||||
/**
|
||||
* The Normal coupon information.
|
||||
* 普通满减券信息
|
||||
*/
|
||||
private NormalCouponInformation normalCouponInformation;
|
||||
/**
|
||||
* The Singleitem.
|
||||
* 是否单品优惠
|
||||
*/
|
||||
private Boolean singleitem;
|
||||
/**
|
||||
* The Singleitem discount off.
|
||||
* 单品优惠特定信息
|
||||
*/
|
||||
private SingleitemDiscountOff singleitemDiscountOff;
|
||||
/**
|
||||
* The Status.
|
||||
* 代金券状态
|
||||
* @see CouponStatus
|
||||
*/
|
||||
private String status;
|
||||
private CouponStatus status;
|
||||
/**
|
||||
* The Stock creator mchid.
|
||||
* 创建批次的商户号
|
||||
*/
|
||||
private String stockCreatorMchid;
|
||||
/**
|
||||
* The Stock id.
|
||||
* 批次号
|
||||
*/
|
||||
private String stockId;
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ public class Goods {
|
||||
/**
|
||||
* 商品数量
|
||||
*/
|
||||
private int quantity;
|
||||
private Integer quantity;
|
||||
/**
|
||||
* 商品单价
|
||||
*/
|
||||
private int unitPrice;
|
||||
private Integer unitPrice;
|
||||
}
|
||||
|
||||
@@ -30,19 +30,19 @@ import lombok.Data;
|
||||
public class GoodsDetail {
|
||||
|
||||
/**
|
||||
* The Discount amount.
|
||||
* 优惠金额,单位【分】
|
||||
*/
|
||||
private Long discountAmount;
|
||||
/**
|
||||
* The Goods id.
|
||||
* 单品券创建时录入的单品编码。
|
||||
*/
|
||||
private String goodsId;
|
||||
/**
|
||||
* The Price.
|
||||
* 单品单价
|
||||
*/
|
||||
private Long price;
|
||||
/**
|
||||
* The Quantity.
|
||||
* 单品数量
|
||||
*/
|
||||
private Long quantity;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public class H5Info {
|
||||
/**
|
||||
* 场景类型
|
||||
*/
|
||||
private String type;
|
||||
private H5SceneType type;
|
||||
/**
|
||||
* 应用名称
|
||||
*/
|
||||
@@ -48,4 +48,26 @@ public class H5Info {
|
||||
* Android 平台 PackageName
|
||||
*/
|
||||
private String packageName;
|
||||
|
||||
/**
|
||||
* H5 场景类型
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.5.RELEASE
|
||||
*/
|
||||
public enum H5SceneType {
|
||||
|
||||
/**
|
||||
* IOS
|
||||
*/
|
||||
iOS,
|
||||
/**
|
||||
* Android
|
||||
*/
|
||||
Android,
|
||||
/**
|
||||
* Wap
|
||||
*/
|
||||
Wap
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ import lombok.Data;
|
||||
public class NormalCouponInformation {
|
||||
|
||||
/**
|
||||
* The Coupon amount.
|
||||
* 面额,单位:分。
|
||||
*/
|
||||
private Long couponAmount;
|
||||
/**
|
||||
* The Transaction minimum.
|
||||
* 使用券金额门槛,单位:分。
|
||||
*/
|
||||
private Long transactionMinimum;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The type Promotion detail.
|
||||
* 优惠功能
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
@@ -33,52 +33,60 @@ import java.util.List;
|
||||
public class PromotionDetail {
|
||||
|
||||
/**
|
||||
* The Amount.
|
||||
* 优惠券面额,单位【分】
|
||||
*/
|
||||
private Long amount;
|
||||
/**
|
||||
* The Coupon id.
|
||||
* 券ID
|
||||
*/
|
||||
private String couponId;
|
||||
/**
|
||||
* The Currency.
|
||||
* 优惠币种,内商户号仅支持人民币 CNY
|
||||
*/
|
||||
private String currency;
|
||||
/**
|
||||
* The Goods detail.
|
||||
* 单品列表信息
|
||||
*/
|
||||
private List<GoodsDetail> goodsDetail;
|
||||
/**
|
||||
* The Merchant contribute.
|
||||
* 商户出资,单位为分
|
||||
*/
|
||||
private Long merchantContribute;
|
||||
/**
|
||||
* The Name.
|
||||
* 优惠名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* The Other contribute.
|
||||
* 其他出资,单位为分
|
||||
*/
|
||||
private Long otherContribute;
|
||||
/**
|
||||
* The Scope.
|
||||
* 优惠范围
|
||||
* <ul>
|
||||
* <li>GLOBAL:全场代金券</li>
|
||||
* <li>SINGLE:单品优惠</li>
|
||||
* </ul>
|
||||
*/
|
||||
private String scope;
|
||||
/**
|
||||
* The Stock id.
|
||||
* 活动ID
|
||||
*/
|
||||
private String stockId;
|
||||
/**
|
||||
* The Type.
|
||||
* 优惠类型
|
||||
* <ul>
|
||||
* <li>CASH:充值</li>
|
||||
* <li>NOCASH:预充值</li>
|
||||
* </ul>
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* The Wechatpay contribute.
|
||||
* 微信出资,单位为分
|
||||
*/
|
||||
private Long wechatpayContribute;
|
||||
|
||||
/**
|
||||
* The type Goods detail.
|
||||
* 单品列表信息
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
@@ -87,23 +95,23 @@ public class PromotionDetail {
|
||||
public static class GoodsDetail {
|
||||
|
||||
/**
|
||||
* The Goods id.
|
||||
* 商品编码
|
||||
*/
|
||||
private String goodsId;
|
||||
/**
|
||||
* The Quantity.
|
||||
* 商品数量
|
||||
*/
|
||||
private Long quantity;
|
||||
/**
|
||||
* The Unit price.
|
||||
* 商品单价
|
||||
*/
|
||||
private Long unitPrice;
|
||||
/**
|
||||
* The Discount amount.
|
||||
* 商品优惠金额,单位【分】
|
||||
*/
|
||||
private Long discountAmount;
|
||||
/**
|
||||
* The Goods remark.
|
||||
* 商品备注
|
||||
*/
|
||||
private String goodsRemark;
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ import lombok.Data;
|
||||
@Data
|
||||
public class SingleitemDiscountOff {
|
||||
|
||||
/**
|
||||
* 单品最高优惠价格,单位:分。
|
||||
*/
|
||||
private Long singlePriceMax;
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付成功通知解密
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
*/
|
||||
@@ -32,67 +34,71 @@ import java.util.List;
|
||||
public class TransactionConsumeData {
|
||||
|
||||
/**
|
||||
* The Amount.
|
||||
* 订单金额
|
||||
*/
|
||||
private Amount amount;
|
||||
/**
|
||||
* The Appid.
|
||||
* 应用ID
|
||||
*/
|
||||
private String appid;
|
||||
/**
|
||||
* The Attach.
|
||||
* 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
|
||||
*/
|
||||
private String attach;
|
||||
/**
|
||||
* The Bank type.
|
||||
* 银行类型,采用字符串类型的银行标识。银行标识请参考 <a target= "_blank" href= "https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6">《银行类型对照表》</a>
|
||||
*/
|
||||
private String bankType;
|
||||
/**
|
||||
* The Mchid.
|
||||
* 商户号
|
||||
*/
|
||||
private String mchid;
|
||||
/**
|
||||
* The Out trade no.
|
||||
* 商户订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
/**
|
||||
* The Payer.
|
||||
* 支付者信息
|
||||
*/
|
||||
private Payer payer;
|
||||
/**
|
||||
* The Promotion detail.
|
||||
* 优惠功能,享受优惠时返回该字段。
|
||||
*/
|
||||
private List<PromotionDetail> promotionDetail;
|
||||
/**
|
||||
* The Scene info.
|
||||
* 支付场景信息描述
|
||||
*/
|
||||
private SceneInfo sceneInfo;
|
||||
/**
|
||||
* The Success time.
|
||||
* 支付完成时间 YYYY-MM-DDTHH:mm:ss+TIMEZONE
|
||||
*/
|
||||
private String successTime;
|
||||
/**
|
||||
* 在 1.0.0.RELEASE 直接返回了枚举字符串,1.0.2.RELEASE 中变更为枚举
|
||||
*
|
||||
* @since 1.0.0.RELEASE
|
||||
*/
|
||||
private TradeState tradeState;
|
||||
/**
|
||||
* The Trade state desc.
|
||||
* 交易状态描述
|
||||
*/
|
||||
private String tradeStateDesc;
|
||||
/**
|
||||
* 交易类型
|
||||
* <p>
|
||||
* 在 1.0.0.RELEASE 直接返回了枚举字符串,1.0.2.RELEASE 中变更为枚举
|
||||
*
|
||||
* @since 1.0.0.RELEASE
|
||||
*/
|
||||
private TradeType tradeType;
|
||||
/**
|
||||
* The Transaction id.
|
||||
* 微信支付订单号
|
||||
*/
|
||||
private String transactionId;
|
||||
|
||||
|
||||
/**
|
||||
* The type Payer.
|
||||
* 支付者信息
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
@@ -100,13 +106,13 @@ public class TransactionConsumeData {
|
||||
@Data
|
||||
public static class Payer {
|
||||
/**
|
||||
* The Openid.
|
||||
* 用户在直连商户appid下的唯一标识。
|
||||
*/
|
||||
private String openid;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type Scene info.
|
||||
* 支付场景信息描述
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
@@ -114,13 +120,13 @@ public class TransactionConsumeData {
|
||||
@Data
|
||||
public static class SceneInfo {
|
||||
/**
|
||||
* The Device id.
|
||||
* 商户端设备号(门店号或收银设备ID)。
|
||||
*/
|
||||
private String deviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type Amount.
|
||||
* 订单金额
|
||||
*
|
||||
* @author felord.cn
|
||||
* @since 1.0.0.RELEASE
|
||||
@@ -128,19 +134,19 @@ public class TransactionConsumeData {
|
||||
@Data
|
||||
public static class Amount {
|
||||
/**
|
||||
* The Total.
|
||||
* 订单总金额,单位为分。
|
||||
*/
|
||||
private Integer total;
|
||||
/**
|
||||
* The Payer total.
|
||||
* 用户支付金额,单位为分。
|
||||
*/
|
||||
private Integer payerTotal;
|
||||
/**
|
||||
* The Currency.
|
||||
* CNY:人民币,境内商户号仅支持人民币。
|
||||
*/
|
||||
private String currency;
|
||||
/**
|
||||
* The Payer currency.
|
||||
* 用户支付币种
|
||||
*/
|
||||
private String payerCurrency;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
<parent>
|
||||
<groupId>cn.felord</groupId>
|
||||
<artifactId>payment-spring-boot</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>payment-spring-boot-starter</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
<packaging>jar</packaging>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -35,6 +35,14 @@
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15to18</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
116
pom.xml
116
pom.xml
@@ -4,7 +4,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<groupId>cn.felord</groupId>
|
||||
<artifactId>payment-spring-boot</artifactId>
|
||||
<version>1.0.4.RELEASE</version>
|
||||
<version>1.0.5.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<tag>payment-spring-boot-1.0.4.RELEASE</tag>
|
||||
<tag>payment-spring-boot-1.0.5.RELEASE</tag>
|
||||
<url>https://github.com/NotFound403/payment-spring-boot</url>
|
||||
<connection>scm:git:https://github.com/NotFound403/payment-spring-boot.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/NotFound403/payment-spring-boot.git</developerConnection>
|
||||
@@ -54,6 +54,8 @@
|
||||
<lombok.verison>1.18.12</lombok.verison>
|
||||
<jackson.version>2.9.10</jackson.version>
|
||||
<bcprov.version>1.66</bcprov.version>
|
||||
<jackson.version>2.11.4</jackson.version>
|
||||
<httpclient.version>4.5.13</httpclient.version>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -116,66 +118,96 @@
|
||||
<artifactId>payment-spring-boot-autoconfigure</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<show>private</show>
|
||||
<nohelp>true</nohelp>
|
||||
<charset>UTF-8</charset>
|
||||
<encoding>UTF-8</encoding>
|
||||
<docencoding>UTF-8</docencoding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.8</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>sonatype-nexus-staging</serverId>
|
||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<show>private</show>
|
||||
<nohelp>true</nohelp>
|
||||
<charset>UTF-8</charset>
|
||||
<encoding>UTF-8</encoding>
|
||||
<docencoding>UTF-8</docencoding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.8</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>sonatype-nexus-staging</serverId>
|
||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
Reference in New Issue
Block a user