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
de3de82d
Commit
de3de82d
authored
Jun 09, 2021
by
dingzhiwei
Browse files
初始化Jeepay项目
parent
40dcaf4a
Changes
453
Hide whitespace changes
Inline
Side-by-side
Too many changes to show.
To preserve performance only
20 of 453+
files are displayed.
Plain diff
Email patch
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/payway/AliJsapi.java
0 → 100644
View file @
de3de82d
/*
* 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.ysfpay.payway
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.pay.channel.ysfpay.YsfpayPaymentService
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.AliJsapiOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.AliJsapiOrderRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.util.ApiResBuilder
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
/*
* 云闪付 支付宝 jsapi
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 18:11
*/
@Service
(
"ysfpayPaymentByAliJsapiService"
)
//Service Name需保持全局唯一性
public
class
AliJsapi
extends
YsfpayPaymentService
{
@Override
public
String
preCheck
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
)
{
AliJsapiOrderRQ
bizRQ
=
(
AliJsapiOrderRQ
)
rq
;
if
(
StringUtils
.
isEmpty
(
bizRQ
.
getBuyerUserId
())){
throw
new
BizException
(
"[buyerUserId]不可为空"
);
}
return
null
;
}
public
AbstractRS
pay
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
,
MchConfigContext
mchConfigContext
)
throws
Exception
{
String
logPrefix
=
"【云闪付(alipayJs)jsapi支付】"
;
JSONObject
reqParams
=
new
JSONObject
();
AliJsapiOrderRS
res
=
ApiResBuilder
.
buildSuccess
(
AliJsapiOrderRS
.
class
);
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
res
.
setChannelRetMsg
(
channelRetMsg
);
// 请求参数赋值
jsapiParamsSet
(
reqParams
,
payOrder
,
getNotifyUrl
(),
getReturnUrl
());
AliJsapiOrderRQ
bizRQ
=
(
AliJsapiOrderRQ
)
rq
;
//云闪付扫一扫支付, 需要传入buyerUserId参数
reqParams
.
put
(
"userId"
,
bizRQ
.
getBuyerUserId
());
// buyerUserId
//客户端IP
reqParams
.
put
(
"customerIp"
,
StringUtils
.
defaultIfEmpty
(
payOrder
.
getClientIp
(),
"127.0.0.1"
));
// 发送请求并返回订单状态
JSONObject
resJSON
=
packageParamAndReq
(
"/gateway/api/pay/unifiedorder"
,
reqParams
,
logPrefix
,
mchConfigContext
.
getIsvConfigContext
(),
mchConfigContext
);
//请求 & 响应成功, 判断业务逻辑
String
respCode
=
resJSON
.
getString
(
"respCode"
);
//应答码
String
respMsg
=
resJSON
.
getString
(
"respMsg"
);
//应答信息
try
{
//00-交易成功, 02-用户支付中 , 12-交易重复, 需要发起查询处理 其他认为失败
if
(
"00"
.
equals
(
respCode
)){
//付款信息
JSONObject
payDataJSON
=
JSONObject
.
parseObject
(
resJSON
.
getString
(
"payData"
));
String
tradeNo
=
""
;
if
(
StringUtils
.
isNotBlank
(
payDataJSON
.
getString
(
"tradeNo"
))){
tradeNo
=
payDataJSON
.
getString
(
"tradeNo"
);
}
else
{
String
prepayId
=
payDataJSON
.
getString
(
"prepayId"
);
if
(
prepayId
!=
null
&&
prepayId
.
length
()
>
2
){
tradeNo
=
prepayId
.
substring
(
2
);
}
}
res
.
setAlipayTradeNo
(
tradeNo
);
res
.
setPayData
(
payDataJSON
.
toJSONString
());
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
}
}
catch
(
Exception
e
)
{
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
return
res
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/payway/WxBar.java
0 → 100644
View file @
de3de82d
/*
* 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.ysfpay.payway
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.pay.channel.ysfpay.YsfpayPaymentService
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.WxBarOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.WxBarOrderRS
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.util.ApiResBuilder
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
/*
* 云闪付 微信bar
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 18:11
*/
@Service
(
"ysfPaymentByWxBarService"
)
//Service Name需保持全局唯一性
public
class
WxBar
extends
YsfpayPaymentService
{
@Override
public
String
preCheck
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
)
{
WxBarOrderRQ
bizRQ
=
(
WxBarOrderRQ
)
rq
;
if
(
StringUtils
.
isEmpty
(
bizRQ
.
getAuthCode
())){
throw
new
BizException
(
"用户支付条码[authCode]不可为空"
);
}
return
null
;
}
public
AbstractRS
pay
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
,
MchConfigContext
mchConfigContext
)
throws
Exception
{
String
logPrefix
=
"【云闪付条码(wechat)支付】"
;
WxBarOrderRQ
bizRQ
=
(
WxBarOrderRQ
)
rq
;
WxBarOrderRS
res
=
ApiResBuilder
.
buildSuccess
(
WxBarOrderRS
.
class
);
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
res
.
setChannelRetMsg
(
channelRetMsg
);
JSONObject
reqParams
=
new
JSONObject
();
reqParams
.
put
(
"authCode"
,
bizRQ
.
getAuthCode
());
//付款码: 用户 APP 展示的付款条码或二维码
// 云闪付 bar 统一参数赋值
barParamsSet
(
reqParams
,
payOrder
);
//客户端IP
reqParams
.
put
(
"termInfo"
,
"{\"ip\": \""
+
StringUtils
.
defaultIfEmpty
(
payOrder
.
getClientIp
(),
"127.0.0.1"
)+
"\"}"
);
//终端信息
// 发送请求
JSONObject
resJSON
=
packageParamAndReq
(
"/gateway/api/pay/micropay"
,
reqParams
,
logPrefix
,
mchConfigContext
.
getIsvConfigContext
(),
mchConfigContext
);
//请求 & 响应成功, 判断业务逻辑
String
respCode
=
resJSON
.
getString
(
"respCode"
);
//应答码
String
respMsg
=
resJSON
.
getString
(
"respMsg"
);
//应答信息
try
{
//00-交易成功, 02-用户支付中 , 12-交易重复, 需要发起查询处理 其他认为失败
if
(
"00"
.
equals
(
respCode
)){
res
.
setPayData
(
resJSON
.
getString
(
"payData"
));
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
else
if
(
"02"
.
equals
(
respCode
)
||
"12"
.
equals
(
respCode
)
||
"99"
.
equals
(
respCode
)){
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
channelRetMsg
.
setNeedQuery
(
true
);
// 开启轮询查单
}
else
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
}
catch
(
Exception
e
)
{
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
return
res
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/payway/WxJsapi.java
0 → 100644
View file @
de3de82d
/*
* 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.ysfpay.payway
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.pay.channel.ysfpay.YsfpayPaymentService
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.WxJsapiOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.WxJsapiOrderRS
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.util.ApiResBuilder
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
/*
* 云闪付 微信jsapi
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 18:11
*/
@Service
(
"ysfpayPaymentByWxJsapiService"
)
//Service Name需保持全局唯一性
public
class
WxJsapi
extends
YsfpayPaymentService
{
@Override
public
String
preCheck
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
)
{
WxJsapiOrderRQ
bizRQ
=
(
WxJsapiOrderRQ
)
rq
;
if
(
StringUtils
.
isEmpty
(
bizRQ
.
getOpenid
())){
throw
new
BizException
(
"[openId]不可为空"
);
}
return
null
;
}
@Override
public
AbstractRS
pay
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
,
MchConfigContext
mchConfigContext
)
throws
Exception
{
String
logPrefix
=
"【云闪付(wechatJs)jsapi支付】"
;
JSONObject
reqParams
=
new
JSONObject
();
WxJsapiOrderRS
res
=
ApiResBuilder
.
buildSuccess
(
WxJsapiOrderRS
.
class
);
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
res
.
setChannelRetMsg
(
channelRetMsg
);
// 请求参数赋值
jsapiParamsSet
(
reqParams
,
payOrder
,
getNotifyUrl
(),
getReturnUrl
());
WxJsapiOrderRQ
bizRQ
=
(
WxJsapiOrderRQ
)
rq
;
//云闪付扫一扫支付, 需要传入openId参数
reqParams
.
put
(
"userId"
,
bizRQ
.
getOpenid
());
// openId
//客户端IP
reqParams
.
put
(
"customerIp"
,
StringUtils
.
defaultIfEmpty
(
payOrder
.
getClientIp
(),
"127.0.0.1"
));
// 发送请求并返回订单状态
JSONObject
resJSON
=
packageParamAndReq
(
"/gateway/api/pay/unifiedorder"
,
reqParams
,
logPrefix
,
mchConfigContext
.
getIsvConfigContext
(),
mchConfigContext
);
//请求 & 响应成功, 判断业务逻辑
String
respCode
=
resJSON
.
getString
(
"respCode"
);
//应答码
String
respMsg
=
resJSON
.
getString
(
"respMsg"
);
//应答信息
try
{
//00-交易成功, 02-用户支付中 , 12-交易重复, 需要发起查询处理 其他认为失败
if
(
"00"
.
equals
(
respCode
)){
//付款信息
res
.
setPayInfo
(
resJSON
.
getString
(
"payData"
));
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
}
else
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
}
catch
(
Exception
e
)
{
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
return
res
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/payway/YsfBar.java
0 → 100644
View file @
de3de82d
/*
* 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.ysfpay.payway
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.pay.channel.ysfpay.YsfpayPaymentService
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfBarOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfBarOrderRS
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.util.ApiResBuilder
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
/*
* 云闪付 云闪付条码支付
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 18:11
*/
@Service
(
"ysfPaymentByYsfBarService"
)
//Service Name需保持全局唯一性
public
class
YsfBar
extends
YsfpayPaymentService
{
@Override
public
String
preCheck
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
)
{
YsfBarOrderRQ
bizRQ
=
(
YsfBarOrderRQ
)
rq
;
if
(
StringUtils
.
isEmpty
(
bizRQ
.
getAuthCode
())){
throw
new
BizException
(
"用户支付条码[authCode]不可为空"
);
}
return
null
;
}
public
AbstractRS
pay
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
,
MchConfigContext
mchConfigContext
)
throws
Exception
{
String
logPrefix
=
"【云闪付条码(unionpay)支付】"
;
YsfBarOrderRQ
bizRQ
=
(
YsfBarOrderRQ
)
rq
;
YsfBarOrderRS
res
=
ApiResBuilder
.
buildSuccess
(
YsfBarOrderRS
.
class
);
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
res
.
setChannelRetMsg
(
channelRetMsg
);
JSONObject
reqParams
=
new
JSONObject
();
reqParams
.
put
(
"authCode"
,
bizRQ
.
getAuthCode
());
//付款码: 用户 APP 展示的付款条码或二维码
// 云闪付 bar 统一参数赋值
barParamsSet
(
reqParams
,
payOrder
);
//客户端IP
reqParams
.
put
(
"termInfo"
,
"{\"ip\": \""
+
StringUtils
.
defaultIfEmpty
(
payOrder
.
getClientIp
(),
"127.0.0.1"
)+
"\"}"
);
//终端信息
// 发送请求
JSONObject
resJSON
=
packageParamAndReq
(
"/gateway/api/pay/micropay"
,
reqParams
,
logPrefix
,
mchConfigContext
.
getIsvConfigContext
(),
mchConfigContext
);
//请求 & 响应成功, 判断业务逻辑
String
respCode
=
resJSON
.
getString
(
"respCode"
);
//应答码
String
respMsg
=
resJSON
.
getString
(
"respMsg"
);
//应答信息
try
{
//00-交易成功, 02-用户支付中 , 12-交易重复, 需要发起查询处理 其他认为失败
if
(
"00"
.
equals
(
respCode
)){
res
.
setPayData
(
resJSON
.
getString
(
"payData"
));
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
else
if
(
"02"
.
equals
(
respCode
)
||
"12"
.
equals
(
respCode
)
||
"99"
.
equals
(
respCode
)){
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
channelRetMsg
.
setNeedQuery
(
true
);
// 开启轮询查单
}
else
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
}
catch
(
Exception
e
)
{
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
return
res
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/payway/YsfJsapi.java
0 → 100644
View file @
de3de82d
/*
* 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.ysfpay.payway
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.pay.channel.ysfpay.YsfpayPaymentService
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfJsapiOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfJsapiOrderRS
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.util.ApiResBuilder
;
import
com.jeequan.jeepay.pay.model.IsvConfigContext
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
/*
* 云闪付 jsapi
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 18:11
*/
@Service
(
"ysfpayPaymentByJsapiService"
)
//Service Name需保持全局唯一性
public
class
YsfJsapi
extends
YsfpayPaymentService
{
@Override
public
String
preCheck
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
)
{
return
null
;
}
public
AbstractRS
pay
(
UnifiedOrderRQ
rq
,
PayOrder
payOrder
,
IsvConfigContext
isvConfigContext
,
MchConfigContext
mchConfigContext
)
throws
Exception
{
String
logPrefix
=
"【云闪付(unionpay)jsapi支付】"
;
JSONObject
reqParams
=
new
JSONObject
();
YsfJsapiOrderRS
res
=
ApiResBuilder
.
buildSuccess
(
YsfJsapiOrderRS
.
class
);
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
res
.
setChannelRetMsg
(
channelRetMsg
);
YsfJsapiOrderRQ
bizRQ
=
(
YsfJsapiOrderRQ
)
rq
;
// 请求参数赋值
jsapiParamsSet
(
reqParams
,
payOrder
,
getNotifyUrl
(),
getReturnUrl
());
//云闪付扫一扫支付, 需要传入termInfo参数
reqParams
.
put
(
"termInfo"
,
"{\"ip\": \""
+
StringUtils
.
defaultIfEmpty
(
payOrder
.
getClientIp
(),
"127.0.0.1"
)+
"\"}"
);
//客户端IP
reqParams
.
put
(
"customerIp"
,
StringUtils
.
defaultIfEmpty
(
payOrder
.
getClientIp
(),
"127.0.0.1"
));
// 发送请求并返回订单状态
JSONObject
resJSON
=
packageParamAndReq
(
"/gateway/api/pay/unifiedorder"
,
reqParams
,
logPrefix
,
isvConfigContext
,
mchConfigContext
);
//请求 & 响应成功, 判断业务逻辑
String
respCode
=
resJSON
.
getString
(
"respCode"
);
//应答码
String
respMsg
=
resJSON
.
getString
(
"respMsg"
);
//应答信息
try
{
//00-交易成功, 02-用户支付中 , 12-交易重复, 需要发起查询处理 其他认为失败
if
(
"00"
.
equals
(
respCode
)){
//付款信息
res
.
setPayData
(
resJSON
.
getString
(
"payData"
));
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
}
else
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
}
catch
(
Exception
e
)
{
channelRetMsg
.
setChannelErrCode
(
respCode
);
channelRetMsg
.
setChannelErrMsg
(
respMsg
);
}
return
res
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/utils/YsfHttpUtil.java
0 → 100644
View file @
de3de82d
/*
* 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.ysfpay.utils
;
import
com.alibaba.fastjson.JSON
;
import
com.jeequan.jeepay.core.constants.CS
;
import
javax.activation.MimetypesFileTypeMap
;
import
javax.net.ssl.*
;
import
java.io.BufferedReader
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.OutputStream
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.net.URLEncoder
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.security.SecureRandom
;
import
java.security.cert.CertificateException
;
import
java.security.cert.X509Certificate
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Map.Entry
;
/*
* 参考云闪付demo实现的 httputils
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:25
*/
public
class
YsfHttpUtil
{
private
static
final
String
DEFAULT_CHARSET
=
"UTF-8"
;
private
static
final
int
DEFAULT_TIMEOUT
=
60
*
1000
;
// 60 秒超时
public
static
String
doGet
(
String
url
)
throws
Exception
{
return
doGet
(
url
,
null
);
}
public
static
String
doGet
(
String
url
,
Map
<
String
,
Object
>
params
)
throws
Exception
{
return
doGet
(
url
,
params
,
null
);
}
public
static
String
doGet
(
String
url
,
Map
<
String
,
Object
>
headers
,
Map
<
String
,
Object
>
params
)
throws
Exception
{
String
getUrl
=
buildGetUrl
(
url
,
params
);
return
doRequest
(
getUrl
,
"GET"
,
headers
,
null
);
}
public
static
String
doPost
(
String
url
)
throws
Exception
{
return
doPost
(
url
,
null
);
}
public
static
String
doPost
(
String
url
,
Map
<
String
,
Object
>
params
)
throws
Exception
{
return
doPost
(
url
,
null
,
params
);
}
public
static
String
doPost
(
String
url
,
Map
<
String
,
Object
>
headers
,
Map
<
String
,
Object
>
params
)
throws
Exception
{
return
doPostStr
(
url
,
headers
,
buildQueryParams
(
params
));
}
public
static
String
doPostStr
(
String
url
,
Map
<
String
,
Object
>
headers
,
String
data
)
throws
Exception
{
return
doRequest
(
url
,
"POST"
,
headers
,
data
);
}
public
static
String
doPostJson
(
String
url
,
Map
<
String
,
Object
>
headers
,
Map
<
String
,
Object
>
params
)
throws
Exception
{
if
(
headers
==
null
)
{
headers
=
new
HashMap
<
String
,
Object
>();
}
if
(!
headers
.
containsKey
(
"Content-Type"
))
{
headers
.
put
(
"Content-Type"
,
"application/json; charset="
+
DEFAULT_CHARSET
);
}
return
doPostStr
(
url
,
headers
,
JSON
.
toJSONString
(
params
));
}
public
static
String
doPostFile
(
String
url
,
Map
<
String
,
Object
>
headers
,
Map
<
String
,
Object
>
params
,
Map
<
String
,
FileItem
>
fileParams
)
throws
Exception
{
HttpURLConnection
http
=
null
;
InputStream
in
=
null
;
OutputStream
out
=
null
;
try
{
String
boundary
=
String
.
valueOf
(
System
.
currentTimeMillis
());
// 随机分隔线
http
=
getHttpConnection
(
url
,
"POST"
);
http
.
setRequestProperty
(
"Content-Type"
,
"multipart/form-data; boundary="
+
boundary
+
";charset="
+
DEFAULT_CHARSET
);
// 添加HTTP请求头
if
(
headers
!=
null
&&
!
headers
.
isEmpty
())
{
for
(
Entry
<
String
,
Object
>
entry
:
headers
.
entrySet
())
{
http
.
setRequestProperty
(
entry
.
getKey
(),
entry
.
getValue
().
toString
());
}
}
out
=
http
.
getOutputStream
();
// 组装文本请求参数
byte
[]
entryBoundaryBytes
=
(
"\r\n--"
+
boundary
+
"\r\n"
).
getBytes
(
DEFAULT_CHARSET
);
if
(
params
!=
null
&&
!
params
.
isEmpty
())
{
for
(
Entry
<
String
,
Object
>
textEntry
:
params
.
entrySet
())
{
byte
[]
textBytes
=
getTextEntry
(
textEntry
.
getKey
(),
String
.
valueOf
(
textEntry
.
getValue
()));
out
.
write
(
entryBoundaryBytes
);
out
.
write
(
textBytes
);
}
}
// 组装文件请求参数
if
(
fileParams
!=
null
&&
!
fileParams
.
isEmpty
())
{
for
(
Entry
<
String
,
FileItem
>
fileEntry
:
fileParams
.
entrySet
())
{
FileItem
fileItem
=
fileEntry
.
getValue
();
byte
[]
fileBytes
=
getFileEntry
(
fileEntry
.
getKey
(),
fileItem
.
getFileName
(),
fileItem
.
getMimeType
());
out
.
write
(
entryBoundaryBytes
);
out
.
write
(
fileBytes
);
out
.
write
(
fileItem
.
getContent
());
}
}
// 添加请求结束标志
byte
[]
endBoundaryBytes
=
(
"\r\n--"
+
boundary
+
"--\r\n"
).
getBytes
(
DEFAULT_CHARSET
);
out
.
write
(
endBoundaryBytes
);
out
.
flush
();
in
=
http
.
getInputStream
();
return
getStreamAsString
(
in
);
}
finally
{
try
{
if
(
in
!=
null
)
{
in
.
close
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
try
{
if
(
out
!=
null
)
{
out
.
close
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
try
{
if
(
http
!=
null
)
{
http
.
disconnect
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
}
public
static
String
doRequest
(
String
url
,
String
method
,
Map
<
String
,
Object
>
headers
,
String
data
)
throws
Exception
{
HttpURLConnection
http
=
null
;
InputStream
in
=
null
;
OutputStream
out
=
null
;
try
{
http
=
getHttpConnection
(
url
,
method
);
if
(
headers
!=
null
&&
!
headers
.
isEmpty
())
{
for
(
Entry
<
String
,
Object
>
entry
:
headers
.
entrySet
())
{
http
.
setRequestProperty
(
entry
.
getKey
(),
entry
.
getValue
().
toString
());
}
}
if
(
data
!=
null
&&
!
data
.
trim
().
isEmpty
())
{
out
=
http
.
getOutputStream
();
out
.
write
(
data
.
getBytes
(
DEFAULT_CHARSET
));
out
.
flush
();
}
in
=
http
.
getInputStream
();
return
getStreamAsString
(
in
);
}
finally
{
try
{
if
(
in
!=
null
)
{
in
.
close
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
try
{
if
(
out
!=
null
)
{
out
.
close
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
try
{
if
(
http
!=
null
)
{
http
.
disconnect
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
}
private
static
HttpURLConnection
getHttpConnection
(
String
url
,
String
method
)
throws
Exception
{
boolean
isSSL
=
url
.
startsWith
(
"https"
);
if
(
isSSL
)
{
SSLContext
sslContext
=
SSLContext
.
getInstance
(
"SSL"
);
sslContext
.
init
(
new
KeyManager
[
0
],
new
TrustManager
[]
{
new
SimpleTrustManager
()
},
new
SecureRandom
());
SSLSocketFactory
sslf
=
sslContext
.
getSocketFactory
();
HttpsURLConnection
https
=
(
HttpsURLConnection
)
new
URL
(
url
).
openConnection
();
https
.
setHostnameVerifier
(
new
SimpleHostnameVerifier
());
https
.
setSSLSocketFactory
(
sslf
);
https
.
setRequestMethod
(
method
);
https
.
setDoOutput
(
true
);
https
.
setDoInput
(
true
);
https
.
setUseCaches
(
false
);
https
.
setConnectTimeout
(
DEFAULT_TIMEOUT
);
https
.
setReadTimeout
(
DEFAULT_TIMEOUT
);
return
https
;
}
else
{
HttpURLConnection
http
=
(
HttpURLConnection
)
new
URL
(
url
).
openConnection
();
http
.
setRequestMethod
(
method
);
http
.
setDoOutput
(
true
);
http
.
setDoInput
(
true
);
http
.
setUseCaches
(
false
);
http
.
setConnectTimeout
(
DEFAULT_TIMEOUT
);
http
.
setReadTimeout
(
DEFAULT_TIMEOUT
);
return
http
;
}
}
private
static
String
getStreamAsString
(
InputStream
in
)
throws
Exception
{
BufferedReader
reader
=
null
;
try
{
reader
=
new
BufferedReader
(
new
InputStreamReader
(
in
,
DEFAULT_CHARSET
));
StringBuilder
buffer
=
new
StringBuilder
();
String
line
=
null
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
buffer
.
append
(
line
);
}
return
buffer
.
toString
();
}
finally
{
if
(
reader
!=
null
)
{
reader
.
close
();
}
}
}
private
static
String
buildGetUrl
(
String
url
,
Map
<
String
,
Object
>
params
)
throws
Exception
{
String
queryParams
=
buildQueryParams
(
params
);
if
(
null
==
queryParams
||
queryParams
.
isEmpty
())
{
return
url
;
}
StringBuilder
sb
=
new
StringBuilder
();
if
(
url
.
endsWith
(
"?"
))
{
sb
.
append
(
url
).
append
(
queryParams
);
}
else
{
sb
.
append
(
url
).
append
(
"?"
).
append
(
queryParams
);
}
return
sb
.
toString
();
}
private
static
String
buildQueryParams
(
Map
<
String
,
Object
>
params
)
throws
Exception
{
if
(
null
==
params
||
params
.
isEmpty
())
{
return
null
;
}
StringBuilder
query
=
new
StringBuilder
();
boolean
hasParam
=
false
;
for
(
Entry
<
String
,
Object
>
entry
:
params
.
entrySet
())
{
Object
v
=
entry
.
getValue
();
if
(
v
==
null
)
{
continue
;
}
if
(
hasParam
)
{
query
.
append
(
"&"
);
}
else
{
hasParam
=
true
;
}
query
.
append
(
entry
.
getKey
()).
append
(
"="
).
append
(
URLEncoder
.
encode
(
v
.
toString
(),
DEFAULT_CHARSET
));
}
return
query
.
toString
();
}
private
static
byte
[]
getTextEntry
(
String
fieldName
,
String
fieldValue
)
throws
Exception
{
StringBuilder
entry
=
new
StringBuilder
();
entry
.
append
(
"Content-Disposition:form-data; name=\""
);
entry
.
append
(
fieldName
);
entry
.
append
(
"\"\r\nContent-Type:text/plain\r\n\r\n"
);
entry
.
append
(
fieldValue
);
return
entry
.
toString
().
getBytes
(
DEFAULT_CHARSET
);
}
private
static
byte
[]
getFileEntry
(
String
fieldName
,
String
fileName
,
String
mimeType
)
throws
Exception
{
StringBuilder
entry
=
new
StringBuilder
();
entry
.
append
(
"Content-Disposition:form-data; name=\""
);
entry
.
append
(
fieldName
);
entry
.
append
(
"\"; filename=\""
);
entry
.
append
(
fileName
);
entry
.
append
(
"\"\r\nContent-Type:"
);
entry
.
append
(
mimeType
);
entry
.
append
(
"\r\n\r\n"
);
return
entry
.
toString
().
getBytes
(
DEFAULT_CHARSET
);
}
private
static
class
SimpleHostnameVerifier
implements
HostnameVerifier
{
@Override
public
boolean
verify
(
String
hostname
,
SSLSession
session
)
{
return
true
;
}
}
private
static
class
SimpleTrustManager
implements
X509TrustManager
{
@Override
public
X509Certificate
[]
getAcceptedIssuers
()
{
return
null
;
}
@Override
public
void
checkServerTrusted
(
X509Certificate
[]
chain
,
String
authType
)
throws
CertificateException
{
}
@Override
public
void
checkClientTrusted
(
X509Certificate
[]
chain
,
String
authType
)
throws
CertificateException
{
}
}
public
static
class
FileItem
{
private
String
fileName
;
private
String
mimeType
;
private
byte
[]
content
;
public
FileItem
()
{
}
public
FileItem
(
String
fileName
,
byte
[]
content
)
{
this
.
fileName
=
fileName
;
this
.
content
=
content
;
}
public
FileItem
(
String
fileName
,
byte
[]
content
,
String
mimeType
)
{
this
.
fileName
=
fileName
;
this
.
content
=
content
;
this
.
mimeType
=
mimeType
;
}
public
String
getFileName
()
{
return
fileName
;
}
public
void
setFileName
(
String
fileName
)
{
this
.
fileName
=
fileName
;
}
public
String
getMimeType
()
{
if
(
mimeType
==
null
)
{
mimeType
=
getContentType
(
fileName
);
}
return
mimeType
;
}
public
void
setMimeType
(
String
mimeType
)
{
this
.
mimeType
=
mimeType
;
}
public
byte
[]
getContent
()
{
return
content
;
}
public
void
setContent
(
byte
[]
content
)
{
this
.
content
=
content
;
}
private
String
getContentType
(
String
fileName
)
{
String
defaultType
=
"application/octet-stream"
;
if
(
fileName
==
null
||
fileName
.
isEmpty
())
{
return
defaultType
;
}
String
contentType
=
null
;
try
{
Path
path
=
Paths
.
get
(
fileName
);
contentType
=
Files
.
probeContentType
(
path
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
if
(
contentType
==
null
||
contentType
.
isEmpty
())
{
contentType
=
new
MimetypesFileTypeMap
().
getContentType
(
fileName
);
}
return
contentType
;
}
}
/** 云闪付条码付 封装参数,orderType **/
public
static
String
getOrderTypeByBar
(
String
wayCode
){
if
(
CS
.
PAY_WAY_CODE
.
ALI_BAR
.
equals
(
wayCode
)){
return
"alipay"
;
}
else
if
(
CS
.
PAY_WAY_CODE
.
WX_BAR
.
equals
(
wayCode
)){
return
"wechat"
;
}
else
if
(
CS
.
PAY_WAY_CODE
.
YSF_BAR
.
equals
(
wayCode
)){
return
"unionpay"
;
}
return
null
;
}
/** 云闪付jsapi对应的订单类型 **/
public
static
String
getOrderTypeByJSapi
(
String
wayCode
){
if
(
CS
.
PAY_WAY_CODE
.
ALI_JSAPI
.
equals
(
wayCode
)){
return
"alipayJs"
;
}
else
if
(
CS
.
PAY_WAY_CODE
.
WX_JSAPI
.
equals
(
wayCode
)){
return
"wechatJs"
;
}
else
if
(
CS
.
PAY_WAY_CODE
.
YSF_JSAPI
.
equals
(
wayCode
)){
return
"upJs"
;
}
return
null
;
}
/** 云闪付通用订单类型, 如查单 **/
public
static
String
getOrderTypeByCommon
(
String
wayCode
){
if
(
CS
.
PAY_WAY_CODE
.
ALI_JSAPI
.
equals
(
wayCode
)
||
CS
.
PAY_WAY_CODE
.
ALI_BAR
.
equals
(
wayCode
)){
return
"alipay"
;
}
else
if
(
CS
.
PAY_WAY_CODE
.
WX_JSAPI
.
equals
(
wayCode
)
||
CS
.
PAY_WAY_CODE
.
WX_BAR
.
equals
(
wayCode
)){
return
"wechat"
;
}
else
if
(
CS
.
PAY_WAY_CODE
.
YSF_JSAPI
.
equals
(
wayCode
)
||
CS
.
PAY_WAY_CODE
.
YSF_BAR
.
equals
(
wayCode
)){
return
"unionpay"
;
}
return
null
;
}
}
\ No newline at end of file
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/utils/YsfSignUtils.java
0 → 100644
View file @
de3de82d
/*
* 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.ysfpay.utils
;
import
com.alibaba.fastjson.JSONObject
;
import
org.apache.commons.codec.binary.Base64
;
import
org.apache.commons.lang3.StringUtils
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.security.*
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.Enumeration
;
import
java.util.TreeMap
;
/**
* 银联接口签名工具类
*
* @author terrfly
* @modify pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021-06-07 07:15
*/
public
class
YsfSignUtils
{
private
static
final
String
KEYSTORE_TYPE_PKCS12
=
"PKCS12"
;
//私钥类型
private
static
final
String
KEYSTORE_PROVIDER_BC
=
"BC"
;
//提供商
private
static
final
String
ALGORITHM_SHA256WITHRSA
=
"SHA256withRSA"
;
//签名算法 sha256
private
static
final
String
CERTIFICATE_TYPE_X509
=
"X.509"
;
//公钥证书类型
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
YsfSignUtils
.
class
);
static
{
try
{
Security
.
addProvider
(
new
BouncyCastleProvider
());
}
catch
(
Exception
e
)
{
logger
.
error
(
"addProvider Error"
,
e
);
}
}
/** 签名
* 注意事项: 签名需商户申请 5.1.0版本证书;
* 文档: https://open.unionpay.com/tjweb/acproduct/list?apiSvcId=468&index=2
* 1. 排序并拼接为[key=value]格式;
* 2. 对原始签名串使用SHA-256算法做摘要
* 3. 使用商户私钥做签名(使用 SHA-256)
* 4. 进行Base64处理
* **/
public
static
String
signBy256
(
JSONObject
params
,
String
privateKeyFilePath
,
String
certPwd
)
{
try
{
//0. 将请求参数 转换成key1=value1&key2=value2的形式
String
stringSign
=
convertSignString
(
params
);
//1. 通过SHA256进行摘要并转16进制
byte
[]
signDigest
=
sha256X16
(
stringSign
,
"UTF-8"
);
//2. /获取私钥证书的key
PrivateKey
privateKey
=
getSignCertPrivateKey
(
privateKeyFilePath
,
certPwd
);
//3. 使用 SHA-256算法 进行签名
Signature
st
=
Signature
.
getInstance
(
ALGORITHM_SHA256WITHRSA
,
KEYSTORE_PROVIDER_BC
);
st
.
initSign
(
privateKey
);
st
.
update
(
signDigest
);
byte
[]
result
=
st
.
sign
();
//4. 做base64 处理
byte
[]
byteSign
=
Base64
.
encodeBase64
(
result
);
return
new
String
(
byteSign
);
}
catch
(
Exception
e
)
{
logger
.
error
(
"银联签名失败"
,
e
);
return
null
;
}
}
/** 验签 **/
public
static
boolean
validate
(
JSONObject
params
,
String
ysfpayPublicKey
){
//签名串
String
signature
=
params
.
getString
(
"signature"
);
// 将请求参数信息转换成key1=value1&key2=value2的形式
String
stringData
=
convertSignString
(
params
);
try
{
//1. 通过SHA256进行摘要并转16进制
byte
[]
signDigest
=
sha256X16
(
stringData
,
"UTF-8"
);
//构造公钥证书
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
"RSA"
);
byte
[]
encodedKey
=
Base64
.
decodeBase64
(
ysfpayPublicKey
);
PublicKey
pubKey
=
keyFactory
.
generatePublic
(
new
X509EncodedKeySpec
(
encodedKey
));
Signature
st
=
Signature
.
getInstance
(
ALGORITHM_SHA256WITHRSA
);
st
.
initVerify
(
pubKey
);
//公钥
st
.
update
(
signDigest
);
return
st
.
verify
(
Base64
.
decodeBase64
(
signature
.
getBytes
(
"UTF-8"
)));
}
catch
(
Exception
e
)
{
logger
.
error
(
"验签失败!"
,
e
);
}
return
false
;
}
/** 进件验签 **/
public
static
boolean
applyValidate
(
JSONObject
params
,
String
ysfpayPublicKey
){
//签名串
String
signature
=
params
.
getString
(
"signature"
);
// 将请求参数信息转换成key1=value1&key2=value2的形式
String
stringData
=
convertSignApplyNotifyString
(
params
);
try
{
//1. 通过SHA256进行摘要并转16进制
byte
[]
signDigest
=
sha256X16
(
stringData
,
"UTF-8"
);
//构造公钥证书
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
"RSA"
);
byte
[]
encodedKey
=
Base64
.
decodeBase64
(
ysfpayPublicKey
);
PublicKey
pubKey
=
keyFactory
.
generatePublic
(
new
X509EncodedKeySpec
(
encodedKey
));
Signature
st
=
Signature
.
getInstance
(
ALGORITHM_SHA256WITHRSA
);
st
.
initVerify
(
pubKey
);
//公钥
st
.
update
(
signDigest
);
return
st
.
verify
(
Base64
.
decodeBase64
(
signature
.
getBytes
(
"UTF-8"
)));
}
catch
(
Exception
e
)
{
logger
.
error
(
"验签失败!"
,
e
);
}
return
false
;
}
/** 进件回调 将JSON中的数据转换成key1=value1&key2=value2的形式,忽略null内容 和 signature字段* */
private
static
String
convertSignApplyNotifyString
(
JSONObject
params
)
{
TreeMap
<
String
,
Object
>
tree
=
new
TreeMap
<>();
//1. 所有参数进行排序
params
.
keySet
().
stream
().
forEach
(
key
->
tree
.
put
(
key
,
params
.
get
(
key
)));
//2. 拼接为 key=value&形式
StringBuffer
stringBuffer
=
new
StringBuffer
();
tree
.
keySet
().
stream
().
forEach
(
key
->
{
if
(
tree
.
get
(
key
)
==
null
)
{
return
;
}
if
(
"signature"
.
equals
(
key
)){
//签名串, 不参与签名
return
;
}
stringBuffer
.
append
(
key
).
append
(
"="
).
append
(
tree
.
get
(
key
).
toString
()).
append
(
"&"
);
});
//3. 去掉最后一个&
return
stringBuffer
.
substring
(
0
,
stringBuffer
.
length
()
-
1
);
}
/** 将JSON中的数据转换成key1=value1&key2=value2的形式, 忽略空内容 和 signature字段 **/
private
static
String
convertSignString
(
JSONObject
params
)
{
TreeMap
<
String
,
Object
>
tree
=
new
TreeMap
<>();
//1. 所有参数进行排序
params
.
keySet
().
stream
().
forEach
(
key
->
tree
.
put
(
key
,
params
.
get
(
key
)));
//2. 拼接为 key=value&形式
StringBuffer
stringBuffer
=
new
StringBuffer
();
tree
.
keySet
().
stream
().
forEach
(
key
->
{
if
(
tree
.
get
(
key
)
==
null
)
{
return
;
}
if
(
StringUtils
.
isAnyEmpty
(
key
,
tree
.
get
(
key
).
toString
())){
//空值, 不参与签名
return
;
}
if
(
"signature"
.
equals
(
key
)){
//签名串, 不参与签名
return
;
}
stringBuffer
.
append
(
key
).
append
(
"="
).
append
(
tree
.
get
(
key
).
toString
()).
append
(
"&"
);
});
//3. 去掉最后一个&
return
stringBuffer
.
substring
(
0
,
stringBuffer
.
length
()
-
1
);
}
/** 通过SHA256进行摘要并转16进制 **/
private
static
byte
[]
sha256X16
(
String
data
,
String
encoding
)
throws
Exception
{
MessageDigest
md
=
MessageDigest
.
getInstance
(
"SHA-256"
);
md
.
reset
();
md
.
update
(
data
.
getBytes
(
encoding
));
byte
[]
bytes
=
md
.
digest
();
StringBuilder
sha256StrBuff
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
bytes
.
length
;
i
++)
{
if
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]).
length
()
==
1
)
{
sha256StrBuff
.
append
(
"0"
).
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
else
{
sha256StrBuff
.
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
}
return
sha256StrBuff
.
toString
().
toLowerCase
().
getBytes
(
encoding
);
}
/** 获取证书私钥 **/
private
static
PrivateKey
getSignCertPrivateKey
(
String
pfxkeyfile
,
String
keypwd
)
{
FileInputStream
fis
=
null
;
try
{
KeyStore
keyStore
=
KeyStore
.
getInstance
(
KEYSTORE_TYPE_PKCS12
,
KEYSTORE_PROVIDER_BC
);
fis
=
new
FileInputStream
(
pfxkeyfile
);
char
[]
nPassword
=
null
==
keypwd
||
""
.
equals
(
keypwd
.
trim
())
?
null
:
keypwd
.
toCharArray
();
if
(
null
!=
keyStore
)
{
keyStore
.
load
(
fis
,
nPassword
);
}
Enumeration
<
String
>
aliasenum
=
keyStore
.
aliases
();
String
keyAlias
=
null
;
if
(
aliasenum
.
hasMoreElements
())
{
keyAlias
=
aliasenum
.
nextElement
();
}
PrivateKey
privateKey
=
(
PrivateKey
)
keyStore
.
getKey
(
keyAlias
,
keypwd
.
toCharArray
());
return
privateKey
;
}
catch
(
Exception
e
)
{
logger
.
error
(
"获取证书私钥失败!"
,
e
);
return
null
;
}
finally
{
if
(
null
!=
fis
)
{
try
{
fis
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/config/RedisConfig.java
0 → 100644
View file @
de3de82d
/*
* 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.config
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Primary
;
import
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
/*
* RedisConfig
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:25
*/
@Configuration
public
class
RedisConfig
{
@Value
(
"${spring.redis.host}"
)
private
String
host
;
@Value
(
"${spring.redis.port}"
)
private
Integer
port
;
@Value
(
"${spring.redis.timeout}"
)
private
Integer
timeout
;
@Value
(
"${spring.redis.database}"
)
private
Integer
defaultDatabase
;
@Value
(
"${spring.redis.password}"
)
private
String
password
;
/** 当前系统的redis缓存操作对象 (主对象) **/
@Primary
@Bean
(
name
=
"defaultStringRedisTemplate"
)
public
StringRedisTemplate
sysStringRedisTemplate
()
{
StringRedisTemplate
template
=
new
StringRedisTemplate
();
LettuceConnectionFactory
jedisConnectionFactory
=
new
LettuceConnectionFactory
();
jedisConnectionFactory
.
setHostName
(
host
);
jedisConnectionFactory
.
setPort
(
port
);
jedisConnectionFactory
.
setTimeout
(
timeout
);
if
(!
StringUtils
.
isEmpty
(
password
))
{
jedisConnectionFactory
.
setPassword
(
password
);
}
if
(
defaultDatabase
!=
0
)
{
jedisConnectionFactory
.
setDatabase
(
defaultDatabase
);
}
jedisConnectionFactory
.
afterPropertiesSet
();
template
.
setConnectionFactory
(
jedisConnectionFactory
);
return
template
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/config/SystemYmlConfig.java
0 → 100644
View file @
de3de82d
/*
* 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.config
;
import
lombok.Data
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.context.properties.NestedConfigurationProperty
;
import
org.springframework.stereotype.Component
;
/**
* 系统Yml配置参数定义Bean
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021-04-27 15:50
*/
@Component
@ConfigurationProperties
(
prefix
=
"isys"
)
@Data
public
class
SystemYmlConfig
{
/** 是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] **/
private
Boolean
allowCors
;
@NestedConfigurationProperty
//指定该属性为嵌套值, 否则默认为简单值导致对象为空(外部类不存在该问题, 内部static需明确指定)
private
OssFile
ossFile
;
/** 系统oss配置信息 **/
@Data
public
static
class
OssFile
{
/** 存储根路径 **/
private
String
rootPath
;
/** 公共读取块 **/
private
String
publicPath
;
/** 私有读取块 **/
private
String
privatePath
;
}
}
\ No newline at end of file
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/ApiController.java
0 → 100644
View file @
de3de82d
/*
* 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
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.ctrls.AbstractCtrl
;
import
com.jeequan.jeepay.core.entity.MchInfo
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.utils.JeepayKit
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRQ
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.pay.service.ValidateService
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
/*
* api 抽象接口, 公共函数
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:28
*/
public
abstract
class
ApiController
extends
AbstractCtrl
{
@Autowired
private
ValidateService
validateService
;
@Autowired
private
ConfigContextService
configContextService
;
/** 获取请求参数并转换为对象,通用验证 **/
protected
<
T
extends
AbstractRQ
>
T
getRQ
(
Class
<
T
>
cls
){
T
bizRQ
=
getObject
(
cls
);
// [1]. 验证通用字段规则
validateService
.
validate
(
bizRQ
);
return
bizRQ
;
}
/** 获取请求参数并转换为对象,商户通用验证 **/
protected
<
T
extends
AbstractRQ
>
T
getRQByWithMchSign
(
Class
<
T
>
cls
){
//获取请求RQ, and 通用验证
T
bizRQ
=
getRQ
(
cls
);
// 转换为 JSON
JSONObject
bizReqJSON
=
(
JSONObject
)
JSONObject
.
toJSON
(
bizRQ
);
// [2]. 业务校验, 包括: 验签, 商户状态是否可用, 是否支持该支付方式下单等。
String
mchNo
=
bizReqJSON
.
getString
(
"mchNo"
);
String
sign
=
bizRQ
.
getSign
();
if
(
StringUtils
.
isAnyEmpty
(
mchNo
,
sign
)){
throw
new
BizException
(
"参数有误!"
);
}
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
mchNo
);
MchInfo
mchInfo
=
mchConfigContext
==
null
?
null
:
mchConfigContext
.
getMchInfo
();
if
(
mchInfo
==
null
||
mchInfo
.
getState
()
!=
CS
.
YES
){
throw
new
BizException
(
"商户不存在或商户状态不可用"
);
}
// 验签
String
privateKey
=
mchInfo
.
getPrivateKey
();
bizReqJSON
.
remove
(
"sign"
);
if
(!
sign
.
equalsIgnoreCase
(
JeepayKit
.
getSign
(
bizReqJSON
,
privateKey
))){
throw
new
BizException
(
"验签失败"
);
}
return
bizRQ
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/AbstractPayOrderController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder
;
import
cn.hutool.core.date.DateUtil
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.MchInfo
;
import
com.jeequan.jeepay.core.entity.MchPayPassage
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.core.utils.SeqKit
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.pay.channel.IPaymentService
;
import
com.jeequan.jeepay.pay.ctrl.ApiController
;
import
com.jeequan.jeepay.pay.exception.ChannelException
;
import
com.jeequan.jeepay.pay.model.IsvConfigContext
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
com.jeequan.jeepay.pay.mq.queue.MqQueue4ChannelOrderQuery
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.QrCashierOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.QrCashierOrderRS
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.pay.service.PayMchNotifyService
;
import
com.jeequan.jeepay.service.impl.MchPayPassageService
;
import
com.jeequan.jeepay.service.impl.PayOrderService
;
import
com.jeequan.jeepay.service.impl.SysConfigService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
java.util.Date
;
/*
* 创建支付订单抽象类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:26
*/
@Slf4j
public
abstract
class
AbstractPayOrderController
extends
ApiController
{
@Autowired
private
MchPayPassageService
mchPayPassageService
;
@Autowired
private
PayOrderService
payOrderService
;
@Autowired
private
ConfigContextService
configContextService
;
@Autowired
private
PayMchNotifyService
payMchNotifyService
;
@Autowired
private
SysConfigService
sysConfigService
;
@Autowired
private
MqQueue4ChannelOrderQuery
mqChannelOrderQueryQueue
;
/** 统一下单 (新建订单模式) **/
protected
ApiRes
unifiedOrder
(
String
wayCode
,
UnifiedOrderRQ
bizRQ
){
return
unifiedOrder
(
wayCode
,
bizRQ
,
null
);
}
/** 统一下单 **/
protected
ApiRes
unifiedOrder
(
String
wayCode
,
UnifiedOrderRQ
bizRQ
,
PayOrder
payOrder
){
// 响应数据
UnifiedOrderRS
bizRS
=
null
;
//是否新订单模式 [ 一般接口都为新订单模式, 由于QR_CASHIER支付方式,需要先 在DB插入一个新订单, 导致此处需要特殊判断下。 如果已存在则直接更新,否则为插入。 ]
boolean
isNewOrder
=
payOrder
==
null
;
try
{
if
(
payOrder
!=
null
){
//当订单存在时,封装公共参数。
if
(
payOrder
.
getState
()
!=
PayOrder
.
STATE_INIT
){
throw
new
BizException
(
"订单状态异常"
);
}
payOrder
.
setWayCode
(
wayCode
);
// 需要将订单更新 支付方式
bizRQ
.
setMchNo
(
payOrder
.
getMchNo
());
bizRQ
.
setMchOrderNo
(
payOrder
.
getMchOrderNo
());
bizRQ
.
setWayCode
(
wayCode
);
bizRQ
.
setAmount
(
payOrder
.
getAmount
());
bizRQ
.
setCurrency
(
payOrder
.
getCurrency
());
bizRQ
.
setClientIp
(
payOrder
.
getClientIp
());
bizRQ
.
setSubject
(
payOrder
.
getSubject
());
bizRQ
.
setNotifyUrl
(
payOrder
.
getNotifyUrl
());
bizRQ
.
setReturnUrl
(
payOrder
.
getReturnUrl
());
bizRQ
.
setChannelExtra
(
payOrder
.
getChannelExtra
());
bizRQ
.
setChannelUser
(
payOrder
.
getChannelUser
());
bizRQ
.
setExtParam
(
payOrder
.
getExtParam
());
}
String
mchNo
=
bizRQ
.
getMchNo
();
// 只有新订单模式,进行校验
if
(
isNewOrder
&&
payOrderService
.
count
(
PayOrder
.
gw
().
eq
(
PayOrder:
:
getMchNo
,
mchNo
).
eq
(
PayOrder:
:
getMchOrderNo
,
bizRQ
.
getMchOrderNo
()))
>
0
){
throw
new
BizException
(
"商户订单["
+
bizRQ
.
getMchOrderNo
()+
"]已存在"
);
}
//获取支付参数 (缓存数据) 和 商户信息
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
mchNo
);
if
(
mchConfigContext
==
null
){
throw
new
BizException
(
"获取商户信息失败"
);
}
MchInfo
mchInfo
=
mchConfigContext
.
getMchInfo
();
//收银台支付并且只有新订单需要走这里, 收银台二次下单的wayCode应该为实际支付方式。
if
(
isNewOrder
&&
CS
.
PAY_WAY_CODE
.
QR_CASHIER
.
equals
(
wayCode
)){
//生成订单
payOrder
=
genPayOrder
(
bizRQ
,
mchInfo
,
null
);
String
payOrderId
=
payOrder
.
getPayOrderId
();
//订单入库 订单状态: 生成状态 此时没有和任何上游渠道产生交互。
payOrderService
.
save
(
payOrder
);
QrCashierOrderRS
qrCashierOrderRS
=
new
QrCashierOrderRS
();
QrCashierOrderRQ
qrCashierOrderRQ
=
(
QrCashierOrderRQ
)
bizRQ
;
String
payUrl
=
sysConfigService
.
getDBApplicationConfig
().
genUniJsapiPayUrl
(
payOrderId
);
if
(
CS
.
PAY_DATA_TYPE
.
CODE_IMG_URL
.
equals
(
qrCashierOrderRQ
.
getPayDataType
())){
//二维码地址
qrCashierOrderRS
.
setCodeImgUrl
(
sysConfigService
.
getDBApplicationConfig
().
genScanImgUrl
(
payUrl
));
}
else
{
//默认都为跳转地址方式
qrCashierOrderRS
.
setPayUrl
(
payUrl
);
}
return
packageApiResByPayOrder
(
bizRQ
,
qrCashierOrderRS
,
payOrder
);
}
//获取支付接口
IPaymentService
paymentService
=
checkMchWayCodeAndGetService
(
mchConfigContext
,
wayCode
);
String
ifCode
=
paymentService
.
getIfCode
();
//生成订单
if
(
isNewOrder
){
payOrder
=
genPayOrder
(
bizRQ
,
mchInfo
,
ifCode
);
}
else
{
payOrder
.
setIfCode
(
ifCode
);
}
//预先校验
String
errMsg
=
paymentService
.
preCheck
(
bizRQ
,
payOrder
);
if
(
StringUtils
.
isNotEmpty
(
errMsg
)){
throw
new
BizException
(
errMsg
);
}
if
(
isNewOrder
){
//订单入库 订单状态: 生成状态 此时没有和任何上游渠道产生交互。
payOrderService
.
save
(
payOrder
);
}
//调起上游支付接口
bizRS
=
(
UnifiedOrderRS
)
paymentService
.
pay
(
bizRQ
,
payOrder
,
mchConfigContext
);
//处理上游返回数据
this
.
processChannelMsg
(
bizRS
.
getChannelRetMsg
(),
payOrder
);
return
packageApiResByPayOrder
(
bizRQ
,
bizRS
,
payOrder
);
}
catch
(
BizException
e
)
{
return
ApiRes
.
customFail
(
e
.
getMessage
());
}
catch
(
ChannelException
e
)
{
//处理上游返回数据
this
.
processChannelMsg
(
e
.
getChannelRetMsg
(),
payOrder
);
if
(
e
.
getChannelRetMsg
().
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
SYS_ERROR
){
return
ApiRes
.
customFail
(
e
.
getMessage
());
}
return
this
.
packageApiResByPayOrder
(
bizRQ
,
bizRS
,
payOrder
);
}
catch
(
Exception
e
)
{
log
.
error
(
"系统异常:{}"
,
e
);
return
ApiRes
.
customFail
(
"系统异常"
);
}
}
private
PayOrder
genPayOrder
(
UnifiedOrderRQ
rq
,
MchInfo
mchInfo
,
String
ifCode
){
PayOrder
payOrder
=
new
PayOrder
();
payOrder
.
setPayOrderId
(
SeqKit
.
genPayOrderId
());
//生成订单ID
payOrder
.
setMchNo
(
mchInfo
.
getMchNo
());
//商户号
payOrder
.
setIsvNo
(
mchInfo
.
getIsvNo
());
//服务商号
payOrder
.
setMchName
(
mchInfo
.
getMchShortName
());
//商户名称(简称)
payOrder
.
setMchType
(
mchInfo
.
getType
());
//商户类型
payOrder
.
setMchOrderNo
(
rq
.
getMchOrderNo
());
//商户订单号
payOrder
.
setIfCode
(
ifCode
);
//接口代码
payOrder
.
setWayCode
(
rq
.
getWayCode
());
//支付方式
payOrder
.
setAmount
(
rq
.
getAmount
());
//订单金额
payOrder
.
setCurrency
(
rq
.
getCurrency
());
//币种
payOrder
.
setState
(
PayOrder
.
STATE_INIT
);
//订单状态, 默认订单生成状态
payOrder
.
setClientIp
(
StringUtils
.
defaultIfEmpty
(
rq
.
getClientIp
(),
getClientIp
()));
//客户端IP
payOrder
.
setSubject
(
rq
.
getSubject
());
//商品标题
payOrder
.
setBody
(
rq
.
getBody
());
//商品描述信息
// payOrder.setChannelExtra(rq.getChannelExtra()); //特殊渠道发起的附件额外参数, 是否应该删除该字段了?? 比如authCode不应该记录, 只是在传输阶段存在的吧? 之前的为了在payOrder对象需要传参。
payOrder
.
setChannelUser
(
rq
.
getChannelUser
());
//渠道用户标志
payOrder
.
setDivisionFlag
(
CS
.
NO
);
//分账标志, 默认为: 0-否
payOrder
.
setExtParam
(
rq
.
getExtParam
());
//商户扩展参数
payOrder
.
setNotifyUrl
(
rq
.
getNotifyUrl
());
//异步通知地址
payOrder
.
setReturnUrl
(
rq
.
getReturnUrl
());
//页面跳转地址
Date
nowDate
=
new
Date
();
payOrder
.
setExpiredTime
(
DateUtil
.
offsetHour
(
nowDate
,
2
));
//订单过期时间 默认两个小时
payOrder
.
setCreatedAt
(
nowDate
);
//订单创建时间
return
payOrder
;
}
/**
* 校验: 商户的支付方式是否可用
* 返回: 支付接口
* **/
private
IPaymentService
checkMchWayCodeAndGetService
(
MchConfigContext
mchConfigContext
,
String
wayCode
){
// 根据支付方式, 查询出 该商户 可用的支付接口
MchPayPassage
mchPayPassage
=
mchPayPassageService
.
findMchPayPassage
(
mchConfigContext
.
getMchNo
(),
wayCode
);
if
(
mchPayPassage
==
null
){
throw
new
BizException
(
"该支付方式商户未开通"
);
}
// 接口代码
String
ifCode
=
mchPayPassage
.
getIfCode
();
IPaymentService
paymentService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"PaymentService"
,
IPaymentService
.
class
);
if
(
paymentService
==
null
){
throw
new
BizException
(
"无此支付通道接口"
);
}
if
(!
paymentService
.
isSupport
(
ifCode
)){
throw
new
BizException
(
"接口不支持该支付方式"
);
}
if
(
mchConfigContext
.
getMchType
()
==
MchInfo
.
TYPE_NORMAL
){
//普通商户
if
(
mchConfigContext
==
null
||
mchConfigContext
.
getNormalMchParamsByIfCode
(
ifCode
)
==
null
){
throw
new
BizException
(
"商户参数未配置"
);
}
}
else
if
(
mchConfigContext
.
getMchType
()
==
MchInfo
.
TYPE_ISVSUB
){
//特约商户
mchConfigContext
=
configContextService
.
getMchConfigContext
(
mchConfigContext
.
getMchNo
());
if
(
mchConfigContext
==
null
||
mchConfigContext
.
getIsvsubMchParamsByIfCode
(
ifCode
)
==
null
){
throw
new
BizException
(
"特约商户参数未配置"
);
}
IsvConfigContext
isvConfigContext
=
configContextService
.
getIsvConfigContext
(
mchConfigContext
.
getMchInfo
().
getIsvNo
());
if
(
isvConfigContext
==
null
||
isvConfigContext
.
getIsvParamsByIfCode
(
ifCode
)
==
null
){
throw
new
BizException
(
"服务商参数未配置"
);
}
}
return
paymentService
;
}
/** 处理返回的渠道信息,并更新订单状态
* payOrder将对部分信息进行 赋值操作。
* **/
private
void
processChannelMsg
(
ChannelRetMsg
channelRetMsg
,
PayOrder
payOrder
){
//对象为空 || 上游返回状态为空, 则无需操作
if
(
channelRetMsg
==
null
||
channelRetMsg
.
getChannelState
()
==
null
){
return
;
}
String
payOrderId
=
payOrder
.
getPayOrderId
();
//明确成功
if
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
==
channelRetMsg
.
getChannelState
())
{
this
.
updateInitOrderStateThrowException
(
PayOrder
.
STATE_SUCCESS
,
payOrder
,
channelRetMsg
);
payMchNotifyService
.
payOrderNotify
(
payOrder
);
//明确失败
}
else
if
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
==
channelRetMsg
.
getChannelState
())
{
this
.
updateInitOrderStateThrowException
(
PayOrder
.
STATE_FAIL
,
payOrder
,
channelRetMsg
);
// 上游处理中 || 未知 || 上游接口返回异常 订单为支付中状态
}
else
if
(
ChannelRetMsg
.
ChannelState
.
WAITING
==
channelRetMsg
.
getChannelState
()
||
ChannelRetMsg
.
ChannelState
.
UNKNOWN
==
channelRetMsg
.
getChannelState
()
||
ChannelRetMsg
.
ChannelState
.
API_RET_ERROR
==
channelRetMsg
.
getChannelState
()
){
this
.
updateInitOrderStateThrowException
(
PayOrder
.
STATE_ING
,
payOrder
,
channelRetMsg
);
// 系统异常: 订单不再处理。 为: 生成状态
}
else
if
(
ChannelRetMsg
.
ChannelState
.
SYS_ERROR
==
channelRetMsg
.
getChannelState
()){
}
else
{
throw
new
BizException
(
"ChannelState 返回异常!"
);
}
//判断是否需要轮询查单
if
(
channelRetMsg
.
isNeedQuery
()){
mqChannelOrderQueryQueue
.
send
(
MqQueue4ChannelOrderQuery
.
buildMsg
(
payOrderId
,
1
),
5
*
1000
);
}
}
/** 更新订单状态 --》 订单生成--》 其他状态 (向外抛出异常) **/
private
void
updateInitOrderStateThrowException
(
byte
orderState
,
PayOrder
payOrder
,
ChannelRetMsg
channelRetMsg
){
payOrder
.
setState
(
orderState
);
payOrder
.
setChannelOrderNo
(
channelRetMsg
.
getChannelOrderId
());
payOrder
.
setErrCode
(
channelRetMsg
.
getChannelErrCode
());
payOrder
.
setErrMsg
(
channelRetMsg
.
getChannelErrMsg
());
boolean
isSuccess
=
payOrderService
.
updateInit2Ing
(
payOrder
.
getPayOrderId
(),
payOrder
.
getIfCode
(),
payOrder
.
getWayCode
());
if
(!
isSuccess
){
throw
new
BizException
(
"更新订单异常!"
);
}
isSuccess
=
payOrderService
.
updateIng2SuccessOrFail
(
payOrder
.
getPayOrderId
(),
payOrder
.
getState
(),
channelRetMsg
.
getChannelOrderId
(),
channelRetMsg
.
getChannelErrCode
(),
channelRetMsg
.
getChannelErrMsg
());
if
(!
isSuccess
){
throw
new
BizException
(
"更新订单异常!"
);
}
}
/** 统一封装订单数据 **/
private
ApiRes
packageApiResByPayOrder
(
UnifiedOrderRQ
bizRQ
,
UnifiedOrderRS
bizRS
,
PayOrder
payOrder
){
// 返回接口数据
bizRS
.
setPayOrderId
(
payOrder
.
getPayOrderId
());
bizRS
.
setOrderState
(
payOrder
.
getState
());
bizRS
.
setMchOrderNo
(
payOrder
.
getMchOrderNo
());
if
(
payOrder
.
getState
()
==
PayOrder
.
STATE_FAIL
){
bizRS
.
setErrCode
(
bizRS
.
getChannelRetMsg
()
!=
null
?
bizRS
.
getChannelRetMsg
().
getChannelErrCode
()
:
null
);
bizRS
.
setErrMsg
(
bizRS
.
getChannelRetMsg
()
!=
null
?
bizRS
.
getChannelRetMsg
().
getChannelErrMsg
()
:
null
);
}
return
ApiRes
.
okWithSign
(
bizRS
,
configContextService
.
getMchConfigContext
(
bizRQ
.
getMchNo
()).
getMchInfo
().
getPrivateKey
());
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/ChannelNoticeController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder
;
import
com.jeequan.jeepay.core.ctrls.AbstractCtrl
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
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.IChannelNoticeService
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.pay.service.PayMchNotifyService
;
import
com.jeequan.jeepay.service.impl.PayOrderService
;
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 【分为同步跳转(doReturn)和异步回调(doNotify) 】
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:26
*/
@Slf4j
@Controller
public
class
ChannelNoticeController
extends
AbstractCtrl
{
@Autowired
private
PayOrderService
payOrderService
;
@Autowired
private
ConfigContextService
configContextService
;
@Autowired
private
PayMchNotifyService
payMchNotifyService
;
/** 同步通知入口 **/
@RequestMapping
(
value
=
{
"/api/pay/return/{ifCode}"
,
"/api/pay/return/{ifCode}/{payOrderId}"
})
public
String
doReturn
(
HttpServletRequest
request
,
@PathVariable
(
"ifCode"
)
String
ifCode
,
@PathVariable
(
value
=
"payOrderId"
,
required
=
false
)
String
urlOrderId
){
String
payOrderId
=
null
;
String
logPrefix
=
"进入["
+
ifCode
+
"]支付同步跳转:urlOrderId:["
+
StringUtils
.
defaultIfEmpty
(
urlOrderId
,
""
)
+
"] "
;
log
.
info
(
"===== {} ====="
,
logPrefix
);
try
{
// 参数有误
if
(
StringUtils
.
isEmpty
(
ifCode
)){
return
this
.
toReturnPage
(
"ifCode is empty"
);
}
//查询支付接口是否存在
IChannelNoticeService
payNotifyService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"ChannelNoticeService"
,
IChannelNoticeService
.
class
);
// 支付通道接口实现不存在
if
(
payNotifyService
==
null
){
log
.
error
(
"{}, interface not exists "
,
logPrefix
);
return
this
.
toReturnPage
(
"["
+
ifCode
+
"] interface not exists"
);
}
// 解析订单号 和 请求参数
MutablePair
<
String
,
Object
>
mutablePair
=
payNotifyService
.
parseParams
(
request
,
urlOrderId
,
IChannelNoticeService
.
NoticeTypeEnum
.
DO_NOTIFY
);
if
(
mutablePair
==
null
){
// 解析数据失败, 响应已处理
log
.
error
(
"{}, mutablePair is null "
,
logPrefix
);
throw
new
BizException
(
"解析数据异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
//解析到订单号
payOrderId
=
mutablePair
.
left
;
log
.
info
(
"{}, 解析数据为:payOrderId:{}, params:{}"
,
logPrefix
,
payOrderId
,
mutablePair
.
getRight
());
if
(
StringUtils
.
isNotEmpty
(
urlOrderId
)
&&
!
urlOrderId
.
equals
(
payOrderId
)){
log
.
error
(
"{}, 订单号不匹配. urlOrderId={}, payOrderId={} "
,
logPrefix
,
urlOrderId
,
payOrderId
);
throw
new
BizException
(
"订单号不匹配!"
);
}
//获取订单号 和 订单数据
PayOrder
payOrder
=
payOrderService
.
getById
(
payOrderId
);
// 订单不存在
if
(
payOrder
==
null
){
log
.
error
(
"{}, 订单不存在. payOrderId={} "
,
logPrefix
,
payOrderId
);
return
this
.
toReturnPage
(
"支付订单不存在"
);
}
//查询出商户的配置信息
String
mchNo
=
payOrder
.
getMchNo
();
//查询出商户配置参数
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
mchNo
);
//调起接口的回调判断
ChannelRetMsg
notifyResult
=
payNotifyService
.
doNotice
(
request
,
mutablePair
.
getRight
(),
payOrder
,
mchConfigContext
,
IChannelNoticeService
.
NoticeTypeEnum
.
DO_RETURN
);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if
(
notifyResult
==
null
||
notifyResult
.
getChannelState
()
==
null
||
notifyResult
.
getResponseEntity
()
==
null
){
log
.
error
(
"{}, 处理回调事件异常 notifyResult data error, notifyResult ={} "
,
logPrefix
,
notifyResult
);
throw
new
BizException
(
"处理回调事件异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
//判断订单状态
if
(
notifyResult
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
)
{
payOrder
.
setState
(
PayOrder
.
STATE_SUCCESS
);
}
else
if
(
notifyResult
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
)
{
payOrder
.
setState
(
PayOrder
.
STATE_FAIL
);
}
boolean
hasReturnUrl
=
StringUtils
.
isNotBlank
(
payOrder
.
getReturnUrl
());
log
.
info
(
"===== {}, 订单通知完成。 payOrderId={}, parseState = {}, hasReturnUrl={} ====="
,
logPrefix
,
payOrderId
,
notifyResult
.
getChannelState
(),
hasReturnUrl
);
//包含通知地址时
if
(
hasReturnUrl
){
// 重定向
response
.
sendRedirect
(
payMchNotifyService
.
createReturnUrl
(
payOrder
,
mchConfigContext
.
getMchInfo
().
getPrivateKey
()));
return
null
;
}
else
{
//跳转到支付成功页面
return
this
.
toReturnPage
(
null
);
}
}
catch
(
BizException
e
)
{
log
.
error
(
"{}, payOrderId={}, BizException"
,
logPrefix
,
payOrderId
,
e
);
return
this
.
toReturnPage
(
e
.
getMessage
());
}
catch
(
ResponseException
e
)
{
log
.
error
(
"{}, payOrderId={}, ResponseException"
,
logPrefix
,
payOrderId
,
e
);
return
this
.
toReturnPage
(
e
.
getMessage
());
}
catch
(
Exception
e
)
{
log
.
error
(
"{}, payOrderId={}, 系统异常"
,
logPrefix
,
payOrderId
,
e
);
return
this
.
toReturnPage
(
e
.
getMessage
());
}
}
/** 异步回调入口 **/
@ResponseBody
@RequestMapping
(
value
=
{
"/api/pay/notify/{ifCode}"
,
"/api/pay/notify/{ifCode}/{payOrderId}"
})
public
ResponseEntity
doNotify
(
HttpServletRequest
request
,
@PathVariable
(
"ifCode"
)
String
ifCode
,
@PathVariable
(
value
=
"payOrderId"
,
required
=
false
)
String
urlOrderId
){
String
payOrderId
=
null
;
String
logPrefix
=
"进入["
+
ifCode
+
"]支付回调:urlOrderId:["
+
StringUtils
.
defaultIfEmpty
(
urlOrderId
,
""
)
+
"] "
;
log
.
info
(
"===== {} ====="
,
logPrefix
);
try
{
// 参数有误
if
(
StringUtils
.
isEmpty
(
ifCode
)){
return
ResponseEntity
.
badRequest
().
body
(
"ifCode is empty"
);
}
//查询支付接口是否存在
IChannelNoticeService
payNotifyService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"ChannelNoticeService"
,
IChannelNoticeService
.
class
);
// 支付通道接口实现不存在
if
(
payNotifyService
==
null
){
log
.
error
(
"{}, interface not exists "
,
logPrefix
);
return
ResponseEntity
.
badRequest
().
body
(
"["
+
ifCode
+
"] interface not exists"
);
}
// 解析订单号 和 请求参数
MutablePair
<
String
,
Object
>
mutablePair
=
payNotifyService
.
parseParams
(
request
,
urlOrderId
,
IChannelNoticeService
.
NoticeTypeEnum
.
DO_NOTIFY
);
if
(
mutablePair
==
null
){
// 解析数据失败, 响应已处理
log
.
error
(
"{}, mutablePair is null "
,
logPrefix
);
throw
new
BizException
(
"解析数据异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
//解析到订单号
payOrderId
=
mutablePair
.
left
;
log
.
info
(
"{}, 解析数据为:payOrderId:{}, params:{}"
,
logPrefix
,
payOrderId
,
mutablePair
.
getRight
());
if
(
StringUtils
.
isNotEmpty
(
urlOrderId
)
&&
!
urlOrderId
.
equals
(
payOrderId
)){
log
.
error
(
"{}, 订单号不匹配. urlOrderId={}, payOrderId={} "
,
logPrefix
,
urlOrderId
,
payOrderId
);
throw
new
BizException
(
"订单号不匹配!"
);
}
//获取订单号 和 订单数据
PayOrder
payOrder
=
payOrderService
.
getById
(
payOrderId
);
// 订单不存在
if
(
payOrder
==
null
){
log
.
error
(
"{}, 订单不存在. payOrderId={} "
,
logPrefix
,
payOrderId
);
return
payNotifyService
.
doNotifyOrderNotExists
(
request
);
}
//查询出商户的配置信息
String
mchNo
=
payOrder
.
getMchNo
();
//查询出商户配置参数
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
mchNo
);
//调起接口的回调判断
ChannelRetMsg
notifyResult
=
payNotifyService
.
doNotice
(
request
,
mutablePair
.
getRight
(),
payOrder
,
mchConfigContext
,
IChannelNoticeService
.
NoticeTypeEnum
.
DO_NOTIFY
);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if
(
notifyResult
==
null
||
notifyResult
.
getChannelState
()
==
null
||
notifyResult
.
getResponseEntity
()
==
null
){
log
.
error
(
"{}, 处理回调事件异常 notifyResult data error, notifyResult ={} "
,
logPrefix
,
notifyResult
);
throw
new
BizException
(
"处理回调事件异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
boolean
updateOrderSuccess
=
true
;
//默认更新成功
// 订单是 【支付中状态】
if
(
payOrder
.
getState
()
==
PayOrder
.
STATE_ING
)
{
//明确成功
if
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
==
notifyResult
.
getChannelState
())
{
updateOrderSuccess
=
payOrderService
.
updateIng2Success
(
payOrderId
,
notifyResult
.
getChannelOrderId
(),
notifyResult
.
getChannelUserId
());
//明确失败
}
else
if
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
==
notifyResult
.
getChannelState
())
{
updateOrderSuccess
=
payOrderService
.
updateIng2Fail
(
payOrderId
,
notifyResult
.
getChannelOrderId
(),
notifyResult
.
getChannelErrCode
(),
notifyResult
.
getChannelErrMsg
());
}
}
// 更新订单 异常
if
(!
updateOrderSuccess
){
log
.
error
(
"{}, updateOrderSuccess = {} "
,
logPrefix
,
updateOrderSuccess
);
return
payNotifyService
.
doNotifyOrderStateUpdateFail
(
request
);
}
//订单支付成功 需要MQ通知下游商户
if
(
notifyResult
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
){
payOrder
.
setState
(
PayOrder
.
STATE_SUCCESS
);
payMchNotifyService
.
payOrderNotify
(
payOrder
);
}
log
.
info
(
"===== {}, 订单通知完成。 payOrderId={}, parseState = {} ====="
,
logPrefix
,
payOrderId
,
notifyResult
.
getChannelState
());
return
notifyResult
.
getResponseEntity
();
}
catch
(
BizException
e
)
{
log
.
error
(
"{}, payOrderId={}, BizException"
,
logPrefix
,
payOrderId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
catch
(
ResponseException
e
)
{
log
.
error
(
"{}, payOrderId={}, ResponseException"
,
logPrefix
,
payOrderId
,
e
);
return
e
.
getResponseEntity
();
}
catch
(
Exception
e
)
{
log
.
error
(
"{}, payOrderId={}, 系统异常"
,
logPrefix
,
payOrderId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
}
/* 跳转到支付成功页面 **/
private
String
toReturnPage
(
String
errInfo
){
return
"cashier/returnPage"
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/QueryOrderController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.pay.rqrs.QueryPayOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.QueryPayOrderRS
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.service.impl.PayOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 商户查单controller
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:26
*/
@Slf4j
@RestController
public
class
QueryOrderController
extends
AbstractPayOrderController
{
@Autowired
private
PayOrderService
payOrderService
;
@Autowired
private
ConfigContextService
configContextService
;
/**
* 查单接口
* **/
@RequestMapping
(
"/api/pay/query"
)
public
ApiRes
queryOrder
(){
//获取参数 & 验签
QueryPayOrderRQ
rq
=
getRQByWithMchSign
(
QueryPayOrderRQ
.
class
);
if
(
StringUtils
.
isAllEmpty
(
rq
.
getMchOrderNo
(),
rq
.
getPayOrderId
())){
throw
new
BizException
(
"mchOrderNo 和 payOrderId不能同时为空"
);
}
PayOrder
payOrder
=
payOrderService
.
queryMchOrder
(
rq
.
getMchNo
(),
rq
.
getPayOrderId
(),
rq
.
getMchOrderNo
());
if
(
payOrder
==
null
){
throw
new
BizException
(
"订单不存在"
);
}
QueryPayOrderRS
bizRes
=
QueryPayOrderRS
.
buildByPayOrder
(
payOrder
);
return
ApiRes
.
okWithSign
(
bizRes
,
configContextService
.
getMchConfigContext
(
rq
.
getMchNo
()).
getMchInfo
().
getPrivateKey
());
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/UnifiedOrderController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.PayWay
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.core.utils.JeepayKit
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.AutoBarOrderRQ
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.service.impl.PayWayService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 统一下单 controller
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:27
*/
@Slf4j
@RestController
public
class
UnifiedOrderController
extends
AbstractPayOrderController
{
@Autowired
private
PayWayService
payWayService
;
@Autowired
private
ConfigContextService
configContextService
;
/**
* 统一下单接口
* **/
@PostMapping
(
"/api/pay/unifiedOrder"
)
public
ApiRes
unifiedOrder
(){
//获取参数 & 验签
UnifiedOrderRQ
rq
=
getRQByWithMchSign
(
UnifiedOrderRQ
.
class
);
UnifiedOrderRQ
bizRQ
=
buildBizRQ
(
rq
);
//实现子类的res
ApiRes
apiRes
=
unifiedOrder
(
bizRQ
.
getWayCode
(),
bizRQ
);
if
(
apiRes
.
getData
()
==
null
){
return
apiRes
;
}
UnifiedOrderRS
bizRes
=
(
UnifiedOrderRS
)
apiRes
.
getData
();
//聚合接口,返回的参数
UnifiedOrderRS
res
=
new
UnifiedOrderRS
();
BeanUtils
.
copyProperties
(
bizRes
,
res
);
//只有 订单生成(QR_CASHIER) || 支付中 || 支付成功返回该数据
if
(
bizRes
.
getOrderState
()
!=
null
&&
(
bizRes
.
getOrderState
()
==
PayOrder
.
STATE_INIT
||
bizRes
.
getOrderState
()
==
PayOrder
.
STATE_ING
||
bizRes
.
getOrderState
()
==
PayOrder
.
STATE_SUCCESS
)
){
res
.
setPayDataType
(
bizRes
.
buildPayDataType
());
res
.
setPayData
(
bizRes
.
buildPayData
());
}
return
ApiRes
.
okWithSign
(
res
,
configContextService
.
getMchConfigContext
(
rq
.
getMchNo
()).
getMchInfo
().
getPrivateKey
());
}
private
UnifiedOrderRQ
buildBizRQ
(
UnifiedOrderRQ
rq
){
//支付方式 比如: ali_bar
String
wayCode
=
rq
.
getWayCode
();
//jsapi 收银台聚合支付场景 (不校验是否存在payWayCode)
if
(
CS
.
PAY_WAY_CODE
.
QR_CASHIER
.
equals
(
wayCode
)){
return
rq
.
buildBizRQ
();
}
//如果是自动分类条码
if
(
CS
.
PAY_WAY_CODE
.
AUTO_BAR
.
equals
(
wayCode
)){
AutoBarOrderRQ
bizRQ
=
(
AutoBarOrderRQ
)
rq
.
buildBizRQ
();
wayCode
=
JeepayKit
.
getPayWayCodeByBarCode
(
bizRQ
.
getAuthCode
());
rq
.
setWayCode
(
wayCode
);
}
if
(
payWayService
.
count
(
PayWay
.
gw
().
eq
(
PayWay:
:
getWayCode
,
wayCode
))
<=
0
){
throw
new
BizException
(
"不支持的支付方式"
);
}
//转换为 bizRQ
return
rq
.
buildBizRQ
();
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/payway/AliBarOrderController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder.payway
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.AliBarOrderRQ
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 支付宝 条码支付 controller
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:25
*/
@Slf4j
@RestController
public
class
AliBarOrderController
extends
AbstractPayOrderController
{
/**
* 统一下单接口
* **/
@PostMapping
(
"/api/pay/aliBarOrder"
)
public
ApiRes
aliBarOrder
(){
//获取参数 & 验证
AliBarOrderRQ
bizRQ
=
getRQByWithMchSign
(
AliBarOrderRQ
.
class
);
// 统一下单接口
return
unifiedOrder
(
CS
.
PAY_WAY_CODE
.
ALI_BAR
,
bizRQ
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/payway/AliJsapiOrderController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder.payway
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.AliJsapiOrderRQ
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 支付宝 jspai controller
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:25
*/
@Slf4j
@RestController
public
class
AliJsapiOrderController
extends
AbstractPayOrderController
{
/**
* 统一下单接口
* **/
@PostMapping
(
"/api/pay/aliJsapiOrder"
)
public
ApiRes
aliJsapiOrder
(){
//获取参数 & 验证
AliJsapiOrderRQ
bizRQ
=
getRQByWithMchSign
(
AliJsapiOrderRQ
.
class
);
// 统一下单接口
return
unifiedOrder
(
CS
.
PAY_WAY_CODE
.
ALI_JSAPI
,
bizRQ
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/payway/YsfBarOrderController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder.payway
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfBarOrderRQ
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 云闪付 条码支付 controller
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 17:25
*/
@Slf4j
@RestController
public
class
YsfBarOrderController
extends
AbstractPayOrderController
{
/**
* 统一下单接口
* **/
@PostMapping
(
"/api/pay/ysfBarOrder"
)
public
ApiRes
aliBarOrder
(){
//获取参数 & 验证
YsfBarOrderRQ
bizRQ
=
getRQByWithMchSign
(
YsfBarOrderRQ
.
class
);
// 统一下单接口
return
unifiedOrder
(
CS
.
PAY_WAY_CODE
.
YSF_BAR
,
bizRQ
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/payway/YsfJsapiOrderController.java
0 → 100644
View file @
de3de82d
/*
* 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.payorder.payway
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfJsapiOrderRQ
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 云闪付 jsapi支付 controller
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 17:25
*/
@Slf4j
@RestController
public
class
YsfJsapiOrderController
extends
AbstractPayOrderController
{
/**
* 统一下单接口
* **/
@PostMapping
(
"/api/pay/ysfJsapiOrder"
)
public
ApiRes
aliJsapiOrder
(){
//获取参数 & 验证
YsfJsapiOrderRQ
bizRQ
=
getRQByWithMchSign
(
YsfJsapiOrderRQ
.
class
);
// 统一下单接口
return
unifiedOrder
(
CS
.
PAY_WAY_CODE
.
YSF_JSAPI
,
bizRQ
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/qr/ChannelUserIdController.java
0 → 100644
View file @
de3de82d
/*
* 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.qr
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.utils.JeepayKit
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.pay.channel.IChannelUserService
;
import
com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController
;
import
com.jeequan.jeepay.pay.rqrs.ChannelUserIdRQ
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
com.jeequan.jeepay.service.impl.SysConfigService
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
java.net.URLEncoder
;
/*
* 商户获取渠道用户ID接口
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:27
*/
@RestController
@RequestMapping
(
"/api/channelUserId"
)
public
class
ChannelUserIdController
extends
AbstractPayOrderController
{
@Autowired
private
ConfigContextService
configContextService
;
@Autowired
private
SysConfigService
sysConfigService
;
/** 重定向到微信地址 **/
@RequestMapping
(
"/jump"
)
public
void
jump
()
throws
Exception
{
//获取请求数据
ChannelUserIdRQ
rq
=
getRQByWithMchSign
(
ChannelUserIdRQ
.
class
);
String
ifCode
=
"AUTO"
.
equalsIgnoreCase
(
rq
.
getIfCode
())
?
getIfCodeByUA
()
:
rq
.
getIfCode
();
// 获取接口
IChannelUserService
channelUserService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"ChannelUserService"
,
IChannelUserService
.
class
);
if
(
channelUserService
==
null
){
throw
new
BizException
(
"不支持的客户端"
);
}
JSONObject
jsonObject
=
new
JSONObject
();
jsonObject
.
put
(
"mchNo"
,
rq
.
getMchNo
());
jsonObject
.
put
(
"ifCode"
,
ifCode
);
jsonObject
.
put
(
"redirectUrl"
,
rq
.
getRedirectUrl
());
//回调地址
String
callbackUrl
=
sysConfigService
.
getDBApplicationConfig
().
genMchChannelUserIdApiOauth2RedirectUrlEncode
(
jsonObject
);
//获取商户配置信息
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
rq
.
getMchNo
());
String
redirectUrl
=
channelUserService
.
buildUserRedirectUrl
(
callbackUrl
,
mchConfigContext
);
response
.
sendRedirect
(
redirectUrl
);
}
/** 回调地址 **/
@RequestMapping
(
"/oauth2Callback/{aesData}"
)
public
void
oauth2Callback
(
@PathVariable
(
"aesData"
)
String
aesData
)
throws
Exception
{
JSONObject
callbackData
=
JSON
.
parseObject
(
JeepayKit
.
aesDecode
(
aesData
));
String
mchNo
=
callbackData
.
getString
(
"mchNo"
);
String
ifCode
=
callbackData
.
getString
(
"ifCode"
);
String
redirectUrl
=
callbackData
.
getString
(
"redirectUrl"
);
// 获取接口
IChannelUserService
channelUserService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"ChannelUserService"
,
IChannelUserService
.
class
);
if
(
channelUserService
==
null
){
throw
new
BizException
(
"不支持的客户端"
);
}
//获取商户配置信息
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
mchNo
);
String
channelUserId
=
channelUserService
.
getChannelUserId
(
getReqParamJSON
(),
mchConfigContext
);
response
.
sendRedirect
(
redirectUrl
+
"?channelId="
+
URLEncoder
.
encode
(
channelUserId
));
}
/** 根据UA获取支付接口 */
private
String
getIfCodeByUA
()
{
String
ua
=
request
.
getHeader
(
"User-Agent"
);
// 无法识别扫码客户端
if
(
StringUtils
.
isBlank
(
ua
))
return
null
;
if
(
ua
.
contains
(
"Alipay"
))
{
return
CS
.
IF_CODE
.
ALIPAY
;
//支付宝服务窗支付
}
else
if
(
ua
.
contains
(
"MicroMessenger"
))
{
return
CS
.
IF_CODE
.
WXPAY
;
}
return
null
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/qr/QrCashierController.java
0 → 100644
View file @
de3de82d
/*
* 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.qr
;
import
com.alipay.api.AlipayApiException
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.utils.JeepayKit
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.pay.channel.IChannelUserService
;
import
com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.AliJsapiOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.payway.WxJsapiOrderRQ
;
import
com.jeequan.jeepay.pay.service.PayMchNotifyService
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.pay.model.MchConfigContext
;
import
com.jeequan.jeepay.service.impl.PayOrderService
;
import
com.jeequan.jeepay.service.impl.SysConfigService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 聚合码支付二维码收银台controller
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:27
*/
@RestController
@RequestMapping
(
"/api/cashier"
)
public
class
QrCashierController
extends
AbstractPayOrderController
{
@Autowired
private
PayOrderService
payOrderService
;
@Autowired
private
ConfigContextService
configContextService
;
@Autowired
private
SysConfigService
sysConfigService
;
@Autowired
private
PayMchNotifyService
payMchNotifyService
;
/**
* 返回 oauth2【获取uerId跳转地址】
* **/
@PostMapping
(
"/redirectUrl"
)
public
ApiRes
redirectUrl
(){
//查询订单
PayOrder
payOrder
=
getPayOrder
();
//回调地址
String
redirectUrlEncode
=
sysConfigService
.
getDBApplicationConfig
().
genOauth2RedirectUrlEncode
(
payOrder
.
getPayOrderId
());
//获取商户配置信息
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
payOrder
.
getMchNo
());
//获取接口并返回数据
IChannelUserService
channelUserService
=
getServiceByWayCode
(
getWayCode
(),
"ChannelUserService"
,
IChannelUserService
.
class
);
return
ApiRes
.
ok
(
channelUserService
.
buildUserRedirectUrl
(
redirectUrlEncode
,
mchConfigContext
));
}
/**
* 获取userId
* **/
@PostMapping
(
"/channelUserId"
)
public
ApiRes
channelUserId
()
throws
Exception
{
//查询订单
PayOrder
payOrder
=
getPayOrder
();
String
wayCode
=
getWayCode
();
//获取商户配置信息
MchConfigContext
mchConfigContext
=
configContextService
.
getMchConfigContext
(
payOrder
.
getMchNo
());
IChannelUserService
channelUserService
=
getServiceByWayCode
(
wayCode
,
"ChannelUserService"
,
IChannelUserService
.
class
);
return
ApiRes
.
ok
(
channelUserService
.
getChannelUserId
(
getReqParamJSON
(),
mchConfigContext
));
}
/**
* 获取订单支付信息
* **/
@PostMapping
(
"/payOrderInfo"
)
public
ApiRes
payOrderInfo
()
throws
Exception
{
//查询订单
PayOrder
payOrder
=
getPayOrder
();
PayOrder
resOrder
=
new
PayOrder
();
resOrder
.
setPayOrderId
(
payOrder
.
getPayOrderId
());
resOrder
.
setMchOrderNo
(
payOrder
.
getMchOrderNo
());
resOrder
.
setMchName
(
payOrder
.
getMchName
());
resOrder
.
setAmount
(
payOrder
.
getAmount
());
resOrder
.
setReturnUrl
(
payMchNotifyService
.
createReturnUrl
(
payOrder
,
configContextService
.
getMchConfigContext
(
payOrder
.
getMchNo
()).
getMchInfo
().
getPrivateKey
()));
return
ApiRes
.
ok
(
resOrder
);
}
/** 调起下单接口, 返回支付数据包 **/
@PostMapping
(
"/pay"
)
public
ApiRes
pay
()
throws
Exception
{
//查询订单
PayOrder
payOrder
=
getPayOrder
();
String
wayCode
=
getWayCode
();
ApiRes
apiRes
=
null
;
if
(
wayCode
.
equals
(
CS
.
PAY_WAY_CODE
.
ALI_JSAPI
)){
apiRes
=
packageAlipayPayPackage
(
payOrder
);
}
else
if
(
wayCode
.
equals
(
CS
.
PAY_WAY_CODE
.
WX_JSAPI
)){
apiRes
=
packageWxpayPayPackage
(
payOrder
);
}
return
ApiRes
.
ok
(
apiRes
);
}
/** 获取支付宝的 支付参数 **/
private
ApiRes
packageAlipayPayPackage
(
PayOrder
payOrder
)
throws
AlipayApiException
{
String
channelUserId
=
getValStringRequired
(
"channelUserId"
);
AliJsapiOrderRQ
rq
=
new
AliJsapiOrderRQ
();
rq
.
setBuyerUserId
(
channelUserId
);
return
this
.
unifiedOrder
(
getWayCode
(),
rq
,
payOrder
);
}
/** 获取微信的 支付参数 **/
private
ApiRes
packageWxpayPayPackage
(
PayOrder
payOrder
)
throws
AlipayApiException
{
String
openId
=
getValStringRequired
(
"channelUserId"
);
WxJsapiOrderRQ
rq
=
new
WxJsapiOrderRQ
();
rq
.
setOpenid
(
openId
);
return
this
.
unifiedOrder
(
getWayCode
(),
rq
,
payOrder
);
}
private
String
getToken
(){
return
getValStringRequired
(
"token"
);
}
private
String
getWayCode
(){
return
getValStringRequired
(
"wayCode"
);
}
private
PayOrder
getPayOrder
(){
String
payOrderId
=
JeepayKit
.
aesDecode
(
getToken
());
//解析token
PayOrder
payOrder
=
payOrderService
.
getById
(
payOrderId
);
if
(
payOrder
==
null
||
payOrder
.
getState
()
!=
PayOrder
.
STATE_INIT
){
throw
new
BizException
(
"订单不存在或状态不正确"
);
}
return
payOrderService
.
getById
(
payOrderId
);
}
private
<
T
>
T
getServiceByWayCode
(
String
wayCode
,
String
serviceSuffix
,
Class
<
T
>
cls
){
if
(
CS
.
PAY_WAY_CODE
.
ALI_JSAPI
.
equals
(
wayCode
)){
return
SpringBeansUtil
.
getBean
(
CS
.
IF_CODE
.
ALIPAY
+
serviceSuffix
,
cls
);
}
else
if
(
CS
.
PAY_WAY_CODE
.
WX_JSAPI
.
equals
(
wayCode
)){
return
SpringBeansUtil
.
getBean
(
CS
.
IF_CODE
.
WXPAY
+
serviceSuffix
,
cls
);
}
return
null
;
}
}
Prev
1
…
7
8
9
10
11
12
13
14
15
…
23
Next
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