微信小程序支付接口和Adapay回调接口

This commit is contained in:
HH 2022-03-25 19:29:11 +08:00
parent 38f6596812
commit 3c07c9f5c6
11 changed files with 421 additions and 0 deletions

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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
View File

@ -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>