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
f608cd83
Commit
f608cd83
authored
May 12, 2023
by
zhuxiao
Browse files
优化微信V3支付
parent
2af0f6ec
Changes
8
Hide whitespace changes
Inline
Side-by-side
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/WxpayPaymentService.java
View file @
f608cd83
...
...
@@ -25,6 +25,7 @@ import com.jeequan.jeepay.core.entity.PayOrder;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams
;
import
com.jeequan.jeepay.pay.channel.AbstractPaymentService
;
import
com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ
;
...
...
@@ -116,53 +117,59 @@ public class WxpayPaymentService extends AbstractPaymentService {
/**
* 构建微信APIV3接口 统一下单请求数据
* @author terrfly
* @param payOrder
* @return
*/
public
JSONObject
buildV3OrderRequest
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
{
public
WxpayV3OrderRequestModel
buildV3OrderRequestModel
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
{
String
payOrderId
=
payOrder
.
getPayOrderId
();
// 微信统一下单请求对象
JSONObject
reqJSON
=
new
JSONObject
();
reqJSON
.
put
(
"out_trade_no"
,
payOrderId
);
reqJSON
.
put
(
"description"
,
payOrder
.
getSubject
());
WxpayV3OrderRequestModel
result
=
new
WxpayV3OrderRequestModel
();
result
.
setOutTradeNo
(
payOrderId
);
result
.
setDescription
(
payOrder
.
getSubject
());
// 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,示例值:2018-06-08T10:34:56+08:00
re
qJSON
.
put
(
"t
ime
_e
xpire
"
,
String
.
format
(
"%sT%s+08:00"
,
DateUtil
.
format
(
payOrder
.
getExpiredTime
(),
DatePattern
.
NORM_DATE_FORMAT
),
DateUtil
.
format
(
payOrder
.
getExpiredTime
(),
DatePattern
.
NORM_TIME_FORMAT
)));
re
sult
.
setT
ime
E
xpire
(
String
.
format
(
"%sT%s+08:00"
,
DateUtil
.
format
(
payOrder
.
getExpiredTime
(),
DatePattern
.
NORM_DATE_FORMAT
),
DateUtil
.
format
(
payOrder
.
getExpiredTime
(),
DatePattern
.
NORM_TIME_FORMAT
)));
re
qJSON
.
put
(
"notify_url"
,
getNotifyUrl
(
payOrderId
));
re
sult
.
setNotifyUrl
(
getNotifyUrl
(
payOrderId
));
JSONObject
amount
=
new
JSONObject
();
amount
.
put
(
"total"
,
payOrder
.
getAmount
().
intValue
());
amount
.
put
(
"currency"
,
"CNY"
);
reqJSON
.
put
(
"amount"
,
amount
);
// 订单金额
result
.
setAmount
(
new
WxpayV3OrderRequestModel
.
Amount
().
setCurrency
(
"CNY"
).
setTotal
(
payOrder
.
getAmount
().
intValue
()));
JSONObject
sceneInfo
=
new
JSONObject
();
sceneInfo
.
put
(
"payer_client_ip"
,
payOrder
.
getClientIp
());
reqJSON
.
put
(
"scene_info"
,
sceneInfo
);
// 场景信息
result
.
setSceneInfo
(
new
WxpayV3OrderRequestModel
.
SceneInfo
().
setPayerClientIp
(
payOrder
.
getClientIp
()));
//订单分账, 将冻结商户资金。
if
(
isDivisionOrder
(
payOrder
)){
JSONObject
settleInfo
=
new
JSONObject
();
settleInfo
.
put
(
"profit_sharing"
,
true
);
reqJSON
.
put
(
"settle_info"
,
settleInfo
);
result
.
setSettleInfo
(
new
WxpayV3OrderRequestModel
.
SettleInfo
().
setProfitSharing
(
true
));
}
WxPayService
wxPayService
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
).
getWxPayService
();
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
WxpayIsvsubMchParams
isvsubMchParams
=
(
WxpayIsvsubMchParams
)
configContextQueryService
.
queryIsvsubMchParams
(
mchAppConfigContext
.
getMchNo
(),
mchAppConfigContext
.
getAppId
(),
getIfCode
());
reqJSON
.
put
(
"sp_appid"
,
wxPayService
.
getConfig
().
getAppId
());
reqJSON
.
put
(
"sp_mchid"
,
wxPayService
.
getConfig
().
getMchId
());
reqJSON
.
put
(
"sub_mchid"
,
isvsubMchParams
.
getSubMchId
());
// 服务商相关参数
result
.
setSpAppid
(
wxPayService
.
getConfig
().
getAppId
());
result
.
setSpMchid
(
wxPayService
.
getConfig
().
getMchId
());
result
.
setSubMchid
(
isvsubMchParams
.
getSubMchId
());
if
(
StringUtils
.
isNotBlank
(
isvsubMchParams
.
getSubMchAppId
()))
{
re
qJSON
.
put
(
"sub_a
ppid
"
,
isvsubMchParams
.
getSubMchAppId
());
re
sult
.
setSubA
ppid
(
isvsubMchParams
.
getSubMchAppId
());
}
}
else
{
// 普通商户
reqJSON
.
put
(
"appid"
,
wxPayService
.
getConfig
().
getAppId
());
reqJSON
.
put
(
"mchid"
,
wxPayService
.
getConfig
().
getMchId
());
result
.
setNormalMchid
(
wxPayService
.
getConfig
().
getMchId
());
result
.
setNormalAppid
(
wxPayService
.
getConfig
().
getAppId
());
}
return
re
qJSON
;
return
re
sult
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/kits/WxpayV3Util.java
View file @
f608cd83
...
...
@@ -24,6 +24,7 @@ import com.github.binarywang.wxpay.exception.WxPayException;
import
com.github.binarywang.wxpay.service.WxPayService
;
import
com.github.binarywang.wxpay.v3.util.PemUtils
;
import
com.github.binarywang.wxpay.v3.util.SignUtils
;
import
com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
...
...
@@ -56,11 +57,6 @@ public class WxpayV3Util {
ISV_URL_MAP
.
put
(
WxPayConstants
.
TradeType
.
MWEB
,
"/v3/pay/partner/transactions/h5"
);
}
public
static
JSONObject
unifiedOrderV3
(
String
reqUrl
,
JSONObject
reqJSON
,
WxPayService
wxPayService
)
throws
WxPayException
{
String
response
=
wxPayService
.
postV3
(
PAY_BASE_URL
+
reqUrl
,
reqJSON
.
toJSONString
());
return
JSONObject
.
parseObject
(
getPayInfo
(
response
,
wxPayService
.
getConfig
()));
}
public
static
JSONObject
queryOrderV3
(
String
url
,
WxPayService
wxPayService
)
throws
WxPayException
{
String
response
=
wxPayService
.
getV3
(
PAY_BASE_URL
+
url
);
return
JSON
.
parseObject
(
response
);
...
...
@@ -90,81 +86,41 @@ public class WxpayV3Util {
}
public
static
String
getPayInfo
(
String
response
,
WxPayConfig
wxPayConfig
)
throws
WxPayException
{
try
{
JSONObject
resJSON
=
JSON
.
parseObject
(
response
);
String
timestamp
=
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000L
);
String
nonceStr
=
SignUtils
.
genRandomStr
();
String
prepayId
=
resJSON
.
getString
(
"prepay_id"
);
switch
(
wxPayConfig
.
getTradeType
())
{
case
WxPayConstants
.
TradeType
.
JSAPI
:
{
Map
<
String
,
String
>
payInfo
=
new
HashMap
<>();
// 如果用JsonObject会出现签名错误
String
appid
=
wxPayConfig
.
getAppId
();
// 用户在服务商appid下的唯一标识
if
(
StringUtils
.
isNotEmpty
(
wxPayConfig
.
getSubAppId
()))
{
appid
=
wxPayConfig
.
getSubAppId
();
// 用户在子商户appid下的唯一标识
}
payInfo
.
put
(
"appId"
,
appid
);
payInfo
.
put
(
"timeStamp"
,
timestamp
);
payInfo
.
put
(
"nonceStr"
,
nonceStr
);
payInfo
.
put
(
"package"
,
"prepay_id="
+
prepayId
);
payInfo
.
put
(
"signType"
,
"RSA"
);
String
beforeSign
=
String
.
format
(
"%s\n%s\n%s\n%s\n"
,
appid
,
timestamp
,
nonceStr
,
"prepay_id="
+
prepayId
);
payInfo
.
put
(
"paySign"
,
SignUtils
.
sign
(
beforeSign
,
PemUtils
.
loadPrivateKey
(
new
FileInputStream
(
wxPayConfig
.
getPrivateKeyPath
()))));
// 签名以后在增加prepayId参数
payInfo
.
put
(
"prepayId"
,
prepayId
);
return
JSON
.
toJSONString
(
payInfo
);
}
case
WxPayConstants
.
TradeType
.
MWEB
:
{
return
response
;
}
case
WxPayConstants
.
TradeType
.
APP
:
{
Map
<
String
,
String
>
payInfo
=
new
HashMap
<>();
// APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数
String
wxAppId
=
wxPayConfig
.
getAppId
();
// 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改
String
partnerId
=
wxPayConfig
.
getMchId
();
if
(
StringUtils
.
isNotEmpty
(
wxPayConfig
.
getSubAppId
()))
{
wxAppId
=
wxPayConfig
.
getSubAppId
();
partnerId
=
wxPayConfig
.
getSubMchId
();
}
String
packageValue
=
"Sign=WXPay"
;
// 此map用于客户端与微信服务器交互
String
beforeSign
=
String
.
format
(
"%s\n%s\n%s\n%s\n"
,
wxAppId
,
timestamp
,
nonceStr
,
prepayId
);
payInfo
.
put
(
"sign"
,
SignUtils
.
sign
(
beforeSign
,
PemUtils
.
loadPrivateKey
(
new
FileInputStream
(
wxPayConfig
.
getPrivateKeyPath
()))));
payInfo
.
put
(
"prepayId"
,
prepayId
);
payInfo
.
put
(
"partnerId"
,
partnerId
);
payInfo
.
put
(
"appId"
,
wxAppId
);
payInfo
.
put
(
"package"
,
packageValue
);
payInfo
.
put
(
"timeStamp"
,
timestamp
);
payInfo
.
put
(
"nonceStr"
,
nonceStr
);
return
JSON
.
toJSONString
(
payInfo
);
}
case
WxPayConstants
.
TradeType
.
NATIVE
:
return
response
;
default
:
return
null
;
}
}
catch
(
Exception
e
)
{
throw
(
e
instanceof
WxPayException
)
?
(
WxPayException
)
e
:
new
WxPayException
(
e
.
getMessage
(),
e
);
/**
* 功能描述:
* 统一调起微信支付请求
* @param model
* @param wxPayService
* @param isIsvsubMch
* @param tradeType
* @param wxCallBack
* @Return: java.lang.String
* @Author: terrfly
* @Date: 2022/4/25 12:38
*/
public
static
String
commonReqWx
(
WxpayV3OrderRequestModel
model
,
WxPayService
wxPayService
,
boolean
isIsvsubMch
,
String
tradeType
,
WxCallBack
wxCallBack
)
throws
WxPayException
{
// 请求地址
String
reqUrl
=
PAY_BASE_URL
+
NORMALMCH_URL_MAP
.
get
(
tradeType
);
if
(
isIsvsubMch
){
// 特约商户
reqUrl
=
PAY_BASE_URL
+
ISV_URL_MAP
.
get
(
tradeType
);
}
}
public
static
JSONObject
processIsvPayer
(
String
subAppId
,
String
openId
)
{
JSONObject
p
ayer
=
new
JSONObject
(
);
// 子商户subAppId不为空
if
(
StringUtils
.
isNotBlank
(
subAppId
))
{
payer
.
put
(
"sub_openid"
,
openId
);
// 用户在子商户appid下的唯一标识
}
else
{
payer
.
put
(
"sp_openid"
,
openId
);
// 用户在服务商appid下的唯一标识
// 调起http请求
String
response
=
wxP
ay
S
er
vice
.
postV3
(
reqUrl
,
JSON
.
toJSONString
(
model
)
);
JSONObject
wxRes
=
JSON
.
parseObject
(
response
);
if
(
wxCallBack
!=
null
)
{
return
wxCallBack
.
genPayInfo
(
wxRes
);
}
return
payer
;
return
response
;
}
public
interface
WxCallBack
{
/** 生成返回数据 */
String
genPayInfo
(
JSONObject
wxRes
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/model/WxpayV3OrderRequestModel.java
0 → 100644
View file @
f608cd83
/*
* 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.wxpay.model
;
import
com.alibaba.fastjson.annotation.JSONField
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
/**
*
* 微信V3支付请求参数类
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/4/25 11:52
*/
@Data
@Accessors
(
chain
=
true
)
public
class
WxpayV3OrderRequestModel
{
/** 服务商应用ID */
@JSONField
(
name
=
"sp_appid"
)
private
String
spAppid
;
/** 服务商户号 */
@JSONField
(
name
=
"sp_mchid"
)
private
String
spMchid
;
/** 子商户号 */
@JSONField
(
name
=
"sub_mchid"
)
private
String
subMchid
;
/** 子商户应用ID */
@JSONField
(
name
=
"sub_appid"
)
private
String
subAppid
;
/** 普通商户: 商户号 */
@JSONField
(
name
=
"mchid"
)
private
String
normalMchid
;
/** 普通商户: appId */
@JSONField
(
name
=
"appid"
)
private
String
normalAppid
;
/** 商户订单号 */
@JSONField
(
name
=
"out_trade_no"
)
private
String
outTradeNo
;
/** 商品描述 */
private
String
description
;
/** 交易结束时间 */
@JSONField
(
name
=
"time_expire"
)
private
String
timeExpire
;
/** 附加数据 */
private
String
attach
;
/** 通知地址 */
@JSONField
(
name
=
"notify_url"
)
private
String
notifyUrl
;
/** 订单优惠标记 */
@JSONField
(
name
=
"goods_tag"
)
private
String
goodsTag
;
/** 结算信息 */
@JSONField
(
name
=
"settle_info"
)
private
SettleInfo
settleInfo
;
/** 订单金额 */
private
Amount
amount
;
/** 支付者 */
private
Payer
payer
;
/** 场景信息 */
@JSONField
(
name
=
"scene_info"
)
private
SceneInfo
sceneInfo
;
/** 场景信息 **/
@Data
@Accessors
(
chain
=
true
)
public
static
class
SceneInfo
{
/** 用户终端IP */
@JSONField
(
name
=
"payer_client_ip"
)
private
String
payerClientIp
;
/** 商户端设备号 */
@JSONField
(
name
=
"device_id"
)
private
String
deviceId
;
/** 商户端设备号 */
@JSONField
(
name
=
"h5_info"
)
private
H5Info
h5Info
;
/** H5场景信息 */
@Data
@Accessors
(
chain
=
true
)
public
static
class
H5Info
{
/** 场景类型 */
@JSONField
(
name
=
"type"
)
private
String
type
;
}
}
/** 结算信息 **/
@Data
@Accessors
(
chain
=
true
)
public
static
class
SettleInfo
{
/** 用户服务标识 */
@JSONField
(
name
=
"profit_sharing"
)
private
Boolean
profitSharing
;
}
/** 支付者 **/
@Data
@Accessors
(
chain
=
true
)
public
static
class
Payer
{
/** 普通商户的: 用户服务标识 */
@JSONField
(
name
=
"openid"
)
private
String
normalOpenId
;
/** 用户服务标识 */
@JSONField
(
name
=
"sp_openid"
)
private
String
spOpenid
;
/** 用户子标识 */
@JSONField
(
name
=
"sub_openid"
)
private
String
subOpenid
;
}
/** 订单金额 **/
@Data
@Accessors
(
chain
=
true
)
public
static
class
Amount
{
/** 总金额 */
private
Integer
total
;
/** 货币类似 */
private
String
currency
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/paywayV3/WxApp.java
View file @
f608cd83
...
...
@@ -15,14 +15,21 @@
*/
package
com.jeequan.jeepay.pay.channel.wxpay.paywayV3
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result
;
import
com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum
;
import
com.github.binarywang.wxpay.constant.WxPayConstants
;
import
com.github.binarywang.wxpay.exception.WxPayException
;
import
com.github.binarywang.wxpay.service.WxPayService
;
import
com.github.binarywang.wxpay.v3.util.PemUtils
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams
;
import
com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util
;
import
com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
...
...
@@ -33,6 +40,10 @@ import com.jeequan.jeepay.pay.util.ApiResBuilder;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
/*
* 微信 app支付
*
...
...
@@ -53,25 +64,9 @@ public class WxApp extends WxpayPaymentService {
WxServiceWrapper
wxServiceWrapper
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
);
WxPayService
wxPayService
=
wxServiceWrapper
.
getWxPayService
();
wxPayService
.
getConfig
().
setTradeType
(
WxPayConstants
.
TradeType
.
APP
);
// 构造请求数据
JSONObject
reqJSON
=
buildV3OrderRequest
(
payOrder
,
mchAppConfigContext
);
// wxPayConfig 添加子商户参数
if
(
mchAppConfigContext
.
isIsvsubMch
()){
wxPayService
.
getConfig
().
setSubMchId
(
reqJSON
.
getString
(
"sub_mchid"
));
if
(
StringUtils
.
isNotBlank
(
reqJSON
.
getString
(
"sub_appid"
)))
{
wxPayService
.
getConfig
().
setSubAppId
(
reqJSON
.
getString
(
"sub_appid"
));
}
}
String
reqUrl
;
// 请求地址
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
reqUrl
=
WxpayV3Util
.
ISV_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
APP
);
}
else
{
reqUrl
=
WxpayV3Util
.
NORMALMCH_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
APP
);
}
WxpayV3OrderRequestModel
wxpayV3OrderRequestModel
=
buildV3OrderRequestModel
(
payOrder
,
mchAppConfigContext
);
// 构造函数响应数据
WxAppOrderRS
res
=
ApiResBuilder
.
buildSuccess
(
WxAppOrderRS
.
class
);
...
...
@@ -79,12 +74,51 @@ public class WxApp extends WxpayPaymentService {
res
.
setChannelRetMsg
(
channelRetMsg
);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try
{
JSONObject
resJSON
=
WxpayV3Util
.
unifiedOrderV3
(
reqUrl
,
reqJSON
,
wxPayService
);
String
payInfo
=
WxpayV3Util
.
commonReqWx
(
wxpayV3OrderRequestModel
,
wxPayService
,
mchAppConfigContext
.
isIsvsubMch
(),
WxPayConstants
.
TradeType
.
APP
,
(
JSONObject
wxRes
)
->
{
// 普通商户,App支付与公众号支付 同一个应用只能配置其中一个
String
resultAppId
=
wxpayV3OrderRequestModel
.
getNormalAppid
();
String
resultMchId
=
wxpayV3OrderRequestModel
.
getNormalMchid
();
// 特约商户,App支付与公众号支付 同一个应用只能配置其中一个
if
(
mchAppConfigContext
.
isIsvsubMch
()){
resultAppId
=
wxpayV3OrderRequestModel
.
getSubAppid
();
resultMchId
=
wxpayV3OrderRequestModel
.
getSubMchid
();
}
WxPayUnifiedOrderV3Result
wxPayUnifiedOrderV3Result
=
new
WxPayUnifiedOrderV3Result
();
wxPayUnifiedOrderV3Result
.
setPrepayId
(
wxRes
.
getString
(
"prepay_id"
));
try
{
FileInputStream
fis
=
new
FileInputStream
(
wxPayService
.
getConfig
().
getPrivateKeyPath
());
WxPayUnifiedOrderV3Result
.
AppResult
appResult
=
wxPayUnifiedOrderV3Result
.
getPayInfo
(
TradeTypeEnum
.
APP
,
resultAppId
,
resultMchId
,
PemUtils
.
loadPrivateKey
(
fis
));
JSONObject
jsonRes
=
(
JSONObject
)
JSON
.
toJSON
(
appResult
);
jsonRes
.
put
(
"package"
,
jsonRes
.
getString
(
"packageValue"
));
jsonRes
.
remove
(
"packageValue"
);
try
{
fis
.
close
();
}
catch
(
IOException
e
)
{
}
return
JSON
.
toJSONString
(
jsonRes
);
}
catch
(
FileNotFoundException
e
)
{
return
null
;
}
}
);
res
.
setPay
Info
(
resJSON
.
toJSONString
()
);
res
.
setPay
Data
(
payInfo
);
// 支付中
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/paywayV3/WxH5.java
View file @
f608cd83
...
...
@@ -26,6 +26,7 @@ import com.jeequan.jeepay.core.entity.PayOrder;
import
com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util
;
import
com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
...
...
@@ -58,25 +59,12 @@ public class WxH5 extends WxpayPaymentService {
WxServiceWrapper
wxServiceWrapper
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
);
WxPayService
wxPayService
=
wxServiceWrapper
.
getWxPayService
();
wxPayService
.
getConfig
().
setTradeType
(
WxPayConstants
.
TradeType
.
MWEB
);
// 构造请求数据
JSONObject
reqJSON
=
buildV3OrderRequest
(
payOrder
,
mchAppConfigContext
);
WxpayV3OrderRequestModel
wxpayV3OrderRequestModel
=
buildV3OrderRequest
Model
(
payOrder
,
mchAppConfigContext
);
JSONObject
sceneInfo
=
reqJSON
.
getJSONObject
(
"scene_info"
);
JSONObject
h5Info
=
new
JSONObject
();
h5Info
.
put
(
"type"
,
"iOS, Android, Wap"
);
sceneInfo
.
put
(
"h5_info"
,
h5Info
);
reqJSON
.
put
(
"scene_info"
,
sceneInfo
);
String
reqUrl
;
// 请求地址
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
reqUrl
=
WxpayV3Util
.
ISV_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
MWEB
);
}
else
{
reqUrl
=
WxpayV3Util
.
NORMALMCH_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
MWEB
);
}
// 场景信息
wxpayV3OrderRequestModel
.
getSceneInfo
().
setH5Info
(
new
WxpayV3OrderRequestModel
.
SceneInfo
.
H5Info
().
setType
(
"iOS, Android, Wap"
));
// 构造函数响应数据
WxH5OrderRS
res
=
ApiResBuilder
.
buildSuccess
(
WxH5OrderRS
.
class
);
...
...
@@ -84,10 +72,10 @@ public class WxH5 extends WxpayPaymentService {
res
.
setChannelRetMsg
(
channelRetMsg
);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try
{
JSONObject
resJSON
=
WxpayV3Util
.
unifiedOrderV3
(
reqUrl
,
reqJSON
,
wxPayService
);
String
payInfo
=
WxpayV3Util
.
commonReqWx
(
wxpayV3OrderRequestModel
,
wxPayService
,
mchAppConfigContext
.
isIsvsubMch
(),
WxPayConstants
.
TradeType
.
MWEB
,
null
);
JSONObject
resJSON
=
JSONObject
.
parseObject
(
payInfo
);
// 拼接returnUrl
String
payUrl
=
String
.
format
(
"%s&redirect_url=%s"
,
resJSON
.
getString
(
"h5_url"
),
URLEncodeUtil
.
encode
(
getReturnUrlOnlyJump
(
payOrder
.
getPayOrderId
())));
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/paywayV3/WxJsapi.java
View file @
f608cd83
...
...
@@ -15,14 +15,21 @@
*/
package
com.jeequan.jeepay.pay.channel.wxpay.paywayV3
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result
;
import
com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum
;
import
com.github.binarywang.wxpay.constant.WxPayConstants
;
import
com.github.binarywang.wxpay.exception.WxPayException
;
import
com.github.binarywang.wxpay.service.WxPayService
;
import
com.github.binarywang.wxpay.v3.util.PemUtils
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams
;
import
com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util
;
import
com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
...
...
@@ -34,6 +41,10 @@ import com.jeequan.jeepay.pay.util.ApiResBuilder;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
/*
* 微信 jsapi支付
*
...
...
@@ -56,28 +67,24 @@ public class WxJsapi extends WxpayPaymentService {
WxJsapiOrderRQ
bizRQ
=
(
WxJsapiOrderRQ
)
rq
;
WxServiceWrapper
wxServiceWrapper
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
);
WxPayService
wxPayService
=
wxServiceWrapper
.
getWxPayService
();
wxPayService
.
getConfig
().
setTradeType
(
WxPayConstants
.
TradeType
.
JSAPI
);
// 构造请求数据
JSONObject
reqJSON
=
buildV3OrderRequest
(
payOrder
,
mchAppConfigContext
);
WxpayV3OrderRequestModel
wxpayV3OrderRequestModel
=
buildV3OrderRequestModel
(
payOrder
,
mchAppConfigContext
);
// 特约商户
if
(
mchAppConfigContext
.
isIsvsubMch
())
{
// wxPayConfig 添加子商户参数
if
(
mchAppConfigContext
.
isIsvsubMch
()){
wxPayService
.
getConfig
().
setSubMchId
(
reqJSON
.
getString
(
"sub_mchid"
));
if
(
StringUtils
.
isNotBlank
(
reqJSON
.
getString
(
"sub_appid"
)))
{
wxPayService
.
getConfig
().
setSubAppId
(
reqJSON
.
getString
(
"sub_appid"
));
// 子商户subAppId不为空
if
(
StringUtils
.
isNotBlank
(
wxpayV3OrderRequestModel
.
getSubAppid
())){
wxpayV3OrderRequestModel
.
setPayer
(
new
WxpayV3OrderRequestModel
.
Payer
().
setSubOpenid
(
bizRQ
.
getOpenid
()));
}
else
{
// 使用的服务商配置的公众号appId获取
wxpayV3OrderRequestModel
.
setPayer
(
new
WxpayV3OrderRequestModel
.
Payer
().
setSpOpenid
(
bizRQ
.
getOpenid
()));
}
}
String
reqUrl
;
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
reqUrl
=
WxpayV3Util
.
ISV_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
JSAPI
);
reqJSON
.
put
(
"payer"
,
WxpayV3Util
.
processIsvPayer
(
reqJSON
.
getString
(
"sub_appid"
),
bizRQ
.
getOpenid
()));
}
else
{
reqUrl
=
WxpayV3Util
.
NORMALMCH_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
JSAPI
);
JSONObject
payer
=
new
JSONObject
();
payer
.
put
(
"openid"
,
bizRQ
.
getOpenid
());
reqJSON
.
put
(
"payer"
,
payer
);
}
else
{
//普通商户 设置openId即可。
wxpayV3OrderRequestModel
.
setPayer
(
new
WxpayV3OrderRequestModel
.
Payer
().
setNormalOpenId
(
bizRQ
.
getOpenid
()));
}
// 构造函数响应数据
...
...
@@ -89,9 +96,47 @@ public class WxJsapi extends WxpayPaymentService {
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try
{
JSONObject
resJSON
=
WxpayV3Util
.
unifiedOrderV3
(
reqUrl
,
reqJSON
,
wxPayService
);
// 调起接口 modify 20220425 by terrfly : 改为统一调用的方式, 将返回数据包放置在业务层进行处理 。
String
payInfo
=
WxpayV3Util
.
commonReqWx
(
wxpayV3OrderRequestModel
,
wxPayService
,
mchAppConfigContext
.
isIsvsubMch
(),
WxPayConstants
.
TradeType
.
JSAPI
,
(
JSONObject
wxRes
)
->
{
// 普通商户
String
resultAppId
=
wxpayV3OrderRequestModel
.
getNormalAppid
();
// 特约商户
if
(
mchAppConfigContext
.
isIsvsubMch
()){
resultAppId
=
StringUtils
.
defaultIfEmpty
(
wxpayV3OrderRequestModel
.
getSubAppid
(),
wxpayV3OrderRequestModel
.
getSpAppid
());
}
WxPayUnifiedOrderV3Result
wxPayUnifiedOrderV3Result
=
new
WxPayUnifiedOrderV3Result
();
wxPayUnifiedOrderV3Result
.
setPrepayId
(
wxRes
.
getString
(
"prepay_id"
));
try
{
FileInputStream
fis
=
new
FileInputStream
(
wxPayService
.
getConfig
().
getPrivateKeyPath
());
WxPayUnifiedOrderV3Result
.
JsapiResult
jsapiResult
=
wxPayUnifiedOrderV3Result
.
getPayInfo
(
TradeTypeEnum
.
JSAPI
,
resultAppId
,
null
,
PemUtils
.
loadPrivateKey
(
fis
));
JSONObject
jsonRes
=
(
JSONObject
)
JSON
.
toJSON
(
jsapiResult
);
jsonRes
.
put
(
"package"
,
jsonRes
.
getString
(
"packageValue"
));
jsonRes
.
remove
(
"packageValue"
);
try
{
fis
.
close
();
}
catch
(
IOException
e
)
{
}
return
JSON
.
toJSONString
(
jsonRes
);
}
catch
(
FileNotFoundException
e
)
{
return
null
;
}
}
);
res
.
setPayInfo
(
resJSON
.
toJSONString
()
);
res
.
setPayInfo
(
payInfo
);
// 支付中
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/paywayV3/WxLite.java
View file @
f608cd83
...
...
@@ -15,14 +15,21 @@
*/
package
com.jeequan.jeepay.pay.channel.wxpay.paywayV3
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result
;
import
com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum
;
import
com.github.binarywang.wxpay.constant.WxPayConstants
;
import
com.github.binarywang.wxpay.exception.WxPayException
;
import
com.github.binarywang.wxpay.service.WxPayService
;
import
com.github.binarywang.wxpay.v3.util.PemUtils
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams
;
import
com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util
;
import
com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
...
...
@@ -34,6 +41,10 @@ import com.jeequan.jeepay.pay.util.ApiResBuilder;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
/*
* 微信 小程序
*
...
...
@@ -56,29 +67,25 @@ public class WxLite extends WxpayPaymentService {
WxLiteOrderRQ
bizRQ
=
(
WxLiteOrderRQ
)
rq
;
WxServiceWrapper
wxServiceWrapper
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
);
WxPayService
wxPayService
=
wxServiceWrapper
.
getWxPayService
();
wxPayService
.
getConfig
().
setTradeType
(
WxPayConstants
.
TradeType
.
JSAPI
);
// 构造请求数据
JSONObject
reqJSON
=
buildV3OrderRequest
(
payOrder
,
mchAppConfigContext
);
WxpayV3OrderRequestModel
wxpayV3OrderRequestModel
=
buildV3OrderRequestModel
(
payOrder
,
mchAppConfigContext
);
// 特约商户
if
(
mchAppConfigContext
.
isIsvsubMch
())
{
// wxPayConfig 添加子商户参数
if
(
mchAppConfigContext
.
isIsvsubMch
()){
wxPayService
.
getConfig
().
setSubMchId
(
reqJSON
.
getString
(
"sub_mchid"
));
if
(
StringUtils
.
isNotBlank
(
reqJSON
.
getString
(
"sub_appid"
)))
{
wxPayService
.
getConfig
().
setSubAppId
(
reqJSON
.
getString
(
"sub_appid"
));
// 子商户subAppId不为空
if
(
StringUtils
.
isNotBlank
(
wxpayV3OrderRequestModel
.
getSubAppid
()))
{
wxpayV3OrderRequestModel
.
setPayer
(
new
WxpayV3OrderRequestModel
.
Payer
().
setSubOpenid
(
bizRQ
.
getOpenid
()));
// 用户在子商户appid下的唯一标识
}
else
{
wxpayV3OrderRequestModel
.
setPayer
(
new
WxpayV3OrderRequestModel
.
Payer
().
setSpOpenid
(
bizRQ
.
getOpenid
()));
}
}
String
reqUrl
;
// 请求地址
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
reqUrl
=
WxpayV3Util
.
ISV_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
JSAPI
);
reqJSON
.
put
(
"payer"
,
WxpayV3Util
.
processIsvPayer
(
reqJSON
.
getString
(
"sub_appid"
),
bizRQ
.
getOpenid
()));
}
else
{
reqUrl
=
WxpayV3Util
.
NORMALMCH_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
JSAPI
);
}
else
{
// 普通商户
JSONObject
payer
=
new
JSONObject
();
payer
.
put
(
"openid"
,
bizRQ
.
getOpenid
());
reqJSON
.
put
(
"payer"
,
payer
);
//openId
wxpayV3OrderRequestModel
.
setPayer
(
new
WxpayV3OrderRequestModel
.
Payer
().
setNormalOpenId
(
bizRQ
.
getOpenid
()));
}
// 构造函数响应数据
...
...
@@ -87,12 +94,48 @@ public class WxLite extends WxpayPaymentService {
res
.
setChannelRetMsg
(
channelRetMsg
);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try
{
JSONObject
resJSON
=
WxpayV3Util
.
unifiedOrderV3
(
reqUrl
,
reqJSON
,
wxPayService
);
String
payInfo
=
WxpayV3Util
.
commonReqWx
(
wxpayV3OrderRequestModel
,
wxPayService
,
mchAppConfigContext
.
isIsvsubMch
(),
WxPayConstants
.
TradeType
.
JSAPI
,
(
JSONObject
wxRes
)
->
{
// 普通商户
String
resultAppId
=
wxpayV3OrderRequestModel
.
getNormalAppid
();
// 特约商户
if
(
mchAppConfigContext
.
isIsvsubMch
()){
resultAppId
=
StringUtils
.
defaultIfEmpty
(
wxpayV3OrderRequestModel
.
getSubAppid
(),
wxpayV3OrderRequestModel
.
getSpAppid
());
}
// 使用wxjava公共函数,生成
WxPayUnifiedOrderV3Result
wxPayUnifiedOrderV3Result
=
new
WxPayUnifiedOrderV3Result
();
wxPayUnifiedOrderV3Result
.
setPrepayId
(
wxRes
.
getString
(
"prepay_id"
));
try
{
FileInputStream
fis
=
new
FileInputStream
(
wxPayService
.
getConfig
().
getPrivateKeyPath
());
WxPayUnifiedOrderV3Result
.
JsapiResult
jsapiResult
=
wxPayUnifiedOrderV3Result
.
getPayInfo
(
TradeTypeEnum
.
JSAPI
,
resultAppId
,
null
,
PemUtils
.
loadPrivateKey
(
fis
));
JSONObject
jsonRes
=
(
JSONObject
)
JSON
.
toJSON
(
jsapiResult
);
jsonRes
.
put
(
"package"
,
jsonRes
.
getString
(
"packageValue"
));
jsonRes
.
remove
(
"packageValue"
);
try
{
fis
.
close
();
}
catch
(
IOException
e
)
{
}
return
JSON
.
toJSONString
(
jsonRes
);
}
catch
(
FileNotFoundException
e
)
{
return
null
;
}
}
);
res
.
setPayInfo
(
resJSON
.
toJSONString
()
);
res
.
setPayInfo
(
payInfo
);
// 支付中
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/paywayV3/WxNative.java
View file @
f608cd83
...
...
@@ -24,6 +24,7 @@ import com.jeequan.jeepay.core.entity.PayOrder;
import
com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util
;
import
com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
...
...
@@ -59,15 +60,7 @@ public class WxNative extends WxpayPaymentService {
WxPayService
wxPayService
=
wxServiceWrapper
.
getWxPayService
();
// 构造请求数据
JSONObject
reqJSON
=
buildV3OrderRequest
(
payOrder
,
mchAppConfigContext
);
wxPayService
.
getConfig
().
setTradeType
(
WxPayConstants
.
TradeType
.
NATIVE
);
String
reqUrl
;
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
reqUrl
=
WxpayV3Util
.
ISV_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
NATIVE
);
}
else
{
reqUrl
=
WxpayV3Util
.
NORMALMCH_URL_MAP
.
get
(
WxPayConstants
.
TradeType
.
NATIVE
);
}
WxpayV3OrderRequestModel
wxpayV3OrderRequestModel
=
buildV3OrderRequestModel
(
payOrder
,
mchAppConfigContext
);
// 构造函数响应数据
WxNativeOrderRS
res
=
ApiResBuilder
.
buildSuccess
(
WxNativeOrderRS
.
class
);
...
...
@@ -75,10 +68,10 @@ public class WxNative extends WxpayPaymentService {
res
.
setChannelRetMsg
(
channelRetMsg
);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try
{
JSONObject
resJSON
=
WxpayV3Util
.
unifiedOrderV3
(
reqUrl
,
reqJSON
,
wxPayService
);
String
payInfo
=
WxpayV3Util
.
commonReqWx
(
wxpayV3OrderRequestModel
,
wxPayService
,
mchAppConfigContext
.
isIsvsubMch
(),
WxPayConstants
.
TradeType
.
NATIVE
,
null
);
JSONObject
resJSON
=
JSONObject
.
parseObject
(
payInfo
);
String
codeUrl
=
resJSON
.
getString
(
"code_url"
);
if
(
CS
.
PAY_DATA_TYPE
.
CODE_IMG_URL
.
equals
(
bizRQ
.
getPayDataType
())){
//二维码图片地址
...
...
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