Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Jeepay
Commits
d430a2b5
Commit
d430a2b5
authored
Feb 20, 2023
by
zhuxiao
Browse files
新增转账异步通知实现
parent
43e2669d
Changes
5
Hide whitespace changes
Inline
Side-by-side
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/AbstractTransferNoticeService.java
0 → 100644
View file @
d430a2b5
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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
com.jeequan.jeepay.pay.channel
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.beans.RequestKitBean
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
com.jeequan.jeepay.pay.util.ChannelCertConfigKitBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.File
;
/*
* 实现回调接口抽象类
*
* @author zx
* @site https://www.jeequan.com
* @date 2022/12/30 10:18
*/
public
abstract
class
AbstractTransferNoticeService
implements
ITransferNoticeService
{
@Autowired
private
RequestKitBean
requestKitBean
;
@Autowired
private
ChannelCertConfigKitBean
channelCertConfigKitBean
;
@Autowired
protected
ConfigContextQueryService
configContextQueryService
;
@Override
public
ResponseEntity
doNotifyOrderNotExists
(
HttpServletRequest
request
)
{
return
textResp
(
"order not exists"
);
}
/** 文本类型的响应数据 **/
protected
ResponseEntity
textResp
(
String
text
){
HttpHeaders
httpHeaders
=
new
HttpHeaders
();
httpHeaders
.
setContentType
(
MediaType
.
TEXT_HTML
);
return
new
ResponseEntity
(
text
,
httpHeaders
,
HttpStatus
.
OK
);
}
/** json类型的响应数据 **/
protected
ResponseEntity
jsonResp
(
Object
body
){
HttpHeaders
httpHeaders
=
new
HttpHeaders
();
httpHeaders
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
return
new
ResponseEntity
(
body
,
httpHeaders
,
HttpStatus
.
OK
);
}
/**request.getParameter 获取参数 并转换为JSON格式 **/
protected
JSONObject
getReqParamJSON
()
{
return
requestKitBean
.
getReqParamJSON
();
}
/**request.getParameter 获取参数 并转换为JSON格式 **/
protected
String
getReqParamFromBody
()
{
return
requestKitBean
.
getReqParamFromBody
();
}
/** 获取文件路径 **/
protected
String
getCertFilePath
(
String
certFilePath
)
{
return
channelCertConfigKitBean
.
getCertFilePath
(
certFilePath
);
}
/** 获取文件File对象 **/
protected
File
getCertFile
(
String
certFilePath
)
{
return
channelCertConfigKitBean
.
getCertFile
(
certFilePath
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ITransferNoticeService.java
0 → 100644
View file @
d430a2b5
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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
com.jeequan.jeepay.pay.channel
;
import
com.jeequan.jeepay.core.entity.TransferOrder
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
org.apache.commons.lang3.tuple.MutablePair
;
import
org.springframework.http.ResponseEntity
;
import
javax.servlet.http.HttpServletRequest
;
/*
* 转账订单通知解析实现 异步回调
*
* @author zx
* @site https://www.jeequan.com
* @date 2022/12/30 10:14
*/
public
interface
ITransferNoticeService
{
/** 获取到接口code **/
String
getIfCode
();
/** 解析参数: 转账单号 和 请求参数
* 异常需要自行捕捉,并返回null , 表示已响应数据。
* **/
MutablePair
<
String
,
Object
>
parseParams
(
HttpServletRequest
request
,
String
urlOrderId
);
/** 返回需要更新的订单状态 和响应数据 **/
ChannelRetMsg
doNotice
(
HttpServletRequest
request
,
Object
params
,
TransferOrder
transferOrder
,
MchAppConfigContext
mchAppConfigContext
);
/** 数据库订单数据不存在 (仅异步通知使用) **/
ResponseEntity
doNotifyOrderNotExists
(
HttpServletRequest
request
);
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayTransferNoticeService.java
0 → 100644
View file @
d430a2b5
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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
com.jeequan.jeepay.pay.channel.alipay
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alipay.api.internal.util.AlipaySignature
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.TransferOrder
;
import
com.jeequan.jeepay.core.exception.ResponseException
;
import
com.jeequan.jeepay.core.model.params.alipay.AlipayConfig
;
import
com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams
;
import
com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams
;
import
com.jeequan.jeepay.pay.channel.AbstractTransferNoticeService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.tuple.MutablePair
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.stereotype.Service
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.Map
;
/*
* 支付宝 转账回调接口实现类
*
* @author zx
* @site https://www.jeequan.com
* @date 2021/21/01 17:16
*/
@Service
@Slf4j
public
class
AlipayTransferNoticeService
extends
AbstractTransferNoticeService
{
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
ALIPAY
;
}
@Override
public
MutablePair
<
String
,
Object
>
parseParams
(
HttpServletRequest
request
,
String
urlOrderId
)
{
try
{
JSONObject
params
=
getReqParamJSON
();
log
.
info
(
"【支付宝转账】回调通知参数:{}"
,
params
.
toJSONString
());
JSONObject
bizContent
=
JSONObject
.
parseObject
(
params
.
getString
(
"biz_content"
));
String
transferId
=
bizContent
.
getString
(
"out_biz_no"
);
return
MutablePair
.
of
(
transferId
,
params
);
}
catch
(
Exception
e
)
{
log
.
error
(
"error"
,
e
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
@Override
public
ChannelRetMsg
doNotice
(
HttpServletRequest
request
,
Object
params
,
TransferOrder
transferOrder
,
MchAppConfigContext
mchAppConfigContext
)
{
String
logPrefix
=
"【支付宝转账通知】"
;
try
{
//配置参数获取
Byte
useCert
=
null
;
String
alipaySignType
,
alipayPublicCert
,
alipayPublicKey
=
null
;
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 获取支付参数
AlipayIsvParams
alipayParams
=
(
AlipayIsvParams
)
configContextQueryService
.
queryIsvParams
(
mchAppConfigContext
.
getMchInfo
().
getIsvNo
(),
getIfCode
());
useCert
=
alipayParams
.
getUseCert
();
alipaySignType
=
alipayParams
.
getSignType
();
alipayPublicCert
=
alipayParams
.
getAlipayPublicCert
();
alipayPublicKey
=
alipayParams
.
getAlipayPublicKey
();
}
else
{
// 获取支付参数
AlipayNormalMchParams
alipayParams
=
(
AlipayNormalMchParams
)
configContextQueryService
.
queryNormalMchParams
(
mchAppConfigContext
.
getMchNo
(),
mchAppConfigContext
.
getAppId
(),
getIfCode
());
useCert
=
alipayParams
.
getUseCert
();
alipaySignType
=
alipayParams
.
getSignType
();
alipayPublicCert
=
alipayParams
.
getAlipayPublicCert
();
alipayPublicKey
=
alipayParams
.
getAlipayPublicKey
();
}
// 获取请求参数
JSONObject
jsonParams
=
(
JSONObject
)
params
;
JSONObject
bizContent
=
JSONObject
.
parseObject
(
jsonParams
.
getString
(
"biz_content"
));
boolean
verifyResult
;
if
(
useCert
!=
null
&&
useCert
==
CS
.
YES
){
//证书方式
verifyResult
=
AlipaySignature
.
rsaCertCheckV1
(
jsonParams
.
toJavaObject
(
Map
.
class
),
getCertFilePath
(
alipayPublicCert
),
AlipayConfig
.
CHARSET
,
alipaySignType
);
}
else
{
verifyResult
=
AlipaySignature
.
rsaCheckV1
(
jsonParams
.
toJavaObject
(
Map
.
class
),
alipayPublicKey
,
AlipayConfig
.
CHARSET
,
alipaySignType
);
}
//验签失败
if
(!
verifyResult
){
log
.
error
(
"{},验签失败"
,
logPrefix
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
//验签成功后判断上游订单状态
ResponseEntity
okResponse
=
textResp
(
"SUCCESS"
);
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
channelRetMsg
.
setResponseEntity
(
okResponse
);
// 响应数据
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
// 默认转账中
// 成功-SUCCESS
String
status
=
bizContent
.
getString
(
"status"
);
if
(
"SUCCESS"
.
equals
(
status
)){
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
return
channelRetMsg
;
}
catch
(
Exception
e
)
{
log
.
error
(
"error"
,
e
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayTransferService.java
View file @
d430a2b5
...
@@ -104,10 +104,12 @@ public class AlipayTransferService implements ITransferService {
...
@@ -104,10 +104,12 @@ public class AlipayTransferService implements ITransferService {
if
(
"SUCCESS"
.
equals
(
response
.
getStatus
()))
{
if
(
"SUCCESS"
.
equals
(
response
.
getStatus
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
channelRetMsg
.
setChannelOrderId
(
response
.
getOrderId
());
channelRetMsg
.
setChannelOrderId
(
response
.
getOrderId
());
return
channelRetMsg
;
}
else
if
(
"FAIL"
.
equals
(
response
.
getStatus
()))
{
}
else
if
(
"FAIL"
.
equals
(
response
.
getStatus
()))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
AlipayKit
.
appendErrCode
(
response
.
getCode
(),
response
.
getSubCode
()));
channelRetMsg
.
setChannelErrCode
(
AlipayKit
.
appendErrCode
(
response
.
getCode
(),
response
.
getSubCode
()));
channelRetMsg
.
setChannelErrMsg
(
AlipayKit
.
appendErrMsg
(
response
.
getMsg
(),
response
.
getSubMsg
()));
channelRetMsg
.
setChannelErrMsg
(
AlipayKit
.
appendErrMsg
(
response
.
getMsg
(),
response
.
getSubMsg
()));
return
channelRetMsg
;
}
else
{
}
else
{
return
ChannelRetMsg
.
waiting
();
return
ChannelRetMsg
.
waiting
();
}
}
...
@@ -122,9 +124,8 @@ public class AlipayTransferService implements ITransferService {
...
@@ -122,9 +124,8 @@ public class AlipayTransferService implements ITransferService {
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
response
.
getSubCode
());
channelRetMsg
.
setChannelErrCode
(
response
.
getSubCode
());
channelRetMsg
.
setChannelErrMsg
(
response
.
getSubMsg
());
channelRetMsg
.
setChannelErrMsg
(
response
.
getSubMsg
());
return
channelRetMsg
;
}
}
return
channelRetMsg
;
}
}
@Override
@Override
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/transfer/TransferNoticeController.java
0 → 100644
View file @
d430a2b5
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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
com.jeequan.jeepay.pay.ctrl.transfer
;
import
com.jeequan.jeepay.core.ctrls.AbstractCtrl
;
import
com.jeequan.jeepay.core.entity.TransferOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.exception.ResponseException
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.pay.channel.ITransferNoticeService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
com.jeequan.jeepay.pay.service.PayMchNotifyService
;
import
com.jeequan.jeepay.service.impl.TransferOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.commons.lang3.tuple.MutablePair
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
javax.servlet.http.HttpServletRequest
;
/**
* 转账异步通知入口Controller
*
* @author zx
* @site https://www.jeequan.com
* @date 2022/12/30 10:26
*/
@Slf4j
@Controller
public
class
TransferNoticeController
extends
AbstractCtrl
{
@Autowired
private
TransferOrderService
transferOrderService
;
@Autowired
private
ConfigContextQueryService
configContextQueryService
;
@Autowired
private
PayMchNotifyService
payMchNotifyService
;
/** 异步回调入口 **/
@ResponseBody
@RequestMapping
(
value
=
{
"/api/transfer/notify/{ifCode}"
,
"/api/transfer/notify/{ifCode}/{transferId}"
})
public
ResponseEntity
doNotify
(
HttpServletRequest
request
,
@PathVariable
(
"ifCode"
)
String
ifCode
,
@PathVariable
(
value
=
"transferId"
,
required
=
false
)
String
urlOrderId
){
String
transferId
=
null
;
String
logPrefix
=
"进入["
+
ifCode
+
"]转账回调:urlOrderId:["
+
StringUtils
.
defaultIfEmpty
(
urlOrderId
,
""
)
+
"] "
;
log
.
info
(
"===== {} ====="
,
logPrefix
);
try
{
// 参数有误
if
(
StringUtils
.
isEmpty
(
ifCode
)){
return
ResponseEntity
.
badRequest
().
body
(
"ifCode is empty"
);
}
//查询转账接口是否存在
ITransferNoticeService
transferNotifyService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"TransferNoticeService"
,
ITransferNoticeService
.
class
);
// 支付通道转账接口实现不存在
if
(
transferNotifyService
==
null
){
log
.
error
(
"{}, transfer interface not exists "
,
logPrefix
);
return
ResponseEntity
.
badRequest
().
body
(
"["
+
ifCode
+
"] transfer interface not exists"
);
}
// 解析转账单号 和 请求参数
MutablePair
<
String
,
Object
>
mutablePair
=
transferNotifyService
.
parseParams
(
request
,
urlOrderId
);
if
(
mutablePair
==
null
){
// 解析数据失败, 响应已处理
log
.
error
(
"{}, mutablePair is null "
,
logPrefix
);
throw
new
BizException
(
"解析数据异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
// 解析到转账单号
transferId
=
mutablePair
.
left
;
log
.
info
(
"{}, 解析数据为:transferId:{}, params:{}"
,
logPrefix
,
transferId
,
mutablePair
.
getRight
());
// 获取转账单号 和 转账单数据
TransferOrder
transferOrder
=
transferOrderService
.
getById
(
transferId
);
// 转账单不存在
if
(
transferOrder
==
null
){
log
.
error
(
"{}, 转账单不存在. transferId={} "
,
logPrefix
,
transferId
);
return
transferNotifyService
.
doNotifyOrderNotExists
(
request
);
}
//查询出商户应用的配置信息
MchAppConfigContext
mchAppConfigContext
=
configContextQueryService
.
queryMchInfoAndAppInfo
(
transferOrder
.
getMchNo
(),
transferOrder
.
getAppId
());
//调起接口的回调判断
ChannelRetMsg
notifyResult
=
transferNotifyService
.
doNotice
(
request
,
mutablePair
.
getRight
(),
transferOrder
,
mchAppConfigContext
);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if
(
notifyResult
==
null
||
notifyResult
.
getChannelState
()
==
null
||
notifyResult
.
getResponseEntity
()
==
null
){
log
.
error
(
"{}, 处理回调事件异常 notifyResult data error, notifyResult ={} "
,
logPrefix
,
notifyResult
);
throw
new
BizException
(
"处理回调事件异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
// 转账单是 【转账中状态】
if
(
transferOrder
.
getState
()
==
TransferOrder
.
STATE_ING
)
{
if
(
notifyResult
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
)
{
// 转账成功
transferOrderService
.
updateIng2Success
(
transferId
,
notifyResult
.
getChannelOrderId
());
payMchNotifyService
.
transferOrderNotify
(
transferOrderService
.
getById
(
transferId
));
}
else
if
(
notifyResult
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
){
// 转账失败
transferOrderService
.
updateIng2Fail
(
transferId
,
notifyResult
.
getChannelOrderId
(),
notifyResult
.
getChannelUserId
(),
notifyResult
.
getChannelErrCode
());
payMchNotifyService
.
transferOrderNotify
(
transferOrderService
.
getById
(
transferId
));
}
}
log
.
info
(
"===== {}, 转账单通知完成。 transferId={}, parseState = {} ====="
,
logPrefix
,
transferId
,
notifyResult
.
getChannelState
());
return
notifyResult
.
getResponseEntity
();
}
catch
(
BizException
e
)
{
log
.
error
(
"{}, transferId={}, BizException"
,
logPrefix
,
transferId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
catch
(
ResponseException
e
)
{
log
.
error
(
"{}, transferId={}, ResponseException"
,
logPrefix
,
transferId
,
e
);
return
e
.
getResponseEntity
();
}
catch
(
Exception
e
)
{
log
.
error
(
"{}, transferId={}, 系统异常"
,
logPrefix
,
transferId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
}
}
Write
Preview
Supports
Markdown
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