Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
7bc08650
authored
Jun 03, 2026
by
renyizhao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
已经可以支付 但轮询还未测试
parent
fde4e3ac
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
271 additions
and
4 deletions
+271
-4
computility-module-member/pom.xml
+5
-0
computility-module-member/src/main/java/com/luhu/computility/module/member/controller/admin/notify/MemberRechargeWpgjPayController.java
+166
-0
computility-module-member/src/main/java/com/luhu/computility/module/member/controller/app/recharge/AppRechargeController.java
+74
-3
computility-module-member/src/main/java/com/luhu/computility/module/member/service/recharge/MemberRechargeServiceImpl.java
+11
-1
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/PayOrderApiImpl.java
+6
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/framework/pay/core/client/impl/wpgj/WpgjPayProperties.java
+5
-0
computility-server/src/main/resources/application-dev.yaml
+1
-0
computility-server/src/main/resources/application-local.yaml
+1
-0
computility-server/src/main/resources/application-prod.yaml
+1
-0
computility-server/src/main/resources/application.yaml
+1
-0
No files found.
computility-module-member/pom.xml
View file @
7bc08650
...
...
@@ -33,6 +33,11 @@
<artifactId>
computility-module-infra
</artifactId>
<version>
${revision}
</version>
</dependency>
<dependency>
<groupId>
com.luhu
</groupId>
<artifactId>
computility-module-pay
</artifactId>
<version>
${revision}
</version>
</dependency>
<!-- 业务组件 -->
<dependency>
...
...
computility-module-member/src/main/java/com/luhu/computility/module/member/controller/admin/notify/MemberRechargeWpgjPayController.java
0 → 100644
View file @
7bc08650
package
com
.
luhu
.
computility
.
module
.
member
.
controller
.
admin
.
notify
;
import
cn.hutool.core.util.StrUtil
;
import
com.luhu.computility.framework.common.pojo.CommonResult
;
import
com.luhu.computility.framework.common.util.json.JsonUtils
;
import
com.luhu.computility.module.member.service.recharge.MemberRechargeService
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyRespDTO
;
import
com.luhu.computility.module.pay.enums.WpgjOrderStatusEnum
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
javax.annotation.Resource
;
import
javax.annotation.security.PermitAll
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.Map
;
import
java.util.TreeMap
;
import
java.util.stream.Collectors
;
/**
* 会员模块 - WPGJ旺铺聚合支付回调Controller
*
* 处理会员充值的支付回调
*
* @author jony
*/
@Tag
(
name
=
"管理后台 - 会员充值WPGJ旺铺聚合支付回调"
)
@RestController
@RequestMapping
(
"/member/wpgj"
)
@Slf4j
public
class
MemberRechargeWpgjPayController
{
@Resource
private
MemberRechargeService
memberRechargeService
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@PostMapping
(
"/notify"
)
@PermitAll
@Operation
(
summary
=
"WPGJ支付异步回调通知 - 会员充值"
)
public
WpgjPayNotifyRespDTO
notifyWpgjPay
(
@RequestBody
WpgjPayNotifyDTO
notifyDTO
)
{
WpgjPayNotifyRespDTO
response
=
new
WpgjPayNotifyRespDTO
();
try
{
log
.
info
(
"[notifyWpgjPay][Member] 收到WPGJ支付回调: {}"
,
JsonUtils
.
toJsonString
(
notifyDTO
));
// 1. 验证签名
if
(!
verifyWpgjSignature
(
toPayloadMap
(
notifyDTO
)))
{
log
.
error
(
"[notifyWpgjPay][Member] WPGJ回调签名验证失败"
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"签名验证失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
String
merOrderId
=
notifyDTO
.
getMerOrderId
();
String
orderStatus
=
notifyDTO
.
getOrderStatus
();
log
.
info
(
"[notifyWpgjPay][Member] 处理WPGJ支付结果,商户订单号: {}, 订单状态: {}"
,
merOrderId
,
orderStatus
);
// 2. 根据订单状态更新充值记录
if
(
WpgjOrderStatusEnum
.
isSuccess
(
orderStatus
))
{
// 支付成功:更新充值状态为已支付
memberRechargeService
.
updateRechargeStatus
(
Long
.
parseLong
(
merOrderId
),
1
);
log
.
info
(
"[notifyWpgjPay][Member] 支付成功处理完成,商户订单号: {}"
,
merOrderId
);
}
else
if
(
WpgjOrderStatusEnum
.
isFailedOrClosed
(
orderStatus
))
{
// 支付失败/关闭:更新充值状态为支付失败
memberRechargeService
.
updateRechargeStatus
(
Long
.
parseLong
(
merOrderId
),
-
1
);
log
.
info
(
"[notifyWpgjPay][Member] 支付失败/关闭处理完成,商户订单号: {}"
,
merOrderId
);
}
else
{
log
.
info
(
"[notifyWpgjPay][Member] 订单状态无需处理,商户订单号: {}, 状态: {}"
,
merOrderId
,
orderStatus
);
}
// 3. 返回成功应答
response
.
setCode
(
"00"
);
response
.
setMsg
(
"成功"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
log
.
info
(
"[notifyWpgjPay][Member] 返回wpgj参数: {}"
,
JsonUtils
.
toJsonString
(
response
));
return
response
;
}
catch
(
Exception
e
)
{
log
.
error
(
"[notifyWpgjPay][Member] WPGJ支付回调处理失败"
,
e
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"处理失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
}
/**
* Map 形式的回调请求验签:对所有出现的非空字段(排除 sign)进行 ASCII 排序拼接后 + key,再 MD5(UTF-8) 大写
*/
private
boolean
verifyWpgjSignature
(
Map
<
String
,
Object
>
payload
)
{
try
{
Object
signObj
=
payload
.
get
(
"sign"
);
String
originSign
=
signObj
==
null
?
null
:
String
.
valueOf
(
signObj
);
if
(
StrUtil
.
isBlank
(
originSign
))
{
log
.
warn
(
"[verifyWpgjSignature][Member] 回调缺少 sign 字段"
);
return
false
;
}
// 过滤掉 sign、自身为空的字段,按 ASCII 升序
TreeMap
<
String
,
String
>
sorted
=
new
TreeMap
<>();
for
(
Map
.
Entry
<
String
,
Object
>
e
:
payload
.
entrySet
())
{
String
k
=
e
.
getKey
();
if
(
"sign"
.
equals
(
k
))
{
continue
;
}
String
v
=
e
.
getValue
()
==
null
?
null
:
String
.
valueOf
(
e
.
getValue
());
if
(
StrUtil
.
isBlank
(
v
))
{
continue
;
}
sorted
.
put
(
k
,
v
);
}
String
dataStr
=
sorted
.
entrySet
().
stream
()
.
map
(
en
->
en
.
getKey
()
+
"="
+
en
.
getValue
())
.
collect
(
Collectors
.
joining
(
"&"
));
String
signStr
=
dataStr
+
"&key="
+
wpgjPayProperties
.
getSignKey
();
String
calculatedSign
=
cn
.
hutool
.
crypto
.
digest
.
DigestUtil
.
md5Hex
(
signStr
).
toUpperCase
();
log
.
info
(
"[verifyWpgjSignature][Member-New] 待签名字符串: {}"
,
dataStr
);
log
.
info
(
"[verifyWpgjSignature][Member-New] 加签前(带key): {}"
,
signStr
);
log
.
info
(
"[verifyWpgjSignature][Member-New] 计算签名: {},原始签名: {}"
,
calculatedSign
,
originSign
);
return
calculatedSign
.
equalsIgnoreCase
(
originSign
);
}
catch
(
Exception
e
)
{
log
.
error
(
"[verifyWpgjSignature][Member-New] 验签异常"
,
e
);
return
false
;
}
}
/**
* 将 DTO 转换为 Map(以供应商字段名 snake_case 作为 key),便于统一验签
*/
private
Map
<
String
,
Object
>
toPayloadMap
(
WpgjPayNotifyDTO
dto
)
{
TreeMap
<
String
,
Object
>
map
=
new
TreeMap
<>();
map
.
put
(
"device_no"
,
dto
.
getDeviceNo
());
map
.
put
(
"mer_no"
,
dto
.
getMerNo
());
map
.
put
(
"mer_code"
,
dto
.
getMerCode
());
map
.
put
(
"payway_code"
,
dto
.
getPaywayCode
());
map
.
put
(
"order_id"
,
dto
.
getOrderId
());
map
.
put
(
"mer_order_id"
,
dto
.
getMerOrderId
());
map
.
put
(
"gateway_mer_order_id"
,
dto
.
getGatewayMerOrderId
());
map
.
put
(
"order_time"
,
dto
.
getOrderTime
());
map
.
put
(
"order_amt"
,
dto
.
getOrderAmt
());
map
.
put
(
"order_status"
,
dto
.
getOrderStatus
());
map
.
put
(
"trade_no"
,
dto
.
getTradeNo
());
map
.
put
(
"trade_time"
,
dto
.
getTradeTime
());
map
.
put
(
"order_title"
,
dto
.
getOrderTitle
());
map
.
put
(
"fee"
,
dto
.
getFee
());
map
.
put
(
"act_amt"
,
dto
.
getActAmt
());
map
.
put
(
"buyer_id"
,
dto
.
getBuyerId
());
map
.
put
(
"trade_top_no"
,
dto
.
getTradeTopNo
());
map
.
put
(
"card_type"
,
dto
.
getCardType
());
map
.
put
(
"sign"
,
dto
.
getSign
());
return
map
;
}
}
computility-module-member/src/main/java/com/luhu/computility/module/member/controller/app/recharge/AppRechargeController.java
View file @
7bc08650
...
...
@@ -3,7 +3,11 @@ package com.luhu.computility.module.member.controller.app.recharge;
import
com.luhu.computility.framework.common.pojo.CommonResult
;
import
com.luhu.computility.module.member.controller.admin.recharge.vo.MemberRechargeCreateReqVO
;
import
com.luhu.computility.module.member.controller.admin.recharge.vo.MemberRechargeRespVO
;
import
com.luhu.computility.module.member.dal.dataobject.recharge.MemberRechargeDO
;
import
com.luhu.computility.module.member.service.recharge.MemberRechargeService
;
import
com.luhu.computility.module.pay.api.wpgj.CommonWpgjPayApi
;
import
com.luhu.computility.module.pay.api.wpgj.dto.CommonWpgjCreateReqDTO
;
import
com.luhu.computility.module.pay.api.wpgj.vo.CommonWpgjPayOrderSubmitRespVO
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.RequiredArgsConstructor
;
...
...
@@ -25,6 +29,12 @@ import static com.luhu.computility.framework.security.core.util.SecurityFramewor
public
class
AppRechargeController
{
private
final
MemberRechargeService
rechargeService
;
private
final
CommonWpgjPayApi
commonWpgjPayApi
;
/**
* 业务类型:3-会员充值
*/
private
static
final
int
BUSINESS_TYPE_MEMBER_RECHARGE
=
3
;
@PostMapping
(
"/create"
)
@Operation
(
summary
=
"创建充值记录"
)
...
...
@@ -32,10 +42,44 @@ public class AppRechargeController {
Long
userId
=
getLoginUserId
();
BigDecimal
amount
=
reqVO
.
getAmount
();
BigDecimal
quota
=
amount
.
setScale
(
2
,
RoundingMode
.
HALF_UP
);
String
transactionId
=
"R"
+
System
.
currentTimeMillis
()
+
userId
;
// 1. 先创建充值记录
String
transactionId
=
"R"
+
System
.
currentTimeMillis
()
+
userId
;
Long
rechargeId
=
rechargeService
.
createRecharge
(
userId
,
amount
,
quota
,
"wpgj"
,
transactionId
);
// 2. 调用旺铺聚合支付
try
{
CommonWpgjCreateReqDTO
createReqDTO
=
new
CommonWpgjCreateReqDTO
();
createReqDTO
.
setBusinessType
(
BUSINESS_TYPE_MEMBER_RECHARGE
);
createReqDTO
.
setBusinessOrderId
(
rechargeId
);
createReqDTO
.
setOrderTitle
(
"会员充值 - "
+
amount
+
"元"
);
createReqDTO
.
setPayAmount
(
amount
.
multiply
(
BigDecimal
.
valueOf
(
100
)).
intValue
());
// 转换为分
CommonWpgjPayOrderSubmitRespVO
payRespVO
=
commonWpgjPayApi
.
createCommonWpgjOrder
(
createReqDTO
);
// 3. 构建返回
MemberRechargeRespVO
respVO
=
new
MemberRechargeRespVO
();
respVO
.
setId
(
rechargeId
);
respVO
.
setAmount
(
amount
);
respVO
.
setQuota
(
quota
);
respVO
.
setPayChannel
(
"wpgj"
);
respVO
.
setTransactionId
(
transactionId
);
respVO
.
setPayStatus
(
0
);
respVO
.
setPayStatusName
(
"待支付"
);
// 根据 displayMode 决定二维码URL
if
(
"QR_CODE"
.
equals
(
payRespVO
.
getDisplayMode
())
&&
payRespVO
.
getDisplayContent
()
!=
null
)
{
respVO
.
setQrCodeUrl
(
payRespVO
.
getDisplayContent
());
}
else
if
(
payRespVO
.
getDisplayContent
()
!=
null
)
{
respVO
.
setQrCodeUrl
(
payRespVO
.
getDisplayContent
());
}
log
.
info
(
"[创建充值记录] userId={}, amount={}, rechargeId={}, wpgjOrderId={}"
,
userId
,
amount
,
rechargeId
,
payRespVO
.
getWpgjOrderId
());
return
CommonResult
.
success
(
respVO
);
}
catch
(
Exception
e
)
{
log
.
error
(
"[创建充值记录] 调用旺铺支付失败 userId={}, amount={}, rechargeId={}"
,
userId
,
amount
,
rechargeId
,
e
);
// 返回基本信息,让前端显示错误
MemberRechargeRespVO
respVO
=
new
MemberRechargeRespVO
();
respVO
.
setId
(
rechargeId
);
respVO
.
setAmount
(
amount
);
...
...
@@ -44,11 +88,38 @@ public class AppRechargeController {
respVO
.
setTransactionId
(
transactionId
);
respVO
.
setPayStatus
(
0
);
respVO
.
setPayStatusName
(
"待支付"
);
respVO
.
setQrCodeUrl
(
"https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=recharge_"
+
rechargeId
);
return
CommonResult
.
success
(
respVO
);
}
}
@GetMapping
(
"/get"
)
@Operation
(
summary
=
"查询充值记录状态"
)
public
CommonResult
<
MemberRechargeRespVO
>
getRecharge
(
@RequestParam
(
"id"
)
Long
id
)
{
MemberRechargeDO
recharge
=
rechargeService
.
getRechargeById
(
id
);
if
(
recharge
==
null
)
{
return
CommonResult
.
error
(
1
,
"充值记录不存在"
);
}
log
.
info
(
"[创建充值记录] userId={}, amount={}, rechargeId={}"
,
userId
,
amount
,
rechargeId
);
MemberRechargeRespVO
respVO
=
new
MemberRechargeRespVO
();
respVO
.
setId
(
recharge
.
getId
());
respVO
.
setAmount
(
recharge
.
getAmount
());
respVO
.
setQuota
(
recharge
.
getQuota
());
respVO
.
setPayChannel
(
recharge
.
getPayChannel
());
respVO
.
setPayStatus
(
recharge
.
getPayStatus
());
respVO
.
setPayStatusName
(
getPayStatusName
(
recharge
.
getPayStatus
()));
respVO
.
setPayTime
(
recharge
.
getPayTime
());
respVO
.
setTransactionId
(
recharge
.
getTransactionId
());
return
CommonResult
.
success
(
respVO
);
}
private
String
getPayStatusName
(
Integer
payStatus
)
{
if
(
payStatus
==
null
)
return
"未知"
;
if
(
payStatus
==
-
1
)
return
"支付失败"
;
if
(
payStatus
==
0
)
return
"待支付"
;
if
(
payStatus
==
1
)
return
"已支付"
;
if
(
payStatus
==
2
)
return
"已退款"
;
return
"未知"
;
}
}
computility-module-member/src/main/java/com/luhu/computility/module/member/service/recharge/MemberRechargeServiceImpl.java
View file @
7bc08650
...
...
@@ -35,10 +35,20 @@ public class MemberRechargeServiceImpl implements MemberRechargeService {
2
,
"已退款"
);
/**
* 业务类型:3-会员充值(用于生成订单号)
*/
private
static
final
int
BUSINESS_TYPE_MEMBER_RECHARGE
=
3
;
@Override
public
Long
createRecharge
(
Long
userId
,
BigDecimal
amount
,
BigDecimal
quota
,
String
payChannel
,
String
transactionId
)
{
// 生成类似 compute 模块那样的长订单号:前缀(1位) + 时间戳(13位)
// 例如:3117804779539728
long
orderId
=
Long
.
parseLong
(
BUSINESS_TYPE_MEMBER_RECHARGE
+
String
.
valueOf
(
System
.
currentTimeMillis
()));
MemberRechargeDO
recharge
=
MemberRechargeDO
.
builder
()
.
id
(
orderId
)
.
userId
(
userId
)
.
amount
(
amount
)
.
quota
(
quota
)
...
...
@@ -48,7 +58,7 @@ public class MemberRechargeServiceImpl implements MemberRechargeService {
.
callbackStatus
(
0
)
.
build
();
rechargeMapper
.
insert
(
recharge
);
log
.
info
(
"[创建充值记录] userId={}, amount={}, transactionId={}
"
,
userId
,
amount
,
transaction
Id
);
log
.
info
(
"[创建充值记录] userId={}, amount={}, transactionId={}
, orderId={}"
,
userId
,
amount
,
transactionId
,
order
Id
);
return
recharge
.
getId
();
}
...
...
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/PayOrderApiImpl.java
View file @
7bc08650
...
...
@@ -250,6 +250,12 @@ public class PayOrderApiImpl implements PayOrderApi {
return
apiNotifyUrl
;
}
break
;
case
3
:
String
memberNotifyUrl
=
wpgjPayProperties
.
getNotifyUrlMember
();
if
(
memberNotifyUrl
!=
null
&&
!
memberNotifyUrl
.
trim
().
isEmpty
())
{
return
memberNotifyUrl
;
}
break
;
default
:
break
;
}
...
...
computility-module-pay/src/main/java/com/luhu/computility/module/pay/framework/pay/core/client/impl/wpgj/WpgjPayProperties.java
View file @
7bc08650
...
...
@@ -50,6 +50,11 @@ public class WpgjPayProperties {
private
String
notifyUrlApi
;
/**
* 会员充值模块回调地址
*/
private
String
notifyUrlMember
;
/**
* 兼容旧的notifyUrl字段
*/
private
String
notifyUrl
;
...
...
computility-server/src/main/resources/application-dev.yaml
View file @
7bc08650
...
...
@@ -211,6 +211,7 @@ computility:
-----END PRIVATE KEY-----
notify-url-compute
:
https://ric.admin.lijinqi.com/admin-api/compute/wpgj/notify
# 算力资源模块WPGJ回调地址
notify-url-api
:
https://ric.admin.lijinqi.com/admin-api/apihub/wpgj/notify
# APIHub模块WPGJ回调地址
notify-url-member
:
https://ric.admin.lijinqi.com/admin-api/member/wpgj/notify
# 会员充值模块WPGJ回调地址
access-log
:
# 访问日志的配置项
enable
:
true
demo
:
false
# 开启演示模式
...
...
computility-server/src/main/resources/application-local.yaml
View file @
7bc08650
...
...
@@ -245,6 +245,7 @@ computility:
-----END PRIVATE KEY-----
notify-url-compute
:
https://ric.admin.lijinqi.com/admin-api/compute/wpgj/notify
# 算力资源模块WPGJ回调地址
notify-url-api
:
https://ric.admin.lijinqi.com/admin-api/apihub/wpgj/notify
# APIHub模块WPGJ回调地址
notify-url-member
:
https://ric.admin.lijinqi.com/admin-api/member/wpgj/notify
# 会员充值模块WPGJ回调地址
access-log
:
# 访问日志的配置项
enable
:
false
demo
:
false
# 关闭演示模式
...
...
computility-server/src/main/resources/application-prod.yaml
View file @
7bc08650
...
...
@@ -211,6 +211,7 @@ computility:
-----END PRIVATE KEY-----
notify-url-compute
:
https://phslgld.hnluchuan.com/admin-api/compute/wpgj/notify
# 算力资源模块WPGJ回调地址
notify-url-api
:
https://phslgld.hnluchuan.com/admin-api/apihub/wpgj/notify
# APIHub模块WPGJ回调地址
notify-url-member
:
https://phslgld.hnluchuan.com/admin-api/member/wpgj/notify
# 会员充值模块WPGJ回调地址
access-log
:
# 访问日志的配置项
enable
:
true
demo
:
false
# 开启演示模式
...
...
computility-server/src/main/resources/application.yaml
View file @
7bc08650
...
...
@@ -283,6 +283,7 @@ computility:
-
/open-api/external/**
-
/admin-api/compute/wpgj/notify
-
/admin-api/apihub/wpgj/notify
-
/admin-api/member/wpgj/notify
ignore-visit-urls
:
-
/admin-api/system/user/profile/**
-
/admin-api/system/auth/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment