|
@@ -50,8 +50,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|
|
public interface OrderFeignClient {
|
|
|
|
|
|
/**
|
|
|
- * 根据订单编号查询订单信息(包含明细)
|
|
|
- *
|
|
|
+ * 根据订单编号查询订单信息
|
|
|
* @param orderNo
|
|
|
* @return
|
|
|
*/
|
|
@@ -116,11 +115,11 @@ public class RechargeInfoApiController {
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * 根据充值订单编号查询充值记录
|
|
|
+ * 根据充值订单编号查询充值信息
|
|
|
* @param orderNo
|
|
|
* @return
|
|
|
*/
|
|
|
- @Operation(summary = "根据充值订单编号查询充值记录")
|
|
|
+ @Operation(summary = "根据充值订单编号查询充值信息")
|
|
|
@GetMapping("/rechargeInfo/getRechargeInfo/{orderNo}")
|
|
|
public Result<RechargeInfo> getRechargeInfo(@PathVariable String orderNo){
|
|
|
RechargeInfo rechargeInfo = rechargeInfoService.getRechargeInfo(orderNo);
|
|
@@ -169,17 +168,19 @@ public class RechargeInfoServiceImpl extends ServiceImpl<RechargeInfoMapper, Rec
|
|
|
@Autowired
|
|
|
private RechargeInfoMapper rechargeInfoMapper;
|
|
|
|
|
|
- /**
|
|
|
- * 根据充值订单编号查询充值记录
|
|
|
- * @param orderNo
|
|
|
- * @return
|
|
|
- */
|
|
|
- @Override
|
|
|
- public RechargeInfo getRechargeInfo(String orderNo) {
|
|
|
- LambdaQueryWrapper<RechargeInfo> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
- queryWrapper.eq(RechargeInfo::getOrderNo, orderNo);
|
|
|
- return rechargeInfoMapper.selectOne(queryWrapper);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 根据充值订单编号查询充值信息
|
|
|
+ *
|
|
|
+ * @param orderNo
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public RechargeInfo getRechargeInfo(String orderNo) {
|
|
|
+ return rechargeInfoMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<RechargeInfo>()
|
|
|
+ .eq(RechargeInfo::getOrderNo, orderNo)
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -187,7 +188,7 @@ public class RechargeInfoServiceImpl extends ServiceImpl<RechargeInfoMapper, Rec
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 根据充值订单编号查询充值记录
|
|
|
+ * 根据充值订单编号查询充值信息
|
|
|
* @param orderNo
|
|
|
* @return
|
|
|
*/
|
|
@@ -272,50 +273,63 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
|
|
*/
|
|
|
@Override
|
|
|
public PaymentInfo savePaymentInfo(String paymentType, String orderNo) {
|
|
|
- //0.根据订单/充值编号查询交易记录 存在直接返回,不存在新增
|
|
|
- LambdaQueryWrapper<PaymentInfo> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
- queryWrapper.eq(PaymentInfo::getOrderNo, orderNo);
|
|
|
- PaymentInfo paymentInfo = this.getOne(queryWrapper);
|
|
|
+ Long userId = AuthContextHolder.getUserId();
|
|
|
+ //1.根据订单编号查询本地交易记录,如果存在则返回即可
|
|
|
+ PaymentInfo paymentInfo = baseMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<PaymentInfo>()
|
|
|
+ .eq(PaymentInfo::getOrderNo, orderNo)
|
|
|
+ );
|
|
|
if (paymentInfo != null) {
|
|
|
return paymentInfo;
|
|
|
- }else{
|
|
|
- //1.构建本地交易记录对象
|
|
|
- paymentInfo = new PaymentInfo();
|
|
|
-
|
|
|
- //1.1 封装对象中简单属性
|
|
|
- Long userId = AuthContextHolder.getUserId();
|
|
|
- paymentInfo.setUserId(userId);
|
|
|
- paymentInfo.setPaymentType(paymentType);
|
|
|
- paymentInfo.setOrderNo(orderNo);
|
|
|
- paymentInfo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);
|
|
|
- paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_UNPAID);
|
|
|
- //1.2 封装本地交易记录中金额跟内容-远程调用其他服务获取
|
|
|
- //1.3 判断支付类型:订单
|
|
|
- if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
|
|
|
- //1.3.1 远程调用订单服务获取订单信息
|
|
|
- OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderNo).getData();
|
|
|
- Assert.notNull(orderInfo, "订单不存在");
|
|
|
- //1.3.2 校验订单状态是否为:未支付
|
|
|
- boolean flag = SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus());
|
|
|
- Assert.state(flag, "订单状态有误!");
|
|
|
- //1.3.3 封装本地交易记录中交易内容跟金额
|
|
|
- paymentInfo.setAmount(orderInfo.getOrderAmount());
|
|
|
- paymentInfo.setContent(orderInfo.getOrderTitle());
|
|
|
- } else if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(paymentType)) {
|
|
|
- //1.4 判断支付类型:充值
|
|
|
- //1.4.1 远程调用账户服务获取充值信息
|
|
|
- RechargeInfo rechargeInfo = accountFeignClient.getRechargeInfo(orderNo).getData();
|
|
|
- Assert.notNull(rechargeInfo, "充值记录不存在");
|
|
|
- //1.4.2 校验充值状态是否为:未支付
|
|
|
- boolean flag = SystemConstant.ORDER_STATUS_UNPAID.equals(rechargeInfo.getRechargeStatus());
|
|
|
- Assert.state(flag, "充值状态有误!");
|
|
|
- //1.4.3 封装本地交易记录中交易内容跟金额
|
|
|
- paymentInfo.setAmount(rechargeInfo.getRechargeAmount());
|
|
|
- paymentInfo.setContent("用户充值:" + rechargeInfo.getRechargeAmount());
|
|
|
+ }
|
|
|
+ //2.构建本地交易记录
|
|
|
+ paymentInfo = new PaymentInfo();
|
|
|
+
|
|
|
+
|
|
|
+ //2.1 封装直接赋值属性:用户ID,支付类型、订单号、付款方式、支付状态
|
|
|
+ paymentInfo.setUserId(userId);
|
|
|
+ paymentInfo.setPaymentType(paymentType);
|
|
|
+ paymentInfo.setOrderNo(orderNo);
|
|
|
+ paymentInfo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);
|
|
|
+ paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_UNPAID);
|
|
|
+ //2.2 处理支付类型为:1301订单,封装交易金额跟内容
|
|
|
+ if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
|
|
|
+ //2.2.1 远程调用订单服务获取订单信息
|
|
|
+ OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderNo).getData();
|
|
|
+ Assert.notNull(orderInfo, "订单{}不存在", orderNo);
|
|
|
+ //2.2.2 判断订单状态,未支付才能支付 订单状态:0901-未支付 0902-已支付 0903-已取消
|
|
|
+ String orderStatus = orderInfo.getOrderStatus();
|
|
|
+ if (!SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)) {
|
|
|
+ throw new GuiguException(500, "订单状态有误:" + orderStatus);
|
|
|
}
|
|
|
- //2.保存本地交易记录对象
|
|
|
- this.save(paymentInfo);
|
|
|
+ //2.2.3 封装交易金额跟内容
|
|
|
+ paymentInfo.setAmount(orderInfo.getOrderAmount());
|
|
|
+ paymentInfo.setContent(orderInfo.getOrderTitle());
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ //2.3 处理支付类型为:1302充值,封装交易金额跟内容
|
|
|
+ if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(paymentType)) {
|
|
|
+ //2.2.1 远程调用账户服务获取充值信息
|
|
|
+ RechargeInfo rechargeInfo = accountFeignClient.getRechargeInfo(orderNo).getData();
|
|
|
+ Assert.notNull(rechargeInfo, "充值{}不存在", orderNo);
|
|
|
+ //2.2.2 判断充值状态,未支付才能支付 充值状态:0901-未支付 0902-已支付 0903-已取消
|
|
|
+ String rechargeStatus = rechargeInfo.getRechargeStatus();
|
|
|
+ if (!SystemConstant.ORDER_STATUS_UNPAID.equals(rechargeStatus)) {
|
|
|
+ throw new GuiguException(500, "充值状态有误:" + rechargeStatus);
|
|
|
+ }
|
|
|
+ //2.3.3 封装交易金额跟内容
|
|
|
+ paymentInfo.setAmount(rechargeInfo.getRechargeAmount());
|
|
|
+ paymentInfo.setContent("充值:" + rechargeInfo.getRechargeAmount());
|
|
|
+ }
|
|
|
+
|
|
|
+ //2.4 TODO 其他属性,等支付成功后异步回调获取
|
|
|
+ //paymentInfo.setOutTradeNo();
|
|
|
+ //paymentInfo.setCallbackTime();
|
|
|
+ //paymentInfo.setCallbackContent();
|
|
|
+
|
|
|
+ //3.保存本地交易记录
|
|
|
+ baseMapper.insert(paymentInfo);
|
|
|
return paymentInfo;
|
|
|
}
|
|
|
}
|
|
@@ -426,17 +440,17 @@ public class WxPayApiController {
|
|
|
private WxPayService wxPayService;
|
|
|
|
|
|
|
|
|
- /**
|
|
|
- * 对接微信支付返回小程序拉起微信支付页面所需参数
|
|
|
- *
|
|
|
- * @param paymentType 支付类型:1301-订单 1302-充值
|
|
|
- * @param orderNo 订单号(订单、充值)
|
|
|
- * @return {}包含五项参数
|
|
|
+ /**
|
|
|
+ * 下单或充值选择微信支付,返回小程序拉起微信支付所需参数
|
|
|
+ * @param paymentType 支付类型:1301下单 1302充值
|
|
|
+ * @param orderNo 订单/充值订单编号
|
|
|
+ * @return {"timeStamp":"","package":"","paySign":"","signType":"RSA","nonceStr":""}
|
|
|
*/
|
|
|
@GuiGuLogin
|
|
|
- @Operation(summary = "对接微信支付返回小程序拉起微信支付页面所需参数")
|
|
|
+ @Operation(summary = "下单或充值选择微信支付,返回小程序拉起微信支付所需参数")
|
|
|
@PostMapping("/wxPay/createJsapi/{paymentType}/{orderNo}")
|
|
|
- public Result<Map<String, String>> createJsapi(@PathVariable String paymentType, @PathVariable String orderNo) {
|
|
|
+ public Result<Map<String, String>> createJsapi(@PathVariable String paymentType,
|
|
|
+ @PathVariable String orderNo){
|
|
|
Map<String, String> map = wxPayService.createJsapi(paymentType, orderNo);
|
|
|
return Result.ok(map);
|
|
|
}
|
|
@@ -453,13 +467,13 @@ import java.util.Map;
|
|
|
public interface WxPayService {
|
|
|
|
|
|
/**
|
|
|
- * 对接微信支付返回小程序拉起微信支付页面所需参数
|
|
|
- *
|
|
|
- * @param paymentType 支付类型:1301-订单 1302-充值
|
|
|
- * @param orderNo 订单号(订单、充值)
|
|
|
- * @return {}包含五项参数
|
|
|
+ * 下单或充值选择微信支付,返回小程序拉起微信支付所需参数
|
|
|
+ * @param paymentType 支付类型:1301下单 1302充值
|
|
|
+ * @param orderNo 订单/充值订单编号
|
|
|
+ * @return {{"timeStamp":"","package":"","paySign":"","signType":"RSA","nonceStr":""}}}
|
|
|
*/
|
|
|
Map<String, String> createJsapi(String paymentType, String orderNo);
|
|
|
+
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -511,22 +525,24 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
@Autowired
|
|
|
private RSAAutoCertificateConfig rsaAutoCertificateConfig;
|
|
|
|
|
|
- /**
|
|
|
- * 对接微信支付返回小程序拉起微信支付页面所需参数
|
|
|
+ /**
|
|
|
+ * 下单或充值选择微信支付,返回小程序拉起微信支付所需参数
|
|
|
*
|
|
|
- * @param paymentType 支付类型:1301-订单 1302-充值
|
|
|
- * @param orderNo 订单号(订单、充值)
|
|
|
- * @return {}包含五项参数
|
|
|
+ * @param paymentType 支付类型:1301下单 1302充值
|
|
|
+ * @param orderNo 订单/充值订单编号
|
|
|
+ * @return {{"timeStamp":"","package":"","paySign":"","signType":"RSA","nonceStr":""}}}
|
|
|
*/
|
|
|
@Override
|
|
|
public Map<String, String> createJsapi(String paymentType, String orderNo) {
|
|
|
try {
|
|
|
- //1.新增本地交易记录
|
|
|
+ //1.获取或保存本地交易记录,验证状态
|
|
|
PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo);
|
|
|
- if (SystemConstant.PAYMENT_STATUS_PAID.equals(paymentInfo.getPaymentStatus())) {
|
|
|
- throw new RuntimeException("该笔交易已支付");
|
|
|
+ //支付状态:1401-未支付 1402-已支付
|
|
|
+ String paymentStatus = paymentInfo.getPaymentStatus();
|
|
|
+ if (!SystemConstant.PAYMENT_STATUS_UNPAID.equals(paymentStatus)) {
|
|
|
+ throw new GuiguException(500, "本地交易记录状态有误" + paymentStatus);
|
|
|
}
|
|
|
- //2.调用微信支付接口返回小程序拉起微信支付所需参数
|
|
|
+ //2.对接微信支付,获取小程序端拉起微信支付所需参数
|
|
|
//2.1 创建调用微信支付JSAPI业务对象
|
|
|
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
|
|
|
|
|
@@ -563,9 +579,9 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
return map;
|
|
|
}
|
|
|
return null;
|
|
|
- } catch (RuntimeException e) {
|
|
|
- log.error("创建微信支付JSAPI参数失败", e);
|
|
|
- throw new RuntimeException(e);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("微信下单失败");
|
|
|
+ throw new GuiguException(500, e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -585,17 +601,16 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 根据商户订单编号查询微信支付结果
|
|
|
- *
|
|
|
+ * 查询订单支付状态
|
|
|
* @param orderNo
|
|
|
* @return
|
|
|
*/
|
|
|
@GuiGuLogin
|
|
|
-@Operation(summary = "根据商户订单编号查询微信支付结果")
|
|
|
+@Operation(summary = "商户端主动查询微信支付结果")
|
|
|
@GetMapping("/wxPay/queryPayStatus/{orderNo}")
|
|
|
-public Result<Boolean> queryPayStatus(@PathVariable String orderNo) {
|
|
|
- Boolean flag = wxPayService.queryPayStatus(orderNo);
|
|
|
- return Result.ok(flag);
|
|
|
+public Result<Boolean> queryPayStatus(@PathVariable String orderNo){
|
|
|
+ boolean result = wxPayService.queryPayStatus(orderNo);
|
|
|
+ return Result.ok(result);
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -615,60 +630,45 @@ Boolean queryPayStatus(String orderNo);
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 查询订单支付状态:调用微信支付接口查询支付状态
|
|
|
+ * 查询订单支付状态
|
|
|
*
|
|
|
* @param orderNo
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
-@GlobalTransactional(rollbackFor = Exception.class)
|
|
|
-public Boolean queryPayStatus(String orderNo) {
|
|
|
- //1 JSAPI支付和APP支付业务类对象
|
|
|
+public boolean queryPayStatus(String orderNo) {
|
|
|
+ /*//1.构建业务对象
|
|
|
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
|
|
|
- //2.创建商户订单查询支付结果请求对象
|
|
|
- QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
|
|
|
- queryRequest.setMchid(wxPayV3Config.getMerchantId());
|
|
|
- queryRequest.setOutTradeNo(orderNo);
|
|
|
-
|
|
|
- try {
|
|
|
- //3.执行查询
|
|
|
- Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
|
|
|
- if (transaction != null) {
|
|
|
- if (transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
|
|
|
- Integer payerTotal = transaction.getAmount().getPayerTotal();
|
|
|
- if (1 == payerTotal) {
|
|
|
- return true;
|
|
|
- }
|
|
|
+ //2.构建根据商户订单号查询微信支付订单状态的请求参数
|
|
|
+ QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
|
|
|
+ request.setMchid(wxPayV3Config.getMerchantId());
|
|
|
+ request.setOutTradeNo(orderNo);
|
|
|
+
|
|
|
+ //3.调用微信支付查询订单状态接口
|
|
|
+ Transaction transaction = service.queryOrderByOutTradeNo(request);
|
|
|
+ if (transaction != null) {
|
|
|
+ Transaction.TradeStateEnum tradeState = transaction.getTradeState();
|
|
|
+ if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
|
|
|
+ //交易成功,验证订单金额跟用户实付金额是否一致
|
|
|
+ Integer payerTotal = transaction.getAmount().getPayerTotal();
|
|
|
+ if (payerTotal.intValue() == 1) {
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
- // API返回失败, 例如ORDER_NOT_EXISTS
|
|
|
- log.error("[支付系统]同步查询支付状态异常:{}", e);
|
|
|
}
|
|
|
- return false;
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**大家实现(没有办法支付,故在同步回调中模拟支付成功)-代码**:
|
|
|
-
|
|
|
-```java
|
|
|
-/**
|
|
|
- * 根据商户订单编号查询微信支付结果
|
|
|
- *
|
|
|
- * @param orderNo 商户订单编号
|
|
|
- * @return
|
|
|
- */
|
|
|
-@Override
|
|
|
-public Boolean queryPayStatus(String orderNo) {
|
|
|
- //TODO 模拟用户已经完成付款(商户入账),处理本地交易记录及订单或充值业务
|
|
|
+ return false;*/
|
|
|
+ //TODO 处理核心业务:更新本地交易记录状态
|
|
|
+ //1.伪造微信交易对象 封装:订单编号+微信交易号
|
|
|
Transaction transaction = new Transaction();
|
|
|
transaction.setOutTradeNo(orderNo);
|
|
|
- transaction.setTransactionId("wx"+ IdUtil.getSnowflakeNextId());
|
|
|
- paymentInfoService.handlerPaymentInfo(transaction);
|
|
|
+ transaction.setTransactionId("WX"+ IdUtil.getSnowflakeNextId());
|
|
|
+ paymentInfoService.updatePaymentInfo(transaction);
|
|
|
return true;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
+**大家课后练习(没有办法支付,故在同步回调中模拟支付成功)**
|
|
|
+
|
|
|
## 1.4 支付异步回调
|
|
|
|
|
|
> 微信异步回调说明:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_5.shtml
|
|
@@ -779,14 +779,15 @@ public Boolean queryPayStatus(String orderNo) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 提供给微信支付调用:用户微信付款成功后,微信通知商户支付结果
|
|
|
+ * 微信支付成功后异步回调
|
|
|
* @param request
|
|
|
- * @return {code:"SUCCESS",message:"成功"}
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
*/
|
|
|
-@Operation(summary = "提供给微信支付调用:用户微信付款成功后,微信通知商户支付结果")
|
|
|
+@Operation(summary = "微信支付成功后异步回调")
|
|
|
@PostMapping("/wxPay/notify")
|
|
|
-public Map<String, String> notifyPayResult(HttpServletRequest request) {
|
|
|
- return wxPayService.notifyPayResult(request);
|
|
|
+public Map<String, String> wxPayNotify(HttpServletRequest request) throws Exception {
|
|
|
+ return wxPayService.wxPayNotify(request);
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -814,7 +815,7 @@ private RedisTemplate redisTemplate;
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
-public Map<String, String> notifyPayResult(HttpServletRequest request) {
|
|
|
+public Map<String, String> wxPayNotify(HttpServletRequest request) {
|
|
|
//1.验签-避免出现虚假通知或支付结果在网络传输中被恶意篡改
|
|
|
//1.1 从请求头中获取封装请求参数对象数据
|
|
|
String signature = request.getHeader("Wechatpay-Signature");
|
|
@@ -826,6 +827,7 @@ public Map<String, String> notifyPayResult(HttpServletRequest request) {
|
|
|
//1.2 获取请求体中参数
|
|
|
String body = PayUtil.readData(request);
|
|
|
log.info("请求体:{}", body);
|
|
|
+
|
|
|
//2.参数解密-解析获取请求体中业务参数(支付结果业务数据)
|
|
|
//2.1 构造RequestParam
|
|
|
RequestParam requestParam = new RequestParam.Builder()
|
|
@@ -840,29 +842,30 @@ public Map<String, String> notifyPayResult(HttpServletRequest request) {
|
|
|
//2.3 解密并转换成 Transaction交易对象
|
|
|
Transaction transaction = parser.parse(requestParam, Transaction.class);
|
|
|
|
|
|
- //3.幂等性处理:微信会多次重复发送通知共计时间24h4m
|
|
|
+ //3.验证微信支付状态:必须是已支付,应付金额跟实付金额一致
|
|
|
if (transaction != null) {
|
|
|
- //3.1 微信支付系统生成的订单号
|
|
|
- String transactionId = transaction.getTransactionId();
|
|
|
- //3.2 采用Redis进行幂等性处理
|
|
|
- String key = "pay:notify:" + transactionId;
|
|
|
- Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, transactionId, 25, TimeUnit.HOURS);
|
|
|
- if (flag) {
|
|
|
- try {
|
|
|
- //4.校验通知的信息是否与商户侧的信息一致:校验应付金额跟实付金额是否一致
|
|
|
- if (transaction.getAmount().getTotal().intValue() == 1) {
|
|
|
- //5.TODO 核心业务:更新本地交易及订单或者充值记录状态-存在分布式事务问题
|
|
|
- paymentInfoService.handlerPaymentInfo(transaction);
|
|
|
+ Transaction.TradeStateEnum tradeState = transaction.getTradeState();
|
|
|
+ if (Transaction.TradeStateEnum.SUCCESS == tradeState
|
|
|
+ && transaction.getAmount().getPayerTotal().intValue() == 1) {
|
|
|
+
|
|
|
+ //4.幂等性处理 同一笔交易仅需处理一次
|
|
|
+ //4.1 获取交易对象中微信支付订单号或者商户订单作为唯一标识
|
|
|
+ String redisKey = RedisConstant.BUSINESS_PREFIX + transaction.getOutTradeNo();
|
|
|
+ //4.2 利用Redis提供set k v ex nx 命令实现
|
|
|
+ Boolean flag = redisTemplate.opsForValue().setIfAbsent(redisKey, transaction.getOutTradeNo(), 25, TimeUnit.HOURS);
|
|
|
+ if (flag) {
|
|
|
+ try {
|
|
|
+ //5.核心业务处理:更新本地交易记录
|
|
|
+ paymentInfoService.updatePaymentInfo(transaction);
|
|
|
//6.返回微信正确应答
|
|
|
Map<String, String> map = new HashMap<>();
|
|
|
map.put("code", "SUCCESS");
|
|
|
map.put("message", "成功");
|
|
|
- return map;
|
|
|
+ } catch (Exception e) {
|
|
|
+ redisTemplate.delete(redisKey);
|
|
|
+ log.error("微信支付回调处理失败");
|
|
|
+ throw new RuntimeException(e);
|
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
- //如果业务发生异常无法正确应答微信,删除key,等待微信下次通知
|
|
|
- redisTemplate.delete(key);
|
|
|
- throw new RuntimeException(e);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -876,52 +879,53 @@ public Map<String, String> notifyPayResult(HttpServletRequest request) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 用户付款成功后,更新本地交易记录及关联的订单或充值相关业务处理
|
|
|
- * @param transaction
|
|
|
+ * 支付成功后,更新交易记录
|
|
|
+ * @param transaction 微信交易对象
|
|
|
*/
|
|
|
-void handlerPaymentInfo(Transaction transaction);
|
|
|
+void updatePaymentInfo(Transaction transaction);
|
|
|
```
|
|
|
|
|
|
**PaymentInfoServiceImpl**
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 用户付款成功后,更新本地交易记录及关联的订单或充值相关业务处理
|
|
|
+ * 支付成功后,更新交易记录
|
|
|
*
|
|
|
- * @param transaction
|
|
|
+ * @param transaction 微信交易对象
|
|
|
*/
|
|
|
@Override
|
|
|
@GlobalTransactional(rollbackFor = Exception.class)
|
|
|
-public void handlerPaymentInfo(Transaction transaction) {
|
|
|
- //1.核心业务1:更新本地交易-支付状态、回调内容、回调时间、微信端交易编号
|
|
|
- //1.1 获取交易对应商户订单编号
|
|
|
+public void updatePaymentInfo(Transaction transaction) {
|
|
|
+ //1.根据微信交易对象中的商户订单号查询本地交易记录 如果已支付 忽略
|
|
|
String orderNo = transaction.getOutTradeNo();
|
|
|
- //1.2 根据订单编号查询本地交易记录
|
|
|
- PaymentInfo paymentInfo = paymentInfoMapper.selectOne(new LambdaQueryWrapper<PaymentInfo>().eq(PaymentInfo::getOrderNo, orderNo));
|
|
|
- if (paymentInfo != null && SystemConstant.PAYMENT_STATUS_UNPAID.equals(paymentInfo.getPaymentStatus())) {
|
|
|
- //1.3 获取到微信交易订单编号
|
|
|
- String transactionId = transaction.getTransactionId();
|
|
|
+ PaymentInfo paymentInfo = baseMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<PaymentInfo>()
|
|
|
+ .eq(PaymentInfo::getOrderNo, orderNo)
|
|
|
+ );
|
|
|
+ //支付状态:1401-未支付 1402-已支付
|
|
|
+ String paymentStatus = paymentInfo.getPaymentStatus();
|
|
|
+ if (SystemConstant.PAYMENT_STATUS_UNPAID.equals(paymentStatus)) {
|
|
|
+ //2.更新本地交易记录状态:已支付 更新:交易编号、回调时间、回调内容
|
|
|
paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_PAID);
|
|
|
- paymentInfo.setOutTradeNo(transactionId);
|
|
|
+ paymentInfo.setOutTradeNo(transaction.getTransactionId());
|
|
|
paymentInfo.setCallbackTime(new Date());
|
|
|
paymentInfo.setCallbackContent(transaction.toString());
|
|
|
- paymentInfoMapper.updateById(paymentInfo);
|
|
|
+ baseMapper.updateById(paymentInfo);
|
|
|
|
|
|
- //支付类型:1301-订单 1302-充值
|
|
|
+ //3.处理支付类型:1301订单 订单状态更新及虚拟物品发货
|
|
|
String paymentType = paymentInfo.getPaymentType();
|
|
|
- //2.核心业务2-如果交易类型是订单,远程调用订单服务更新订单并且完成虚拟物品发货
|
|
|
if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
|
|
|
- //2.1 远程调用订单服务修改订单状态:已支付
|
|
|
Result result = orderFeignClient.orderPaySuccess(orderNo);
|
|
|
- if (!result.getCode().equals(200)) {
|
|
|
- throw new RuntimeException("远程调用-更新订单状态异常");
|
|
|
+ if (result.getCode().intValue() != 200) {
|
|
|
+ throw new GuiguException(result.getCode(), result.getMessage());
|
|
|
}
|
|
|
}
|
|
|
- //3.TODO 核心业务3-如果交易类型是充值,远程调用账户服务完成充值业务
|
|
|
- if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(paymentType)) {
|
|
|
- Result result = accountFeignClient.rechargePaySuccess(orderNo);
|
|
|
- if (!result.getCode().equals(200)) {
|
|
|
- throw new RuntimeException("远程调用-充值异常");
|
|
|
+ //4.处理支付类型:1302充值 余额充值
|
|
|
+ if(SystemConstant.PAYMENT_TYPE_RECHARGE.equals(paymentType)){
|
|
|
+ //4.1 远程调用账户服务,修改充值状态,完车充值业务
|
|
|
+ Result result = accountFeignClient.rechargePaySuccess(orderNo);
|
|
|
+ if (result.getCode().intValue() != 200) {
|
|
|
+ throw new GuiguException(result.getCode(), result.getMessage());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -963,36 +967,44 @@ void orderPaySuccess(String orderNo);
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 用户付款成功后,处理订单相关业务
|
|
|
+ * 用户支付成功后,修改订单状态:已支付
|
|
|
*
|
|
|
* @param orderNo
|
|
|
- * @return
|
|
|
*/
|
|
|
@Override
|
|
|
public void orderPaySuccess(String orderNo) {
|
|
|
- //1.修改订单状态改为已支付
|
|
|
- OrderInfo orderInfo = this.getOrderInfo(orderNo);
|
|
|
- orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
|
|
|
- orderInfoMapper.updateById(orderInfo);
|
|
|
-
|
|
|
- //2.远程调用用户服务完成虚拟物品发货
|
|
|
- //2.1 构建虚拟物品发货VO对象
|
|
|
- UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
|
|
|
- userPaidRecordVo.setOrderNo(orderInfo.getOrderNo());
|
|
|
- userPaidRecordVo.setUserId(orderInfo.getUserId());
|
|
|
- //2.1.1 购买项目类型:付款项目类型: 1001-专辑 1002-声音 1003-vip会员'
|
|
|
- userPaidRecordVo.setItemType(orderInfo.getItemType());
|
|
|
- //2.1.2 从订单中获取订单明细得到购买项目ID列表
|
|
|
- List<OrderDetail> orderInfoOrderDetailList = orderInfo.getOrderDetailList();
|
|
|
- if (CollectionUtil.isNotEmpty(orderInfoOrderDetailList)) {
|
|
|
- List<Long> itemIdList = orderInfoOrderDetailList.stream().map(OrderDetail::getItemId).collect(Collectors.toList());
|
|
|
+ //1.根据订单编号查询订单状态
|
|
|
+ OrderInfo orderInfo = orderInfoMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<OrderInfo>()
|
|
|
+ .eq(OrderInfo::getOrderNo, orderNo)
|
|
|
+ );
|
|
|
+ //订单状态:0901-未支付 0902-已支付 0903-已取消
|
|
|
+ String orderStatus = orderInfo.getOrderStatus();
|
|
|
+ if (SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)) {
|
|
|
+ //2.如果订单状态是未支付:修改订单状态为已支付
|
|
|
+ orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
|
|
|
+ orderInfoMapper.updateById(orderInfo);
|
|
|
+
|
|
|
+ //3.远程调用"用户服务"虚拟物品发货
|
|
|
+ //3.1 构建虚拟物品发货vo对象
|
|
|
+ UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
|
|
|
+ userPaidRecordVo.setOrderNo(orderNo);
|
|
|
+ userPaidRecordVo.setUserId(orderInfo.getUserId());
|
|
|
+ userPaidRecordVo.setItemType(orderInfo.getItemType());
|
|
|
+ //查询订单明细得的购买项目ID列表
|
|
|
+ List<OrderDetail> orderDetailList = orderDetailService.list(
|
|
|
+ new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderInfo.getId())
|
|
|
+ .select(OrderDetail::getItemId)
|
|
|
+ );
|
|
|
+ List<Long> itemIdList = orderDetailList.stream().map(OrderDetail::getItemId).collect(Collectors.toList());
|
|
|
userPaidRecordVo.setItemIdList(itemIdList);
|
|
|
- //2.2 判断业务状态码
|
|
|
+ //3.2 执行远程调用,一定要判断调用业务状态码
|
|
|
Result result = userFeignClient.savePaidRecord(userPaidRecordVo);
|
|
|
- if (!result.getCode().equals(200)) {
|
|
|
- throw new RuntimeException("远程调用-虚拟物品发货异常");
|
|
|
+ if (result.getCode().intValue() != 200) {
|
|
|
+ throw new GuiguException(result.getCode(), result.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -1038,12 +1050,12 @@ public Result orderPaySuccess(String orderNo) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 保存充值记录
|
|
|
+ * 保存充值
|
|
|
* @param rechargeInfoVo
|
|
|
* @return {orderNo:"充值订单编号"}
|
|
|
*/
|
|
|
@GuiGuLogin
|
|
|
-@Operation(summary = "保存充值记录")
|
|
|
+@Operation(summary = "保存充值")
|
|
|
@PostMapping("/rechargeInfo/submitRecharge")
|
|
|
public Result<Map<String, String>> submitRecharge(@RequestBody RechargeInfoVo rechargeInfoVo){
|
|
|
Map<String, String> map = rechargeInfoService.submitRecharge(rechargeInfoVo);
|
|
@@ -1066,29 +1078,27 @@ Map<String, String> submitRecharge(RechargeInfoVo rechargeInfoVo);
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 保存充值记录
|
|
|
+ * 保存充值
|
|
|
*
|
|
|
* @param rechargeInfoVo
|
|
|
* @return {orderNo:"充值订单编号"}
|
|
|
*/
|
|
|
@Override
|
|
|
public Map<String, String> submitRecharge(RechargeInfoVo rechargeInfoVo) {
|
|
|
- //1.构建充值记录对象
|
|
|
RechargeInfo rechargeInfo = new RechargeInfo();
|
|
|
rechargeInfo.setUserId(AuthContextHolder.getUserId());
|
|
|
- rechargeInfo.setRechargeStatus(SystemConstant.ORDER_STATUS_UNPAID);
|
|
|
- rechargeInfo.setRechargeAmount(rechargeInfoVo.getAmount());
|
|
|
- rechargeInfo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);
|
|
|
- //生成充值订单编号 CZ+日期+雪花算法
|
|
|
+ //生成充值订单编号
|
|
|
String orderNo = "CZ" + DateUtil.today().replace("-", "") + IdUtil.getSnowflakeNextId();
|
|
|
rechargeInfo.setOrderNo(orderNo);
|
|
|
- //2.执行保存充值记录
|
|
|
+ rechargeInfo.setRechargeStatus(SystemConstant.ORDER_STATUS_UNPAID);
|
|
|
+ rechargeInfo.setRechargeAmount(rechargeInfoVo.getAmount());
|
|
|
+ rechargeInfo.setPayWay(rechargeInfoVo.getPayWay());
|
|
|
rechargeInfoMapper.insert(rechargeInfo);
|
|
|
- //3.封装响应对象中订单编号
|
|
|
+
|
|
|
+ //TODO 超时未支付充值订单关闭,RabbitMQ延迟消息
|
|
|
+
|
|
|
Map<String, String> map = new HashMap<>();
|
|
|
map.put("orderNo", orderNo);
|
|
|
-
|
|
|
- //4.TODO 发送延迟消息 延迟关闭充值记录
|
|
|
return map;
|
|
|
}
|
|
|
```
|
|
@@ -1107,16 +1117,15 @@ public Map<String, String> submitRecharge(RechargeInfoVo rechargeInfoVo) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 用户付款后处理充值成功业务
|
|
|
- *
|
|
|
+ * 微信支付成功后,处理充值业务
|
|
|
* @param orderNo
|
|
|
* @return
|
|
|
*/
|
|
|
-@Operation(summary = "用户付款后处理充值成功业务")
|
|
|
+@Operation(summary = "微信支付成功后,处理充值业务")
|
|
|
@GetMapping("/rechargeInfo/rechargePaySuccess/{orderNo}")
|
|
|
-public Result rechargePaySuccess(@PathVariable String orderNo) {
|
|
|
- rechargeInfoService.rechargePaySuccess(orderNo);
|
|
|
- return Result.ok();
|
|
|
+public Result rechargePaySuccess(@PathVariable String orderNo){
|
|
|
+ rechargeInfoService.rechargePaySuccess(orderNo);
|
|
|
+ return Result.ok();
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -1124,9 +1133,9 @@ public Result rechargePaySuccess(@PathVariable String orderNo) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 用户付款后处理充值成功业务
|
|
|
- *
|
|
|
+ * 微信支付成功后,处理充值业务
|
|
|
* @param orderNo
|
|
|
+ * @return
|
|
|
*/
|
|
|
void rechargePaySuccess(String orderNo);
|
|
|
```
|
|
@@ -1134,37 +1143,39 @@ void rechargePaySuccess(String orderNo);
|
|
|
**RechargeInfoServiceImpl实现**
|
|
|
|
|
|
```java
|
|
|
-@Autowired
|
|
|
-private UserAccountService userAccountService;
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
- * 用户付款后处理充值成功业务
|
|
|
+ * 微信支付成功后,处理充值业务
|
|
|
*
|
|
|
* @param orderNo
|
|
|
+ * @return
|
|
|
*/
|
|
|
@Override
|
|
|
public void rechargePaySuccess(String orderNo) {
|
|
|
- //1.修改充值状态
|
|
|
- //1.1. 根据充值订单编号查询充值记录
|
|
|
- LambdaQueryWrapper<RechargeInfo> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
- queryWrapper.eq(RechargeInfo::getOrderNo, orderNo);
|
|
|
- RechargeInfo rechargeInfo = rechargeInfoMapper.selectOne(queryWrapper);
|
|
|
-
|
|
|
- if (SystemConstant.ORDER_STATUS_UNPAID.equals(rechargeInfo.getRechargeStatus())) {
|
|
|
- //1.2 修改充值状态:已支付
|
|
|
+ //1.根据充值订单编号查询充值记录 判断状态是否为未支付
|
|
|
+ RechargeInfo rechargeInfo = rechargeInfoMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<RechargeInfo>()
|
|
|
+ .eq(RechargeInfo::getOrderNo, orderNo)
|
|
|
+ );
|
|
|
+ String rechargeStatus = rechargeInfo.getRechargeStatus();
|
|
|
+ if (SystemConstant.ORDER_STATUS_UNPAID.equals(rechargeStatus)) {
|
|
|
+ //2.更新充值记录:已支付
|
|
|
rechargeInfo.setRechargeStatus(SystemConstant.ORDER_STATUS_PAID);
|
|
|
rechargeInfoMapper.updateById(rechargeInfo);
|
|
|
-
|
|
|
- //2.余额充值
|
|
|
- LambdaUpdateWrapper<UserAccount> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
+ //3.充值,对总金额、可用金额增加
|
|
|
BigDecimal amount = rechargeInfo.getRechargeAmount();
|
|
|
- updateWrapper.setSql("total_amount = total_amount + " + amount + ", available_amount = available_amount + " + amount + ", total_income_amount = total_income_amount + " + amount);
|
|
|
- updateWrapper.eq(UserAccount::getUserId, rechargeInfo.getUserId());
|
|
|
- userAccountService.update(updateWrapper);
|
|
|
-
|
|
|
- //3.新增账户变动日志
|
|
|
- userAccountService.saveUserAccountDetail(rechargeInfo.getUserId(), "充值:" + amount, SystemConstant.ACCOUNT_TRADE_TYPE_DEPOSIT, amount, orderNo);
|
|
|
+ boolean flag = userAccountService.update(
|
|
|
+ null,
|
|
|
+ new LambdaUpdateWrapper<UserAccount>()
|
|
|
+ .setSql("total_amount = total_amount +" + amount)
|
|
|
+ .setSql("available_amount = available_amount +" + amount)
|
|
|
+ .setSql("total_income_amount = total_income_amount +" + amount)
|
|
|
+ .eq(UserAccount::getUserId, rechargeInfo.getUserId())
|
|
|
+ );
|
|
|
+ if (!flag) {
|
|
|
+ throw new GuiguException(500, "充值失败!");
|
|
|
+ }
|
|
|
+ //4.新增账户变动日志
|
|
|
+ userAccountService.saveUserAccountDetail(rechargeInfo.getUserId(), "充值", SystemConstant.ACCOUNT_TRADE_TYPE_DEPOSIT, amount, orderNo);
|
|
|
}
|
|
|
}
|
|
|
```
|
|
@@ -1177,7 +1188,7 @@ public void rechargePaySuccess(String orderNo) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 用户付款后处理充值成功业务
|
|
|
+ * 微信支付成功后,处理充值业务
|
|
|
* @param orderNo
|
|
|
* @return
|
|
|
*/
|