微信小程序支付接口和Adapay回调接口
This commit is contained in:
parent
38f6596812
commit
3c07c9f5c6
|
|
@ -116,6 +116,35 @@
|
|||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- @ConfigurationProperties annotation processing (metadata for IDEs) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- 汇聚支付 Adapay SDK -->
|
||||
<dependency>
|
||||
<groupId>com.huifu.adapay.core</groupId>
|
||||
<artifactId>adapay-core-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.huifu.adapay</groupId>
|
||||
<artifactId>adapay-java-sdk</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Adapay SDK 需要依赖 httpmime -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Adapay SDK 需要依赖 httpclient -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.ghy.common.adapay;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Adapay 自动装载
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(AdapayProperties.class)
|
||||
public class AdapayAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public AdapayService adapayService(AdapayProperties adapayProperties) {
|
||||
AdapayService adapayService = new AdapayService();
|
||||
adapayService.setAdapayProperties(adapayProperties);
|
||||
return adapayService;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.ghy.common.adapay;
|
||||
|
||||
import com.huifu.adapay.Adapay;
|
||||
import com.huifu.adapay.model.MerConfig;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Adapay 配置类
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
@Data
|
||||
@Slf4j
|
||||
@ConfigurationProperties("adapay")
|
||||
public class AdapayProperties implements InitializingBean {
|
||||
|
||||
/**
|
||||
* 是否打印调用日志,默认不打印
|
||||
*/
|
||||
private boolean debug = false;
|
||||
|
||||
/**
|
||||
* 是否是prod_mode 默认为 true
|
||||
*/
|
||||
private boolean prodMode = true;
|
||||
|
||||
private String appId;
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 初始化商户配置,服务器启动前,必须通过该方式初始化商户配置完成
|
||||
* apiKey为prod模式的API KEY
|
||||
* mockApiKey为mock模式的API KEY
|
||||
* rsaPrivateKey为商户发起请求时,用于请求参数加签所需要的RSA私钥
|
||||
*/
|
||||
private String apiKey;
|
||||
private String mockApiKey;
|
||||
private String rsaPrivateKey;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
log.info("Adapay.debug={}, Adapay.prodMode={}", debug, prodMode);
|
||||
Assert.hasText(appId, "Adapay.appId is blank!");
|
||||
Assert.hasText(apiKey, "Adapay.apiKey is blank!");
|
||||
Assert.hasText(mockApiKey, "Adapay.mockApiKey is blank!");
|
||||
Assert.hasText(rsaPrivateKey, "Adapay.rsaPrivateKey is blank!");
|
||||
|
||||
MerConfig merConfig = new MerConfig();
|
||||
merConfig.setApiKey(apiKey);
|
||||
merConfig.setApiMockKey(mockApiKey);
|
||||
merConfig.setRSAPrivateKey(rsaPrivateKey);
|
||||
Adapay.initWithMerConfig(merConfig);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.ghy.common.adapay;
|
||||
|
||||
import com.ghy.common.adapay.callback.PayCallback;
|
||||
import com.huifu.adapay.core.exception.BaseAdaPayException;
|
||||
import com.huifu.adapay.model.Payment;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
@Slf4j
|
||||
@Setter
|
||||
public class AdapayService {
|
||||
|
||||
AdapayProperties adapayProperties;
|
||||
|
||||
/**
|
||||
* @param callback 处理支付结果的回调接口
|
||||
* @param orderNo 订单号
|
||||
* @param payAmt 支付金额
|
||||
* @param goodsTittle 商品名称
|
||||
* @param goodsDesc 商品描述
|
||||
* @param description 订单附加说明
|
||||
*/
|
||||
public Map<String, Object> wxLitePay(PayCallback callback, String orderNo, String payAmt, String goodsTittle, String goodsDesc, String description) throws BaseAdaPayException {
|
||||
Map<String, Object> paymentParams = new HashMap<>(10);
|
||||
paymentParams.put("app_id", adapayProperties.getAppId());
|
||||
paymentParams.put("notify_url", adapayProperties.getNotifyUrl());
|
||||
paymentParams.put("order_no", orderNo);
|
||||
paymentParams.put("pay_channel", PayChannelEnum.WX_LITE.getCode());
|
||||
paymentParams.put("pay_amt", payAmt);
|
||||
paymentParams.put("goods_title", goodsTittle);
|
||||
paymentParams.put("goods_desc", goodsDesc);
|
||||
paymentParams.put("description", description);
|
||||
PayResultMapping.putCallback(orderNo, callback);
|
||||
return Payment.create(paymentParams);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.ghy.common.adapay;
|
||||
|
||||
/**
|
||||
* Event时间枚举
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
public enum EventEnum {
|
||||
|
||||
PAY_SUCCEEDED("payment.succeeded", "支付成功"),
|
||||
PAY_FAILED("payment.failed", "支付失败"),
|
||||
|
||||
PAY_CLOSE_SUCCEEDED("payment.close.succeeded", "关闭支付订单成功"),
|
||||
PAY_CLOSE_FAILED("payment.close.failed", "关闭支付订单失败"),
|
||||
|
||||
REFUND_SUCCEEDED("refund.succeeded", "退款成功"),
|
||||
REFUND_FAILED("refund.failed", "退款失败"),
|
||||
|
||||
CORP_MEMBER_SUCCEEDED("corp_member.succeeded", "开户成功"),
|
||||
CORP_MEMBER_FAILED("corp_member.failed", "开户失败"),
|
||||
|
||||
PAYMENT_REVERSE_SUCCEEDED("payment_reverse.succeeded", "支付撤销成功"),
|
||||
PAYMENT_REVERSE_FAILED("payment_reverse.failed", "支付撤销失败"),
|
||||
|
||||
CASH_SUCCEEDED("cash.succeeded", "取现成功"),
|
||||
CASH_FAILED("cash.failed", "取现失败"),
|
||||
|
||||
ACCOUNT_PAYMENT_SUCCEEDED("account_payment.succeeded", "钱包支付成功"),
|
||||
ACCOUNT_PAYMENT_FAILED("account_payment.failed", "钱包支付失败"),
|
||||
|
||||
FASTPAY_SUCCEEDED("fastpay.succeeded", "快捷支付成功"),
|
||||
FASTPAY_FAILED("fastpay.failed", "快捷支付失败");
|
||||
|
||||
private final String type;
|
||||
private final String description;
|
||||
|
||||
EventEnum(String type, String description) {
|
||||
this.type = type;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.ghy.common.adapay;
|
||||
|
||||
/**
|
||||
* 支付渠道
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
public enum PayChannelEnum {
|
||||
|
||||
ALIPAY_QR("alipay_qr", "支付宝正扫"),
|
||||
WX_LITE("wx_lite", "wx_lite");
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
PayChannelEnum(String code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.ghy.common.adapay;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ghy.common.adapay.callback.Event;
|
||||
import com.ghy.common.adapay.callback.PayCallback;
|
||||
import com.huifu.adapay.model.Payment;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 支付结果匹配池
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
public class PayResultMapping {
|
||||
|
||||
/**
|
||||
* 临时保存支付结果
|
||||
* key: orderNo
|
||||
* value: 处理支付结果的回调接口
|
||||
*/
|
||||
private final static ConcurrentHashMap<String, PayCallback> PAY_RESULT_CALLBACK_MAP = new ConcurrentHashMap<>(1024);
|
||||
|
||||
public static void putResult(Event event) {
|
||||
String data = event.getData();
|
||||
Payment payment = JSON.parseObject(data, Payment.class);
|
||||
Assert.hasText(payment.getOrderNo(), "orderNo is blank !!!");
|
||||
PayCallback callback = PAY_RESULT_CALLBACK_MAP.remove(payment.getOrderNo());
|
||||
if (callback != null) {
|
||||
callback.onResponse(payment);
|
||||
}
|
||||
}
|
||||
|
||||
public static void putCallback(String orderNo, PayCallback callback) {
|
||||
Assert.hasText(orderNo, "orderNo is blank !!!");
|
||||
Assert.notNull(callback, "PayCallback is null !!!");
|
||||
PAY_RESULT_CALLBACK_MAP.put(orderNo, callback);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.ghy.common.adapay.callback;
|
||||
|
||||
import com.ghy.common.adapay.PayResultMapping;
|
||||
import com.huifu.adapay.core.AdapayCore;
|
||||
import com.huifu.adapay.core.util.AdapaySign;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 提供给 Adapay 的回调接口
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class AdapayCallbackController {
|
||||
|
||||
@PostMapping("/adapay/callback")
|
||||
public String callback(@RequestBody Event event) {
|
||||
//验签请参data
|
||||
String data = event.getData();
|
||||
//验签请参sign
|
||||
String sign = event.getSign();
|
||||
boolean verifySign = false;
|
||||
try {
|
||||
verifySign = verifySign(data, sign);
|
||||
} catch (Exception e) {
|
||||
log.error("签名验证失败 {}", e.getMessage());
|
||||
}
|
||||
if (verifySign) {
|
||||
//Event事件类型
|
||||
String type = event.getType();
|
||||
if (StringUtils.isBlank(type)) {
|
||||
return "NG";
|
||||
}
|
||||
switch (type) {
|
||||
case "payment.succeeded":
|
||||
case "payment.failed":
|
||||
PayResultMapping.putResult(event);
|
||||
break;
|
||||
default:
|
||||
log.warn("UNKNOWN EVENT TYPE [{}]", type);
|
||||
return "NG";
|
||||
}
|
||||
return "OK";
|
||||
}
|
||||
log.warn("签名验证失败 data=[{}], sign=[{}]", data, sign);
|
||||
return "NG";
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验签名
|
||||
*
|
||||
* @param data AdapayCallback.data
|
||||
* @param sign AdapayCallback.sign
|
||||
* @return TRUE=校验成功
|
||||
*/
|
||||
private boolean verifySign(String data, String sign) throws Exception {
|
||||
Assert.hasText(data, "data is blank!");
|
||||
Assert.hasText(sign, "sign is blank!");
|
||||
//验签请参publicKey
|
||||
String publicKey = AdapayCore.PUBLIC_KEY;
|
||||
log.debug("验签请参:data={}sign={}", data, sign);
|
||||
//验签
|
||||
return AdapaySign.verifySign(data, sign, publicKey);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.ghy.common.adapay.callback;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 支付结果
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
@Data
|
||||
public class Event {
|
||||
|
||||
/**
|
||||
* 由 Adapay 生成的支付对象 id, 该 id 在 Adapay 系统内唯一
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
private String sign;
|
||||
/**
|
||||
* 支付创建时的 10 位时间戳
|
||||
*/
|
||||
@JSONField(name = "created_time")
|
||||
private Long createdTime;
|
||||
/**
|
||||
* 是否 prod模式,true 是 prod模式,false 是 mock模式
|
||||
*/
|
||||
@JSONField(name = "created_time")
|
||||
private String prodMode;
|
||||
/**
|
||||
* Event 事件类型
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 支付对象
|
||||
*/
|
||||
private String data;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.ghy.common.adapay.callback;
|
||||
|
||||
import com.huifu.adapay.model.Payment;
|
||||
|
||||
/**
|
||||
* 处理支付结果的回调接口
|
||||
*
|
||||
* @author HH 2022/3/25
|
||||
*/
|
||||
public interface PayCallback {
|
||||
|
||||
void onResponse(Payment payment);
|
||||
}
|
||||
28
pom.xml
28
pom.xml
|
|
@ -37,6 +37,8 @@
|
|||
<qiniu.version>7.4.0</qiniu.version>
|
||||
<gson.version>2.8.5</gson.version>
|
||||
<wxpay.version>0.4.3</wxpay.version>
|
||||
<Adapay.version>1.2.10</Adapay.version>
|
||||
<httpcomponents.version>4.5.13</httpcomponents.version>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
|
|
@ -199,6 +201,32 @@
|
|||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 汇聚支付 Adapay SDK -->
|
||||
<dependency>
|
||||
<groupId>com.huifu.adapay.core</groupId>
|
||||
<artifactId>adapay-core-sdk</artifactId>
|
||||
<version>${Adapay.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.huifu.adapay</groupId>
|
||||
<artifactId>adapay-java-sdk</artifactId>
|
||||
<version>${Adapay.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Adapay SDK 需要依赖 httpmime -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
<version>${httpcomponents.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Adapay SDK 需要依赖 httpclient -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpcomponents.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- log4j日志组件 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
|
|
|
|||
Loading…
Reference in New Issue