Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
gxpt_ht
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
pseer
gxpt_ht
Commits
e712f029
Commit
e712f029
authored
Oct 25, 2023
by
wuwenlong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wechat pay callback dev;
parent
53d83141
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
648 additions
and
6 deletions
+648
-6
CallbackController.java
.../java/share/web/controller/system/CallbackController.java
+55
-0
WeChatConfig.java
...ommon/src/main/java/share/common/config/WeChatConfig.java
+2
-0
Constants.java
...common/src/main/java/share/common/constant/Constants.java
+11
-0
OrderTypeEnum.java
...ommon/src/main/java/share/common/enums/OrderTypeEnum.java
+23
-4
AttachVo.java
...system/src/main/java/share/system/domain/vo/AttachVo.java
+32
-0
CallbackVo.java
...stem/src/main/java/share/system/domain/vo/CallbackVo.java
+100
-0
CallbackService.java
...m/src/main/java/share/system/service/CallbackService.java
+22
-0
ISOrderService.java
...em/src/main/java/share/system/service/ISOrderService.java
+2
-0
CallbackServiceImpl.java
...n/java/share/system/service/impl/CallbackServiceImpl.java
+386
-0
OrderPayServiceImpl.java
...n/java/share/system/service/impl/OrderPayServiceImpl.java
+6
-0
SOrderServiceImpl.java
...ain/java/share/system/service/impl/SOrderServiceImpl.java
+9
-2
No files found.
share-admin/src/main/java/share/web/controller/system/CallbackController.java
0 → 100644
View file @
e712f029
package
com
.
zbkj
.
admin
.
controller
;
import
com.zbkj.service.service.CallbackService
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.servlet.http.HttpServletRequest
;
/**
* 支付回调
*/
@Slf4j
@RestController
@RequestMapping
(
"api/admin/payment/callback"
)
@Api
(
tags
=
"支付回调"
)
public
class
CallbackController
{
@Autowired
private
CallbackService
callbackService
;
/**
* 微信支付回调
*/
@ApiOperation
(
value
=
"微信支付回调"
)
@RequestMapping
(
value
=
"/wechat"
,
method
=
RequestMethod
.
POST
)
public
String
weChat
(
@RequestBody
String
request
)
{
System
.
out
.
println
(
"微信支付回调 request ===> "
+
request
);
String
response
=
callbackService
.
weChat
(
request
);
System
.
out
.
println
(
"微信支付回调 response ===> "
+
response
);
return
response
;
}
/**
* 微信退款回调
*/
@ApiOperation
(
value
=
"微信退款回调"
)
@RequestMapping
(
value
=
"/wechat/refund"
,
method
=
RequestMethod
.
POST
)
public
String
weChatRefund
(
@RequestBody
String
request
)
{
System
.
out
.
println
(
"微信退款回调 request ===> "
+
request
);
String
response
=
callbackService
.
weChatRefund
(
request
);
System
.
out
.
println
(
"微信退款回调 response ===> "
+
response
);
return
response
;
}
}
share-common/src/main/java/share/common/config/WeChatConfig.java
View file @
e712f029
...
@@ -27,6 +27,8 @@ public class WeChatConfig
...
@@ -27,6 +27,8 @@ public class WeChatConfig
private
String
publicAppSecret
;
private
String
publicAppSecret
;
private
String
publicSignKey
;
private
Integer
wechatJsApiDebug
;
private
Integer
wechatJsApiDebug
;
}
}
share-common/src/main/java/share/common/constant/Constants.java
View file @
e712f029
...
@@ -9,6 +9,7 @@ import io.jsonwebtoken.Claims;
...
@@ -9,6 +9,7 @@ import io.jsonwebtoken.Claims;
*/
*/
public
class
Constants
public
class
Constants
{
{
public
static
final
String
CONFIG_KEY_SITE_URL
=
"site_url"
;
//域名
public
static
final
String
CONFIG_KEY_SITE_URL
=
"site_url"
;
//域名
public
static
final
String
CONFIG_KEY_API_URL
=
"api_url"
;
//admin接口地址
public
static
final
String
CONFIG_KEY_API_URL
=
"api_url"
;
//admin接口地址
// 订单取消Key
// 订单取消Key
...
@@ -40,6 +41,16 @@ public class Constants
...
@@ -40,6 +41,16 @@ public class Constants
public
static
final
int
THIRD_LOGIN_TOKEN_TYPE_ANDROID_WX
=
6
;
//android微信
public
static
final
int
THIRD_LOGIN_TOKEN_TYPE_ANDROID_WX
=
6
;
//android微信
public
static
final
int
THIRD_LOGIN_TOKEN_TYPE_IOS
=
7
;
//ios
public
static
final
int
THIRD_LOGIN_TOKEN_TYPE_IOS
=
7
;
//ios
/** 订单支付成功后Task */
public
static
final
String
ORDER_TASK_PAY_SUCCESS_AFTER
=
"orderPaySuccessTask"
;
//订单操作redis队列
public
static
final
String
ORDER_TASK_REDIS_KEY_AFTER_DELETE_BY_USER
=
"alterOrderDeleteByUser"
;
// 用户删除订单后续操作
public
static
final
String
ORDER_TASK_REDIS_KEY_AFTER_COMPLETE_BY_USER
=
"alterOrderCompleteByUser"
;
// 用户完成订单后续操作
public
static
final
String
ORDER_TASK_REDIS_KEY_AFTER_CANCEL_BY_USER
=
"alterOrderCancelByUser"
;
// 用户取消订单后续操作
public
static
final
String
ORDER_TASK_REDIS_KEY_AFTER_REFUND_BY_USER
=
"alterOrderRefundByUser"
;
// 用户订单退款后续操作
public
static
final
int
NUM_ZERO
=
0
;
public
static
final
int
NUM_ZERO
=
0
;
public
static
final
int
NUM_ONE
=
1
;
public
static
final
int
NUM_ONE
=
1
;
public
static
final
int
NUM_TWO
=
2
;
public
static
final
int
NUM_TWO
=
2
;
...
...
share-common/src/main/java/share/common/enums/OrderTypeEnum.java
View file @
e712f029
package
share
.
common
.
enums
;
package
share
.
common
.
enums
;
import
share.common.utils.StringUtils
;
/**
/**
* @Author wwl
* @Author wwl
* @Date 2023/10/20 10:57
* @Date 2023/10/20 10:57
*/
*/
public
enum
OrderTypeEnum
{
public
enum
OrderTypeEnum
{
RESERVER
(
1
,
"预定"
),
RESERVER
(
1
,
"
reserver"
,
"
预定"
),
RENEW
(
2
,
"续费"
),
RENEW
(
2
,
"
renew"
,
"
续费"
),
RECHARGE
(
3
,
"充值"
);
RECHARGE
(
3
,
"
recharge"
,
"
充值"
);
private
Integer
code
;
private
Integer
code
;
private
String
value
;
private
String
name
;
private
String
name
;
OrderTypeEnum
(
Integer
code
,
String
name
)
{
OrderTypeEnum
(
Integer
code
,
String
value
,
String
name
)
{
this
.
code
=
code
;
this
.
code
=
code
;
this
.
value
=
value
;
this
.
name
=
name
;
this
.
name
=
name
;
}
}
...
@@ -26,10 +30,25 @@ public enum OrderTypeEnum {
...
@@ -26,10 +30,25 @@ public enum OrderTypeEnum {
return
null
;
return
null
;
}
}
public
static
OrderTypeEnum
getEnumByValue
(
String
value
){
if
(
StringUtils
.
isNotBlank
(
value
))
{
for
(
OrderTypeEnum
type
:
OrderTypeEnum
.
values
())
{
if
(
type
.
value
.
equals
(
value
))
{
return
type
;
}
}
}
return
null
;
}
public
Integer
getCode
(){
public
Integer
getCode
(){
return
code
;
return
code
;
}
}
public
String
getValue
()
{
return
value
;
}
public
String
getName
()
{
public
String
getName
()
{
return
name
;
return
name
;
}
}
...
...
share-system/src/main/java/share/system/domain/vo/AttachVo.java
0 → 100644
View file @
e712f029
package
share
.
system
.
domain
.
vo
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
lombok.experimental.Accessors
;
/**
* 支付附加对象
*/
@Data
@EqualsAndHashCode
(
callSuper
=
false
)
@Accessors
(
chain
=
true
)
@ApiModel
(
value
=
"AttachVo对象"
,
description
=
"支付附加对象"
)
public
class
AttachVo
{
public
AttachVo
()
{
}
public
AttachVo
(
String
type
,
Long
userId
)
{
this
.
type
=
type
;
this
.
userId
=
userId
;
}
@ApiModelProperty
(
value
=
"业务类型, 订单 = order, 充值 = recharge"
,
required
=
true
)
private
String
type
=
"order"
;
@ApiModelProperty
(
value
=
"用户id"
,
required
=
true
)
private
Long
userId
;
}
share-system/src/main/java/share/system/domain/vo/CallbackVo.java
0 → 100644
View file @
e712f029
package
com
.
zbkj
.
common
.
vo
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
lombok.experimental.Accessors
;
/**
* 微信回调对象
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
@Data
@EqualsAndHashCode
(
callSuper
=
false
)
@Accessors
(
chain
=
true
)
@ApiModel
(
value
=
"CallbackVo对象"
,
description
=
"微信回调"
)
public
class
CallbackVo
{
@ApiModelProperty
(
value
=
"调用接口提交的公众账号ID"
)
@JsonProperty
(
value
=
"appid"
)
private
String
appId
;
@ApiModelProperty
(
value
=
"调用接口提交的商户号"
)
@JsonProperty
(
value
=
"mch_id"
)
private
String
mchId
;
@ApiModelProperty
(
value
=
"调用接口提交的终端设备号"
)
@JsonProperty
(
value
=
"device_info"
)
private
String
deviceInfo
;
@ApiModelProperty
(
value
=
"微信返回的随机字符串"
)
@JsonProperty
(
value
=
"nonce_str"
)
private
String
nonceStr
;
@ApiModelProperty
(
value
=
"微信返回的签名"
)
private
String
sign
;
@ApiModelProperty
(
value
=
"SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断"
)
@JsonProperty
(
value
=
"return_code"
)
private
String
returnCode
;
@ApiModelProperty
(
value
=
"当return_code为FAIL时返回信息为错误原因 ,例如 签名失败 参数格式校验错误"
)
@JsonProperty
(
value
=
"return_msg"
)
private
String
returnMsg
;
@ApiModelProperty
(
value
=
"SUCCESS/FAIL 业务结果"
)
@JsonProperty
(
value
=
"result_code"
)
private
String
resultCode
;
@ApiModelProperty
(
value
=
"详细参见错误列表"
)
@JsonProperty
(
value
=
"err_code"
)
private
String
errCode
;
@ApiModelProperty
(
value
=
"错误返回的信息描述"
)
@JsonProperty
(
value
=
"err_code_des"
)
private
String
errCodeDes
;
@ApiModelProperty
(
value
=
"用户在商户appid下的唯一标识"
)
private
String
openid
;
@ApiModelProperty
(
value
=
"微信支付订单号"
)
@JsonProperty
(
value
=
"transaction_id"
)
private
String
transactionId
;
@ApiModelProperty
(
value
=
"微信支付订单号"
)
@JsonProperty
(
value
=
"out_trade_no"
)
private
String
outTradeNo
;
@ApiModelProperty
(
value
=
"商家数据包,原样返回"
)
private
String
attach
;
@ApiModelProperty
(
value
=
"支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则"
)
@JsonProperty
(
value
=
"time_end"
)
private
String
timeEnd
;
@ApiModelProperty
(
value
=
"用户是否关注公众账号,Y-关注,N-未关注"
)
@JsonProperty
(
value
=
"is_subscribe"
)
private
String
isSubscribe
;
@ApiModelProperty
(
value
=
"银行类型"
)
@JsonProperty
(
value
=
"bank_type"
)
private
String
bankType
;
@ApiModelProperty
(
value
=
"现金支付金额"
)
@JsonProperty
(
value
=
"cash_fee"
)
private
Integer
cashFee
;
@ApiModelProperty
(
value
=
"总代金券金额"
)
@JsonProperty
(
value
=
"coupon_fee"
)
private
Integer
couponFee
;
}
share-system/src/main/java/share/system/service/CallbackService.java
0 → 100644
View file @
e712f029
package
com
.
zbkj
.
service
.
service
;
import
javax.servlet.http.HttpServletRequest
;
/**
* 订单支付回调 service
*/
public
interface
CallbackService
{
/**
* 微信支付回调
* @param xmlInfo 微信回调json
* @return String
*/
String
weChat
(
String
xmlInfo
);
/**
* 微信退款回调
* @param request 微信回调json
* @return String
*/
String
weChatRefund
(
String
request
);
}
share-system/src/main/java/share/system/service/ISOrderService.java
View file @
e712f029
...
@@ -96,4 +96,6 @@ public interface ISOrderService extends IService<SOrder>
...
@@ -96,4 +96,6 @@ public interface ISOrderService extends IService<SOrder>
* @return
* @return
*/
*/
SOrder
getByOrderNo
(
String
orderNo
);
SOrder
getByOrderNo
(
String
orderNo
);
SOrder
getInfoByEntity
(
SOrder
orderParam
);
}
}
share-system/src/main/java/share/system/service/impl/CallbackServiceImpl.java
0 → 100644
View file @
e712f029
package
share
.
system
.
service
.
impl
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.crypto.SecureUtil
;
import
com.alibaba.fastjson.JSONObject
;
import
com.baomidou.dynamic.datasource.annotation.DSTransactional
;
import
com.zbkj.common.vo.AttachVo
;
import
com.zbkj.common.vo.CallbackVo
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.support.TransactionTemplate
;
import
share.common.config.WeChatConfig
;
import
share.common.constant.Constants
;
import
share.common.core.redis.RedisUtil
;
import
share.common.enums.OrderTypeEnum
;
import
share.common.enums.YesNoEnum
;
import
share.common.exception.base.BaseException
;
import
share.common.utils.BaseUtil
;
import
share.common.utils.DateUtils
;
import
share.system.domain.SConsumer
;
import
share.system.domain.SOrder
;
import
share.system.domain.WechatPayInfo
;
import
share.system.domain.vo.MyRecord
;
import
share.system.service.ISOrderService
;
import
share.system.service.ISysConfigService
;
import
share.system.service.SConsumerService
;
import
share.system.service.WechatPayInfoService
;
import
share.system.util.WxPayUtil
;
import
javax.crypto.Cipher
;
import
javax.crypto.spec.SecretKeySpec
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.UnsupportedEncodingException
;
import
java.nio.charset.StandardCharsets
;
import
java.security.Security
;
import
java.util.*
;
/**
* 订单支付回调 CallbackService 实现类
*/
@Service
public
class
CallbackServiceImpl
implements
com
.
zbkj
.
service
.
service
.
CallbackService
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
CallbackServiceImpl
.
class
);
@Autowired
private
ISOrderService
sOrderService
;
@Autowired
private
SConsumerService
sConsumerService
;
@Autowired
private
RedisUtil
redisUtil
;
@Autowired
private
WechatPayInfoService
wechatPayInfoService
;
@Autowired
private
WeChatConfig
weChatConfig
;
/**
* 微信支付回调
*/
@DSTransactional
@Override
public
String
weChat
(
String
xmlInfo
)
{
StringBuffer
sb
=
new
StringBuffer
();
sb
.
append
(
"<xml>"
);
if
(
StrUtil
.
isBlank
(
xmlInfo
)){
sb
.
append
(
"<return_code><![CDATA[FAIL]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[xmlInfo is blank]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
logger
.
error
(
"wechat callback error : "
+
sb
.
toString
());
return
sb
.
toString
();
}
try
{
HashMap
<
String
,
Object
>
map
=
WxPayUtil
.
processResponseXml
(
xmlInfo
);
// 通信是否成功
String
returnCode
=
(
String
)
map
.
get
(
"return_code"
);
if
(!
returnCode
.
equals
(
Constants
.
SUCCESS
))
{
sb
.
append
(
"<return_code><![CDATA[SUCCESS]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[OK]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
logger
.
error
(
"wechat callback error : wx pay return code is fail returnMsg : "
+
map
.
get
(
"return_msg"
));
return
sb
.
toString
();
}
// 交易是否成功
String
resultCode
=
(
String
)
map
.
get
(
"result_code"
);
if
(!
resultCode
.
equals
(
Constants
.
SUCCESS
))
{
sb
.
append
(
"<return_code><![CDATA[SUCCESS]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[OK]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
logger
.
error
(
"wechat callback error : wx pay result code is fail"
);
return
sb
.
toString
();
}
//解析xml
CallbackVo
callbackVo
=
BaseUtil
.
mapToObj
(
map
,
CallbackVo
.
class
);
AttachVo
attachVo
=
JSONObject
.
toJavaObject
(
JSONObject
.
parseObject
(
callbackVo
.
getAttach
()),
AttachVo
.
class
);
//判断openid
SConsumer
sConsumer
=
sConsumerService
.
getById
(
attachVo
.
getUserId
());
if
(
ObjectUtil
.
isNull
(
sConsumer
))
{
//用户信息错误
throw
new
BaseException
(
"用户信息错误!"
);
}
OrderTypeEnum
orderTypeEnum
=
OrderTypeEnum
.
getEnumByValue
(
attachVo
.
getType
());
switch
(
orderTypeEnum
){
case
RESERVER:
case
RENEW:
SOrder
orderParam
=
new
SOrder
();
orderParam
.
setOutTradeNo
(
callbackVo
.
getOutTradeNo
());
orderParam
.
setConsumerId
(
attachVo
.
getUserId
());
SOrder
sOrder
=
sOrderService
.
getInfoByEntity
(
orderParam
);
if
(
ObjectUtil
.
isNull
(
sOrder
))
{
logger
.
error
(
"wechat pay error : 订单信息不存在==》"
+
callbackVo
.
getOutTradeNo
());
throw
new
BaseException
(
"wechat pay error : 订单信息不存在==》"
+
callbackVo
.
getOutTradeNo
());
}
if
(
YesNoEnum
.
yes
.
getIndex
().
equals
(
sOrder
.
getPayStatus
()))
{
logger
.
error
(
"wechat pay error : 订单已处理==》"
+
callbackVo
.
getOutTradeNo
());
sb
.
append
(
"<return_code><![CDATA[SUCCESS]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[OK]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
return
sb
.
toString
();
}
WechatPayInfo
wechatPayInfo
=
wechatPayInfoService
.
getByNo
(
sOrder
.
getOutTradeNo
());
if
(
ObjectUtil
.
isNull
(
wechatPayInfo
))
{
logger
.
error
(
"wechat pay error : 微信订单信息不存在==》"
+
callbackVo
.
getOutTradeNo
());
throw
new
BaseException
(
"wechat pay error : 微信订单信息不存在==》"
+
callbackVo
.
getOutTradeNo
());
}
wechatPayInfo
.
setIsSubscribe
(
callbackVo
.
getIsSubscribe
());
wechatPayInfo
.
setBankType
(
callbackVo
.
getBankType
());
wechatPayInfo
.
setCashFee
(
callbackVo
.
getCashFee
());
wechatPayInfo
.
setCouponFee
(
callbackVo
.
getCouponFee
());
wechatPayInfo
.
setTransactionId
(
callbackVo
.
getTransactionId
());
wechatPayInfo
.
setTimeEnd
(
callbackVo
.
getTimeEnd
());
Boolean
execute
=
Boolean
.
FALSE
;
try
{
sOrder
.
setPayStatus
(
YesNoEnum
.
yes
.
getIndex
());
sOrder
.
setPayTime
(
DateUtils
.
getNowDate
());
sOrderService
.
updateById
(
sOrder
);
wechatPayInfoService
.
updateById
(
wechatPayInfo
);
execute
=
Boolean
.
TRUE
;
}
catch
(
Exception
e
)
{
logger
.
error
(
"微信支付回调出错"
);
logger
.
error
(
e
.
toString
());
}
if
(!
execute
)
{
logger
.
error
(
"wechat pay error : 订单更新失败==》"
+
callbackVo
.
getOutTradeNo
());
sb
.
append
(
"<return_code><![CDATA[SUCCESS]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[OK]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
return
sb
.
toString
();
}
redisUtil
.
lPush
(
Constants
.
ORDER_TASK_PAY_SUCCESS_AFTER
,
sOrder
.
getOrderNo
());
sb
.
append
(
"<return_code><![CDATA[SUCCESS]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[OK]]></return_msg>"
);
break
;
case
RECHARGE:
break
;
default
:
logger
.
error
(
"wechat pay err : 未知的支付类型==》"
+
callbackVo
.
getOutTradeNo
());
throw
new
BaseException
(
"未知的支付类型!"
);
}
}
catch
(
Exception
e
){
sb
.
append
(
"<return_code><![CDATA[FAIL]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA["
).
append
(
e
.
getMessage
()).
append
(
"]]></return_msg>"
);
logger
.
error
(
"wechat pay error : 业务异常==》"
+
e
.
getMessage
());
}
sb
.
append
(
"</xml>"
);
logger
.
error
(
"wechat callback response : "
+
sb
.
toString
());
return
sb
.
toString
();
}
/**
* 将request中的参数转换成Map
* @param request
* @return
*/
private
Map
<
String
,
String
>
convertRequestParamsToMap
(
HttpServletRequest
request
)
{
Map
<
String
,
String
>
retMap
=
new
HashMap
<
String
,
String
>();
Map
requestParams
=
request
.
getParameterMap
();
for
(
Iterator
iter
=
requestParams
.
keySet
().
iterator
();
iter
.
hasNext
();)
{
String
name
=
(
String
)
iter
.
next
();
String
[]
values
=
(
String
[])
requestParams
.
get
(
name
);
String
valueStr
=
""
;
for
(
int
i
=
0
;
i
<
values
.
length
;
i
++)
{
valueStr
=
(
i
==
values
.
length
-
1
)
?
valueStr
+
values
[
i
]
:
valueStr
+
values
[
i
]
+
","
;
}
//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
retMap
.
put
(
name
,
valueStr
);
}
return
retMap
;
}
/**
* 微信退款回调
* @param xmlInfo 微信回调json
* @return MyRecord
*/
@Override
public
String
weChatRefund
(
String
xmlInfo
)
{
MyRecord
notifyRecord
=
new
MyRecord
();
MyRecord
refundRecord
=
refundNotify
(
xmlInfo
,
notifyRecord
);
if
(
refundRecord
.
getStr
(
"status"
).
equals
(
"fail"
))
{
logger
.
error
(
"微信退款回调失败==>"
+
refundRecord
.
getColumns
()
+
", rawData==>"
+
xmlInfo
+
", data==>"
+
notifyRecord
);
return
refundRecord
.
getStr
(
"returnXml"
);
}
if
(!
refundRecord
.
getBoolean
(
"isRefund"
))
{
logger
.
error
(
"微信退款回调失败==>"
+
refundRecord
.
getColumns
()
+
", rawData==>"
+
xmlInfo
+
", data==>"
+
notifyRecord
);
return
refundRecord
.
getStr
(
"returnXml"
);
}
String
outRefundNo
=
notifyRecord
.
getStr
(
"out_refund_no"
);
SOrder
sOrder
=
sOrderService
.
getByOrderNo
(
outRefundNo
);
if
(
ObjectUtil
.
isNull
(
sOrder
))
{
logger
.
error
(
"微信退款订单查询失败==>"
+
refundRecord
.
getColumns
()
+
", rawData==>"
+
xmlInfo
+
", data==>"
+
notifyRecord
);
return
refundRecord
.
getStr
(
"returnXml"
);
}
if
(
sOrder
.
getRefundStatus
()
==
2
)
{
logger
.
warn
(
"微信退款订单已确认成功==>"
+
refundRecord
.
getColumns
()
+
", rawData==>"
+
xmlInfo
+
", data==>"
+
notifyRecord
);
return
refundRecord
.
getStr
(
"returnXml"
);
}
sOrder
.
setRefundStatus
(
2
);
boolean
update
=
sOrderService
.
updateById
(
sOrder
);
if
(
update
)
{
// 退款task
redisUtil
.
lPush
(
Constants
.
ORDER_TASK_REDIS_KEY_AFTER_REFUND_BY_USER
,
sOrder
.
getId
());
}
else
{
logger
.
warn
(
"微信退款订单更新失败==>"
+
refundRecord
.
getColumns
()
+
", rawData==>"
+
xmlInfo
+
", data==>"
+
notifyRecord
);
}
return
refundRecord
.
getStr
(
"returnXml"
);
}
/**
* 支付订单回调通知
* @return MyRecord
*/
private
MyRecord
refundNotify
(
String
xmlInfo
,
MyRecord
notifyRecord
)
{
MyRecord
refundRecord
=
new
MyRecord
();
refundRecord
.
set
(
"status"
,
"fail"
);
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"<xml>"
);
if
(
StrUtil
.
isBlank
(
xmlInfo
)){
sb
.
append
(
"<return_code><![CDATA[FAIL]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[xmlInfo is blank]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
logger
.
error
(
"wechat refund callback error : "
+
sb
.
toString
());
return
refundRecord
.
set
(
"returnXml"
,
sb
.
toString
()).
set
(
"errMsg"
,
"xmlInfo is blank"
);
}
Map
<
String
,
String
>
respMap
;
try
{
respMap
=
WxPayUtil
.
xmlToMap
(
xmlInfo
);
}
catch
(
Exception
e
)
{
sb
.
append
(
"<return_code><![CDATA[FAIL]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA["
).
append
(
e
.
getMessage
()).
append
(
"]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
logger
.
error
(
"wechat refund callback error : "
+
e
.
getMessage
());
return
refundRecord
.
set
(
"returnXml"
,
sb
.
toString
()).
set
(
"errMsg"
,
e
.
getMessage
());
}
notifyRecord
.
setColums
(
_strMap2ObjMap
(
respMap
));
// 这里的可以应该根据小程序还是公众号区分
String
return_code
=
respMap
.
get
(
"return_code"
);
if
(
return_code
.
equals
(
Constants
.
SUCCESS
))
{
String
appid
=
respMap
.
get
(
"appid"
);
String
signKey
=
getSignKey
(
appid
);
// 解码加密信息
String
reqInfo
=
respMap
.
get
(
"req_info"
);
System
.
out
.
println
(
"encodeReqInfo==>"
+
reqInfo
);
try
{
String
decodeInfo
=
decryptToStr
(
reqInfo
,
signKey
);
Map
<
String
,
String
>
infoMap
=
WxPayUtil
.
xmlToMap
(
decodeInfo
);
notifyRecord
.
setColums
(
_strMap2ObjMap
(
infoMap
));
String
refund_status
=
infoMap
.
get
(
"refund_status"
);
refundRecord
.
set
(
"isRefund"
,
refund_status
.
equals
(
Constants
.
SUCCESS
));
}
catch
(
Exception
e
)
{
refundRecord
.
set
(
"isRefund"
,
false
);
logger
.
error
(
"微信退款回调异常,e==》"
+
e
.
getMessage
());
}
}
else
{
notifyRecord
.
set
(
"return_msg"
,
respMap
.
get
(
"return_msg"
));
refundRecord
.
set
(
"isRefund"
,
false
);
}
sb
.
append
(
"<return_code><![CDATA[SUCCESS]]></return_code>"
);
sb
.
append
(
"<return_msg><![CDATA[OK]]></return_msg>"
);
sb
.
append
(
"</xml>"
);
return
refundRecord
.
set
(
"returnXml"
,
sb
.
toString
()).
set
(
"status"
,
"ok"
);
}
private
String
getSignKey
(
String
appid
)
{
String
publicAppid
=
weChatConfig
.
getPublicAppId
();
String
miniAppid
=
weChatConfig
.
getAppId
();
String
signKey
=
""
;
if
(
StrUtil
.
isBlank
(
publicAppid
)
&&
StrUtil
.
isBlank
(
miniAppid
))
{
throw
new
BaseException
(
"pay_weixin_appid或pay_routine_appid不能都为空"
);
}
if
(
StrUtil
.
isNotBlank
(
publicAppid
)
&&
appid
.
equals
(
publicAppid
))
{
signKey
=
weChatConfig
.
getSignKey
();
}
if
(
StrUtil
.
isNotBlank
(
miniAppid
)
&&
appid
.
equals
(
miniAppid
))
{
signKey
=
weChatConfig
.
getPublicSignKey
();
}
return
signKey
;
}
/**
* java自带的是PKCS5Padding填充,不支持PKCS7Padding填充。
* 通过BouncyCastle组件来让java里面支持PKCS7Padding填充
* 在加解密之前加上:Security.addProvider(new BouncyCastleProvider()),
* 并给Cipher.getInstance方法传入参数来指定Java使用这个库里的加/解密算法。
*/
public
static
String
decryptToStr
(
String
reqInfo
,
String
signKey
)
throws
Exception
{
Security
.
addProvider
(
new
BouncyCastleProvider
());
// byte[] decodeReqInfo = Base64.decode(reqInfo);
byte
[]
decodeReqInfo
=
base64DecodeJustForWxPay
(
reqInfo
).
getBytes
(
StandardCharsets
.
ISO_8859_1
);
SecretKeySpec
key
=
new
SecretKeySpec
(
SecureUtil
.
md5
(
signKey
).
toLowerCase
().
getBytes
(),
"AES"
);
Cipher
cipher
;
cipher
=
Cipher
.
getInstance
(
"AES/ECB/PKCS7Padding"
);
cipher
.
init
(
Cipher
.
DECRYPT_MODE
,
key
);
return
new
String
(
cipher
.
doFinal
(
decodeReqInfo
),
StandardCharsets
.
UTF_8
);
}
private
static
final
List
<
String
>
list
=
new
ArrayList
<>();
static
{
list
.
add
(
"total_fee"
);
list
.
add
(
"cash_fee"
);
list
.
add
(
"coupon_fee"
);
list
.
add
(
"coupon_count"
);
list
.
add
(
"refund_fee"
);
list
.
add
(
"settlement_refund_fee"
);
list
.
add
(
"settlement_total_fee"
);
list
.
add
(
"cash_refund_fee"
);
list
.
add
(
"coupon_refund_fee"
);
list
.
add
(
"coupon_refund_count"
);
}
private
Map
<
String
,
Object
>
_strMap2ObjMap
(
Map
<
String
,
String
>
params
)
{
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
for
(
Map
.
Entry
<
String
,
String
>
entry
:
params
.
entrySet
())
{
if
(
list
.
contains
(
entry
.
getKey
()))
{
try
{
map
.
put
(
entry
.
getKey
(),
Integer
.
parseInt
(
entry
.
getValue
()));
}
catch
(
NumberFormatException
e
)
{
map
.
put
(
entry
.
getKey
(),
0
);
logger
.
error
(
"字段格式错误,key==》"
+
entry
.
getKey
()
+
", value==》"
+
entry
.
getValue
());
}
continue
;
}
map
.
put
(
entry
.
getKey
(),
entry
.
getValue
());
}
return
map
;
}
/**
* 仅仅为微信解析密文使用
* @param source 待解析密文
* @return 结果
*/
public
static
String
base64DecodeJustForWxPay
(
final
String
source
)
{
String
result
=
""
;
final
Base64
.
Decoder
decoder
=
Base64
.
getDecoder
();
try
{
result
=
new
String
(
decoder
.
decode
(
source
),
"ISO-8859-1"
);
}
catch
(
final
UnsupportedEncodingException
e
)
{
e
.
printStackTrace
();
}
return
result
;
}
}
share-system/src/main/java/share/system/service/impl/OrderPayServiceImpl.java
View file @
e712f029
package
share
.
system
.
service
.
impl
;
package
share
.
system
.
service
.
impl
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
com.alibaba.fastjson.JSONObject
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
@@ -8,6 +9,7 @@ import org.springframework.stereotype.Service;
...
@@ -8,6 +9,7 @@ import org.springframework.stereotype.Service;
import
share.common.config.WeChatConfig
;
import
share.common.config.WeChatConfig
;
import
share.common.constant.Constants
;
import
share.common.constant.Constants
;
import
share.common.constant.PayConstants
;
import
share.common.constant.PayConstants
;
import
share.common.enums.OrderTypeEnum
;
import
share.common.enums.PayTypeEnum
;
import
share.common.enums.PayTypeEnum
;
import
share.common.enums.YesNoEnum
;
import
share.common.enums.YesNoEnum
;
import
share.common.exception.base.BaseException
;
import
share.common.exception.base.BaseException
;
...
@@ -16,6 +18,7 @@ import share.common.utils.DateUtil;
...
@@ -16,6 +18,7 @@ import share.common.utils.DateUtil;
import
share.common.utils.JsonConvertUtil
;
import
share.common.utils.JsonConvertUtil
;
import
share.system.domain.SConsumerToken
;
import
share.system.domain.SConsumerToken
;
import
share.system.domain.SOrder
;
import
share.system.domain.SOrder
;
import
share.system.domain.vo.AttachVo
;
import
share.system.domain.vo.CreateOrderRequestVo
;
import
share.system.domain.vo.CreateOrderRequestVo
;
import
share.system.domain.vo.CreateOrderResponseVo
;
import
share.system.domain.vo.CreateOrderResponseVo
;
import
share.system.domain.vo.WxPayJsResultVo
;
import
share.system.domain.vo.WxPayJsResultVo
;
...
@@ -117,11 +120,14 @@ public class OrderPayServiceImpl implements OrderPayService {
...
@@ -117,11 +120,14 @@ public class OrderPayServiceImpl implements OrderPayService {
private
CreateOrderRequestVo
getUnifiedorderVo
(
SOrder
sOrder
,
String
openid
,
String
appId
,
String
mchId
,
String
signKey
)
{
private
CreateOrderRequestVo
getUnifiedorderVo
(
SOrder
sOrder
,
String
openid
,
String
appId
,
String
mchId
,
String
signKey
)
{
// 获取域名
// 获取域名
String
apiDomain
=
Constants
.
CONFIG_KEY_API_URL
;
String
apiDomain
=
Constants
.
CONFIG_KEY_API_URL
;
AttachVo
attachVo
=
new
AttachVo
(
OrderTypeEnum
.
getEnumByCode
(
sOrder
.
getOrderType
()).
getValue
(),
sOrder
.
getConsumerId
());
CreateOrderRequestVo
vo
=
new
CreateOrderRequestVo
();
CreateOrderRequestVo
vo
=
new
CreateOrderRequestVo
();
vo
.
setAppid
(
appId
);
vo
.
setAppid
(
appId
);
vo
.
setMch_id
(
mchId
);
vo
.
setMch_id
(
mchId
);
vo
.
setNonce_str
(
WxPayUtil
.
getNonceStr
());
vo
.
setNonce_str
(
WxPayUtil
.
getNonceStr
());
vo
.
setSign_type
(
PayConstants
.
WX_PAY_SIGN_TYPE_MD5
);
vo
.
setSign_type
(
PayConstants
.
WX_PAY_SIGN_TYPE_MD5
);
vo
.
setAttach
(
JSONObject
.
toJSONString
(
attachVo
));
vo
.
setOut_trade_no
(
BaseUtil
.
getOrderNo
(
"wxNo"
));
vo
.
setOut_trade_no
(
BaseUtil
.
getOrderNo
(
"wxNo"
));
// 订单中使用的是BigDecimal,这里要转为Integer类型
// 订单中使用的是BigDecimal,这里要转为Integer类型
vo
.
setTotal_fee
(
sOrder
.
getPayPrice
().
multiply
(
BigDecimal
.
TEN
).
multiply
(
BigDecimal
.
TEN
).
intValue
());
vo
.
setTotal_fee
(
sOrder
.
getPayPrice
().
multiply
(
BigDecimal
.
TEN
).
multiply
(
BigDecimal
.
TEN
).
intValue
());
...
...
share-system/src/main/java/share/system/service/impl/SOrderServiceImpl.java
View file @
e712f029
...
@@ -269,6 +269,13 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
...
@@ -269,6 +269,13 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
return
getOne
(
lqw
);
return
getOne
(
lqw
);
}
}
@Override
public
SOrder
getInfoByEntity
(
SOrder
orderParam
)
{
LambdaQueryWrapper
<
SOrder
>
lambdaQueryWrapper
=
new
LambdaQueryWrapper
<>();
lambdaQueryWrapper
.
setEntity
(
orderParam
);
return
getOne
(
lambdaQueryWrapper
);
}
private
BigDecimal
computeTotalPrice
(
BigDecimal
unitPrice
,
Date
startTime
,
Date
endTime
){
private
BigDecimal
computeTotalPrice
(
BigDecimal
unitPrice
,
Date
startTime
,
Date
endTime
){
return
DateUtils
.
differentHour
(
startTime
,
endTime
).
multiply
(
unitPrice
);
return
DateUtils
.
differentHour
(
startTime
,
endTime
).
multiply
(
unitPrice
);
}
}
...
@@ -298,10 +305,10 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
...
@@ -298,10 +305,10 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
if
(
ObjectUtil
.
isNull
(
consumerCoupon
)
||
!
consumerCoupon
.
getCouponId
().
equals
(
user
.
getId
()))
{
if
(
ObjectUtil
.
isNull
(
consumerCoupon
)
||
!
consumerCoupon
.
getCouponId
().
equals
(
user
.
getId
()))
{
throw
new
BaseException
(
"优惠券领取记录不存在!"
);
throw
new
BaseException
(
"优惠券领取记录不存在!"
);
}
}
if
(
CouponStatusEnum
.
USED
.
getValue
().
compareTo
(
Integer
.
parseInt
(
consumerCoupon
.
getUseStatus
()
))
==
0
)
{
if
(
CouponStatusEnum
.
USED
.
getValue
().
compareTo
(
consumerCoupon
.
getUseStatus
(
))
==
0
)
{
throw
new
BaseException
(
"此优惠券已使用!"
);
throw
new
BaseException
(
"此优惠券已使用!"
);
}
}
if
(
CouponStatusEnum
.
EXPIRED
.
getValue
().
compareTo
(
Integer
.
parseInt
(
consumerCoupon
.
getUseStatus
()
))
==
0
)
{
if
(
CouponStatusEnum
.
EXPIRED
.
getValue
().
compareTo
(
consumerCoupon
.
getUseStatus
(
))
==
0
)
{
throw
new
BaseException
(
"此优惠券已失效!"
);
throw
new
BaseException
(
"此优惠券已失效!"
);
}
}
//判断是否在使用时间内
//判断是否在使用时间内
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment