Browse Source

支付服务添加回调接口

feature-1.1
wuxicheng 3 years ago
parent
commit
f5e72cc6b2
  1. 22
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/PayInfo.java
  2. 2
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayStatus.java
  3. 8
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/exception/ServiceException.java
  4. 2
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/utils/DateUtils.java
  5. 2
      bnyer-common/bnyer-common-redis/src/main/java/com/bnyer/common/redis/service/RedisService.java
  6. 7
      bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/config/RocketMqConstant.java
  7. 6
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/config/RocketMqConfig.java
  8. 2
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/controller/VipOrderController.java
  9. 84
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPayNotifyConsumer.java
  10. 18
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPaySuccessConsumer.java
  11. 8
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/mapper/VipOrderMapper.java
  12. 4
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java
  13. 11
      bnyer-services/bnyer-order/src/main/resources/com/bnyer/order/mapper/VipOrderMapper.xml
  14. 4
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/config/RocketMqConfig.java
  15. 36
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/AliPayController.java
  16. 4
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayInfoController.java
  17. 14
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/WxPayController.java
  18. 6
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/factory/PayFactory.java
  19. 83
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AbstractPayStrategy.java
  20. 97
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AliPayStrategy.java
  21. 40
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/IPayStrategy.java
  22. 32
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/PayStrategy.java
  23. 87
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java
  24. 37
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/EditPayInfoNotifyDto.java
  25. 32
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/PayNotifyCheckDto.java
  26. 22
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/WxPayManager.java
  27. 8
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/mapper/PayInfoMapper.java
  28. 8
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java
  29. 71
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java
  30. 71
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/WXPayUtil.java
  31. 15
      bnyer-services/bnyer-pay/src/main/resources/com/bnyer/pay/mapper/PayInfoMapper.xml

22
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/PayInfo.java

@ -57,6 +57,21 @@ public class PayInfo extends BaseDomain {
@ApiModelProperty(value="支付状态:1000未支付;1001支付成功 ;1002支付失败")
private Integer payStatus;
/**
* 单笔对账状态1001 对账成功
*/
@TableField(value = "single_status")
@ApiModelProperty(value="单笔对账状态:1001 对账成功")
private Integer singleStatus;
/**
* 单笔对账时间
*/
@TableField(value = "single_time")
@ApiModelProperty(value="单笔对账时间")
private Date singleTime;
/**
* 支付类型wxpay/alipay
*/
@ -64,6 +79,13 @@ public class PayInfo extends BaseDomain {
@ApiModelProperty(value="支付类型:wxpay/alipay")
private String payType;
/**
* 交易类型JSAPI等
*/
@TableField(value = "trade_type")
@ApiModelProperty(value = "交易类型:JSAPI等")
private String tradeType;
/**
* 支付单号(第三方返回)
*/

2
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumPayStatus.java → bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayStatus.java

@ -1,4 +1,4 @@
package com.bnyer.pay.enums;
package com.bnyer.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;

8
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/exception/ServiceException.java

@ -49,12 +49,12 @@ public final class ServiceException extends RuntimeException
this.code = code;
}
public ServiceException(Integer code, String... params) {
this.code = code;
public ServiceException(ResponseEnum responseEnum,String... params) {
this.code = responseEnum.getCode();
if (StringUtils.isNotEmpty(params)){
this.message = StringUtils.join(params,",") + ResponseEnum.getCodeMsg(code);
this.message = StringUtils.join(params,",") + responseEnum.getMsg();
}else {
this.message = ResponseEnum.getCodeMsg(code);
this.message = responseEnum.getMsg();
}
}

2
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/utils/DateUtils.java

@ -226,7 +226,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
break;
}
default:
throw new ServiceException(ResponseEnum.PARAM_ERROR.getCode());
throw new ServiceException(ResponseEnum.PARAM_ERROR);
}
return DateUtils.parseDate(format);
}

2
bnyer-common/bnyer-common-redis/src/main/java/com/bnyer/common/redis/service/RedisService.java

@ -356,7 +356,7 @@ public class RedisService
public boolean cad(String key, String value) {
if (key.contains(StrUtil.SPACE) || value.contains(StrUtil.SPACE)) {
throw new ServiceException(ResponseEnum.SERVER_ERROR.getCode());
throw new ServiceException(ResponseEnum.SERVER_ERROR);
}
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

7
bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/config/RocketMqConstant.java

@ -35,6 +35,11 @@ public class RocketMqConstant {
/**
* vip订单支付成功
*/
public static final String VIP_ORDER_PAY_SUCCESS_TOPIC = "vip-order-pay-success-topic";
public static final String VIP_ORDER_PAY_NOTIFY_TOPIC = "vip-order-pay-notify-topic";
/**
* 添加vip记录
*/
public static final String VIP_RECORD_CREATE_TOPIC = "vip-record-create-topic";
}

6
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/config/RocketMqConfig.java

@ -25,4 +25,10 @@ public class RocketMqConfig {
public RocketMQTemplate orderCancelMqTemplate() {
return rocketMqAdapter.getTemplateByTopicName(RocketMqConstant.VIP_ORDER_CANCEL_TOPIC);
}
@Lazy
@Bean(destroyMethod = "destroy")
public RocketMQTemplate vipRecordMqTemplate() {
return rocketMqAdapter.getTemplateByTopicName(RocketMqConstant.VIP_RECORD_CREATE_TOPIC);
}
}

2
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/controller/VipOrderController.java

@ -22,7 +22,7 @@ import java.util.List;
*/
@Api(value = "会员订单相关接口",tags = "会员订单相关接口")
@RestController
@RequestMapping("/order/vip")
@RequestMapping("/vip")
@Slf4j
public class VipOrderController extends BaseController {

84
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPayNotifyConsumer.java

@ -0,0 +1,84 @@
package com.bnyer.order.listener.vip;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.domain.VipOrder;
import com.bnyer.common.core.enums.EnumPayStatus;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.rocketmq.config.RocketMqConstant;
import com.bnyer.order.enums.EnumVipOrderStatus;
import com.bnyer.order.mapper.VipOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;
/**
* @author :WXC
* @Date :2023/03/24
* @description :订单支付回调mq消费监听
*/
@Slf4j
@Component
@RocketMQMessageListener(topic = RocketMqConstant.VIP_ORDER_PAY_NOTIFY_TOPIC,consumerGroup = RocketMqConstant.VIP_ORDER_PAY_NOTIFY_TOPIC)
public class VipOrderPayNotifyConsumer implements RocketMQListener<String> {
@Resource
private VipOrderMapper vipOrderMapper;
@Resource
private RocketMQTemplate vipRecordMqTemplate;
@Override
public void onMessage(String message) {
log.info("收到消息:{}", message);
JSONObject jsonObject = JSON.parseObject(message);
//修改订单表状态为已支付
String orderId = jsonObject.getString("orderId");
VipOrder vipOrder = vipOrderMapper.selectOne(new LambdaQueryWrapper<VipOrder>().eq(VipOrder::getOrderId, orderId));
if (Objects.isNull(vipOrder)){
log.error("订单不存在,订单id:{}",orderId);
return;
}
vipOrder.setPayStatus(EnumPayStatus.SUCCESS.getCode());
vipOrder.setOrderStatus(EnumVipOrderStatus.SUCCESS.getStatus());
vipOrder.setUpdateTime(new Date());
vipOrder.setPayTime(new Date());
vipOrderMapper.updateById(vipOrder);
// TODO: 2023/04/13 发消息到img服务创建vip记录开通会员
String msg = buildVipRecordMsg(vipOrder);
SendStatus sendStatus = vipRecordMqTemplate.syncSend(RocketMqConstant.VIP_RECORD_CREATE_TOPIC, new GenericMessage<>(msg)).getSendStatus();
if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
// 消息发不出去就抛异常
throw new ServiceException(ResponseEnum.SERVER_ERROR);
}
}
/**
* 构建vip记录消息体
* @param vipOrder
* @return
*/
private String buildVipRecordMsg(VipOrder vipOrder) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("orderId",vipOrder.getOrderId());
jsonObject.put("startTime",vipOrder.getStartTime());
jsonObject.put("endTime",vipOrder.getEndTime());
jsonObject.put("vipId",vipOrder.getVipId());
jsonObject.put("vipName",vipOrder.getVipName());
jsonObject.put("vipTypeName",vipOrder.getVipTypeName());
jsonObject.put("categoryName",vipOrder.getCategoryName());
jsonObject.put("phone",vipOrder.getPhone());
jsonObject.put("userId",vipOrder.getUserId());
return JSON.toJSONString(jsonObject);
}
}

18
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPaySuccessConsumer.java

@ -1,18 +0,0 @@
//package com.bnyer.order.listener.vip;
//
//import com.bnyer.common.rocketmq.config.RocketMqConstant;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
//import org.springframework.stereotype.Component;
//
///**
// * @author :WXC
// * @Date :2023/03/24
// * @description :订单支付成功mq消费监听
// */
//@Slf4j
//@Component
//@RocketMQMessageListener(topic = RocketMqConstant.VIP_ORDER_PAY_SUCCESS_TOPIC,consumerGroup = RocketMqConstant.VIP_ORDER_PAY_SUCCESS_TOPIC)
//public class VipOrderPaySuccessConsumer {
//
//}

8
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/mapper/VipOrderMapper.java

@ -26,5 +26,11 @@ public interface VipOrderMapper extends BaseMapper<VipOrder> {
* 取消订单
* @param orderIds
*/
void cancelVipOrder(@Param("orderIds") List<String> orderIds, @Param("close_type") Integer close_type);
void cancelVipOrder(@Param("orderIds") List<String> orderIds, @Param("closeType") Integer closeType);
/**
* 修改订单表状态为已支付
* @param orderId
*/
void updateByToPaySuccess(@Param("orderId") String orderId);
}

4
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java

@ -86,7 +86,7 @@ public class VipOrderServiceImpl extends ServiceImpl<VipOrderMapper, VipOrder> i
SendStatus sendStatus = orderCancelMqTemplate.syncSend(RocketMqConstant.VIP_ORDER_CANCEL_TOPIC, new GenericMessage<>(orderId), RocketMqConstant.TIMEOUT, RocketMqConstant.CANCEL_ORDER_DELAY_LEVEL).getSendStatus();
if (!Objects.equals(sendStatus,SendStatus.SEND_OK)) {
// 消息发不出去就抛异常,发的出去无所谓
throw new ServiceException(ResponseEnum.SERVER_ERROR.getCode());
throw new ServiceException(ResponseEnum.SERVER_ERROR);
}else {
log.info("消息发送成功,topic:{}",RocketMqConstant.VIP_ORDER_CANCEL_TOPIC);
}
@ -109,7 +109,7 @@ public class VipOrderServiceImpl extends ServiceImpl<VipOrderMapper, VipOrder> i
}
List<UserVipVo> userVipVoList = userVipVoListResult.getData();
if (CollUtil.isEmpty(userVipVoList)){
throw new ServiceException(ResponseEnum.NOT_EXIST.getCode(),"会员信息");
throw new ServiceException(ResponseEnum.NOT_EXIST,"会员信息");
}
UserVipVo userVipVo = userVipVoList.get(0);
VipOrder vipOrder = null;

11
bnyer-services/bnyer-order/src/main/resources/com/bnyer/order/mapper/VipOrderMapper.xml

@ -76,7 +76,7 @@
update order_vip_order
set
order_status = 2,
close_type = #{close_type,jdbcType=VARCHAR},
close_type = #{closeType,jdbcType=VARCHAR},
cancel_time = now(),
update_time=now()
where pay_status = 1000 and order_id in
@ -84,4 +84,13 @@
#{orderId}
</foreach>
</update>
<update id="updateByToPaySuccess">
update order_vip_order
set
order_status = 1,
pay_status = 1001,
pay_time = now(),
update_time = now()
where order_id = #{orderId}
</update>
</mapper>

4
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/config/RocketMqConfig.java

@ -22,7 +22,7 @@ public class RocketMqConfig {
@Lazy
@Bean(destroyMethod = "destroy")
public RocketMQTemplate orderPaySuccessMqTemplate() {
return rocketMqAdapter.getTemplateByTopicName(RocketMqConstant.VIP_ORDER_PAY_SUCCESS_TOPIC);
public RocketMQTemplate vipOrderPayNotifyMqTemplate() {
return rocketMqAdapter.getTemplateByTopicName(RocketMqConstant.VIP_ORDER_PAY_NOTIFY_TOPIC);
}
}

36
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/AliPayController.java

@ -1,14 +1,18 @@
package com.bnyer.pay.controller;
import com.bnyer.common.core.domain.R;
import com.bnyer.pay.dto.AliPayInOrderDto;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.pay.design.factory.PayFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @author :WXC
@ -17,8 +21,28 @@ import javax.validation.Valid;
*/
@Api(value = "支付宝支付相关接口",tags = "支付宝支付相关接口")
@RestController
@RequestMapping("/pay/ali")
@Slf4j
public class AliPayController {
@ApiOperation(value="支付宝支付回调")
@PostMapping("/alipayBack")
public String alipayBack(ServletRequest arg0){
log.info("=======================alipayBack====================");
HttpServletRequest req = (HttpServletRequest)arg0;
Map<String,String> inMap = new HashMap<>();
Map<String, String[]> requestParams = req.getParameterMap();
for (String name : requestParams.keySet()) {
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
//乱码解决
valueStr = new String(valueStr.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
inMap.put(name, valueStr);
}
System.out.println("====================alipayBack:"+inMap);
return PayFactory.getInstance().getConcreteStrategy(EnumPayType.ALI_PAY.getType()).parsePayNotify(inMap.toString());
}
}

4
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayController.java → bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayInfoController.java

@ -23,9 +23,9 @@ import javax.validation.Valid;
*/
@Api(value = "支付订单相关接口",tags = "支付订单相关接口")
@RestController
@RequestMapping("/pay/order")
@RequestMapping("/payinfo")
@Slf4j
public class PayController {
public class PayInfoController {
@Autowired
private PayInfoService payInfoService;

14
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/WxPayController.java

@ -1,8 +1,13 @@
package com.bnyer.pay.controller;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.pay.design.factory.PayFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
@ -12,8 +17,13 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Api(value = "微信支付相关接口",tags = "微信支付相关接口")
@RestController
@RequestMapping("/pay/wx")
@Slf4j
public class WxPayController {
@ApiOperation(value="微信支付回调")
@PostMapping("/wxpayBack")
public @ResponseBody String wxpayBack(@RequestBody String inXml) {
log.info("====================wxpayBack=========");
return PayFactory.getInstance().getConcreteStrategy(EnumPayType.WX_PAY.getType()).parsePayNotify(inXml);
}
}

6
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/factory/PayFactory.java

@ -2,7 +2,7 @@ package com.bnyer.pay.design.factory;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.pay.design.strategy.AliPayStrategy;
import com.bnyer.pay.design.strategy.PayStrategy;
import com.bnyer.pay.design.strategy.IPayStrategy;
import com.bnyer.pay.design.strategy.WxPayStrategy;
import com.google.common.collect.ImmutableMap;
@ -14,7 +14,7 @@ import java.util.Map;
* @description :支付工厂
*/
public class PayFactory {
private static final Map<String, PayStrategy> strategyMap = new ImmutableMap.Builder<String, PayStrategy>()
private static final Map<String, IPayStrategy> strategyMap = new ImmutableMap.Builder<String, IPayStrategy>()
.put(EnumPayType.ALI_PAY.getType(),new AliPayStrategy())
.put(EnumPayType.WX_PAY.getType(),new WxPayStrategy())
.build();
@ -27,7 +27,7 @@ public class PayFactory {
return SingletonHolder.payStrategy;
}
public PayStrategy getConcreteStrategy(String payType){
public IPayStrategy getConcreteStrategy(String payType){
return PayFactory.strategyMap.get(payType);
}

83
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AbstractPayStrategy.java

@ -0,0 +1,83 @@
package com.bnyer.pay.design.strategy;
import com.alibaba.fastjson.JSON;
import com.alipay.api.msg.MsgConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.domain.PayInfo;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.pay.dto.PayNotifyCheckDto;
import com.bnyer.pay.mapper.PayInfoMapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
import java.util.Objects;
/**
* @author :WXC
* @Date :2023/04/12
* @description :提供公共的方法
*/
@Slf4j
public abstract class AbstractPayStrategy implements IPayStrategy {
@Resource
private PayInfoMapper payInfoMapper;
public <T> T payNotify(Object o,Class<T> tClass,EnumPayType payType){
String string = "";
if (EnumPayType.ALI_PAY == payType){
string = o.toString();
}else if (EnumPayType.WX_PAY == payType){
}
return JSON.parseObject(string,tClass);
}
/**
* 校验是否已支付避免重复调用
* @param checkDto
* @return
*/
public String payNotifyCheck(PayNotifyCheckDto checkDto){
String resultMsg = "";
PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayId, checkDto.getPayId()).eq(PayInfo::getIsShow, "1"));
if (Objects.isNull(payInfo)){
return WxPayNotifyResponse.fail("查询支付订单信息不存在");
}
log.info("查询到支付订单信息为:{}", JSON.toJSONString(payInfo));
//订单中的金额
String payInfoPayAmount = payInfo.getPayAmount().toString();
//回调中的金额
String notifyPayAmount = checkDto.getPayAmount();
//对账状态
Integer singleStatus = payInfo.getSingleStatus();
log.info("回调中的金额:{},订单中的金额:{}",payInfoPayAmount,notifyPayAmount);
if (payInfoPayAmount.equals(notifyPayAmount)){
if (Objects.nonNull(singleStatus)){
resultMsg = buildNotifyCheckResultMsg(checkDto.getPayType(),true,"OK");
}
}else {
resultMsg = buildNotifyCheckResultMsg(checkDto.getPayType(),false,"Amount_Diff");
}
return resultMsg;
}
/**
* 构建校验后回调返回结果信息
* @param payType 支付方式
* @param isSuccess 是否构建成功消息
* @param msg 消息内容
* @return
*/
private String buildNotifyCheckResultMsg(EnumPayType payType,boolean isSuccess,String msg){
String result = "";
if (EnumPayType.WX_PAY == payType){
result = isSuccess?WxPayNotifyResponse.success(msg):WxPayNotifyResponse.fail(msg);
}else if (EnumPayType.ALI_PAY == payType){
result = isSuccess?MsgConstants.SUCCESS:MsgConstants.FAIL;
}
return result;
}
}

97
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AliPayStrategy.java

@ -2,27 +2,42 @@ package com.bnyer.pay.design.strategy;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.msg.MsgConstants;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.domain.AlipayConfig;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.DateUtils;
import com.bnyer.common.core.utils.SpringUtils;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.pay.constant.AliPayConstant;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.PayNotifyCheckDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.mapper.AlipayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.vo.PayInOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author :WXC
@ -31,14 +46,18 @@ import java.util.List;
*/
@Slf4j
@Component
public class AliPayStrategy implements PayStrategy{
public class AliPayStrategy extends AbstractPayStrategy {
@Resource
private AlipayConfigMapper alipayConfigMapper;
@Transactional(propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
@Override
public PayInOrderVo unifiedOrder(UnifiedOrderDto dto) {
AlipayConfigMapper alipayConfigMapper = SpringUtils.getBean(AlipayConfigMapper.class);
log.info("支付宝支付:统一下单接口调用开始,AliPayStrategy.unifiedOrder dto:{}", JSON.toJSONString(dto));
List<AlipayConfig> alipayConfigList = alipayConfigMapper.selectList(new LambdaQueryWrapper<AlipayConfig>().eq(AlipayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(alipayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR.getCode());
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
AlipayConfig alipayConfig = alipayConfigList.get(0);
String appid = alipayConfig.getAppid();
@ -77,8 +96,78 @@ public class AliPayStrategy implements PayStrategy{
} catch (Exception e) {
e.printStackTrace();
log.error("支付宝下单接口调用失败,error:{}",e.getMessage());
throw new ServiceException(ResponseEnum.PAY_FAILS.getCode());
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
}
@Transactional(propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
@Override
public String parsePayNotify(String params) {
Map<String, String> inMap = JSON.parseObject(params, new TypeReference<HashMap<String, String>>() {});
log.info("支付宝支付回调开始: AliPayStrategy.parsePayNotify inMap:{}",JSON.toJSONString(inMap));
PayInfoService payInfoService = SpringUtils.getBean(PayInfoService.class);
try{
//--------------------------1.解析并拿到参数---------------------
String appId = inMap.get("app_id");
//支付订单号
String tradeNo = inMap.get("trade_no");
//支付流水号
String outTradeNo = inMap.get("out_trade_no");
//交易状态:TRADE_FINISHED,TRADE_SUCCESS,TRADE_CLOSED
String tradeStatus = inMap.get("trade_status");
//交易付款时间
String gmtPayment = inMap.get("gmt_payment");
//交易退款时间
String gmtRefund = inMap.get("gmt_refund");
//订单金额(元)
String totalAmount = inMap.get("total_amount");
//通过appid查询配置的密钥:用于校验签名
List<AlipayConfig> alipayConfigList = alipayConfigMapper.selectList(new LambdaQueryWrapper<AlipayConfig>()
.eq(AlipayConfig::getAppid,appId).eq(AlipayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(alipayConfigList)){
log.error(ResponseEnum.PAY_CONFIG_ERROR.getMsg());
return MsgConstants.FAIL;
}
AlipayConfig alipayConfig = alipayConfigList.get(0);
//-----------------------2.签名校验---------------------------
String alipayPublicKey = alipayConfig.getAlipayPublicKey();
boolean flag = AlipaySignature.rsaCheckV1(inMap, alipayPublicKey, AlipayConstants.CHARSET_UTF8,AlipayConstants.SIGN_TYPE_RSA2);
if(!flag){
log.error("支付宝支付回调:签名校验失败");
return MsgConstants.FAIL;
}
log.info("支付宝支付回调:签名校验成功");
//交易完成、成功
if(tradeStatus.equals("TRADE_FINISHED") || tradeStatus.equals("TRADE_SUCCESS")){
PayNotifyCheckDto payNotifyCheckDto = new PayNotifyCheckDto();
payNotifyCheckDto.setPayType(EnumPayType.ALI_PAY);
payNotifyCheckDto.setPayId(tradeNo);
payNotifyCheckDto.setPayAmount(totalAmount);
String notifyCheckResult = super.payNotifyCheck(payNotifyCheckDto);
if (StringUtils.isNotBlank(notifyCheckResult)){
return notifyCheckResult;
}
log.info("支付宝支付回调,交易正常:封装参数修改内部支付单信息");
//时间处理
gmtPayment = gmtPayment.replaceAll(" ", "").replaceAll("-", "").replaceAll(":", "");
EditPayInfoNotifyDto editPayInfoNotifyDto = new EditPayInfoNotifyDto();
editPayInfoNotifyDto.setPayId(outTradeNo);
editPayInfoNotifyDto.setPayTime(gmtPayment);
editPayInfoNotifyDto.setPayAmount(totalAmount);
editPayInfoNotifyDto.setPayNo(tradeNo);
editPayInfoNotifyDto.setAppId(appId);
editPayInfoNotifyDto.setPayType(EnumPayType.ALI_PAY.getType());
payInfoService.editPayInfoNotify(editPayInfoNotifyDto);
}else if(tradeStatus.equals("TRADE_CLOSED")){
log.info("支付宝支付回调:TRADE_CLOSED 状态不做处理");
//交易关闭不作处理:退款或未支付超时关闭
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}catch (Exception e){
log.info("支付宝支付回调:处理过程异常,error:{}",e.getMessage());
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return MsgConstants.SUCCESS;
}

40
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/IPayStrategy.java

@ -0,0 +1,40 @@
package com.bnyer.pay.design.strategy;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.vo.PayInOrderVo;
/**
* @author :WXC
* @Date :2023/04/03
* @description :支付策略
*/
public interface IPayStrategy {
/**
* 统一下单
* @param dto
* @return
*/
PayInOrderVo unifiedOrder(UnifiedOrderDto dto);
/**
* 支付回调处理
* 满足支付成功需要几个条件
* 1.回调到pay服务时要保证修改支付状态payStatus为1001对账状态singStatus为1001
* 2.pay服务处理完以后发送消息到order服务修改order表订单状态orderStatus为1支付状态payStatus为1001
*
* 如果pay服务发送消息失败可利用第三方支付回调的重试机制多次发送如果order服务消费失败可利用mq重试机制重试消费重试多次还是失败就人工处理该订单
* @param params
* @return
*/
String parsePayNotify(String params);
//===========待完成================
// TODO: 2023/04/03 订单查询
// void orderQuery();
// TODO: 2023/04/03 退款
// void refund();
// TODO: 2023/04/03 退款查询
// void refundQuery();
}

32
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/PayStrategy.java

@ -1,32 +0,0 @@
package com.bnyer.pay.design.strategy;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.vo.PayInOrderVo;
/**
* @author :WXC
* @Date :2023/04/03
* @description :支付策略
*/
public interface PayStrategy {
/**
* 统一下单
* @param dto
* @return
*/
PayInOrderVo unifiedOrder(UnifiedOrderDto dto);
//===========待完成================
// TODO: 2023/04/03 回调处理
// void parsePayNotify();
// TODO: 2023/04/03 订单查询
// void orderQuery();
// TODO: 2023/04/03 退款
// void refund();
// TODO: 2023/04/03 退款查询
// void refundQuery();
}

87
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java

@ -1,21 +1,45 @@
package com.bnyer.pay.design.strategy;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.msg.MsgConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.domain.AlipayConfig;
import com.bnyer.common.core.domain.WxpayConfig;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.SpringUtils;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.PayNotifyCheckDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.enums.EnumTradeType;
import com.bnyer.pay.manager.WxPayManager;
import com.bnyer.pay.mapper.WxpayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.utils.WXPayUtil;
import com.bnyer.pay.vo.PayInOrderVo;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author :WXC
@ -24,7 +48,7 @@ import org.springframework.stereotype.Component;
*/
@Slf4j
@Component
public class WxPayStrategy implements PayStrategy {
public class WxPayStrategy extends AbstractPayStrategy {
@Autowired
private WxPayManager wxPayManager;
@ -52,7 +76,7 @@ public class WxPayStrategy implements PayStrategy {
* @return
*/
private PayInOrderVo jsApiPay(UnifiedOrderDto dto) {
WxpayConfig wxPayConfig = wxPayManager.getWxPayConfig(dto.getTradeType());
WxpayConfig wxPayConfig = wxPayManager.getWxPayConfigByTradeType(dto.getTradeType());
WxPayService wxPayService = wxPayManager.getWxPayService(wxPayConfig);
try {
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
@ -80,7 +104,64 @@ public class WxPayStrategy implements PayStrategy {
return payInOrderVo;
} catch (WxPayException e) {
log.error("微信支付:统一下单接口调用失败,orderId:{},error{}", dto.getOrderId(), e.getMessage());
throw new ServiceException(ResponseEnum.PAY_FAILS.getCode());
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
}
/**
* 支付回调处理
* @param params
* @return
*/
@Override
public String parsePayNotify(String params) {
log.info("微信支付回调开始: WxPayStrategy.parsePayNotify params:{}",params);
PayInfoService payInfoService = SpringUtils.getBean(PayInfoService.class);
Map<String, String> inMap = null;
try {
inMap = WXPayUtil.xmlToMap(params);
} catch (Exception e) {
log.error("微信支付回调结果异常,异常原因{}", e.getMessage());
return WxPayNotifyResponse.fail(e.getMessage());
}
log.info("微信支付回调开始: WxPayStrategy.parsePayNotify inMap:{}",JSON.toJSONString(inMap));
WxpayConfig wxpayConfig = wxPayManager.getWxPayConfigByAppId(inMap.get("appid"));
WxPayService wxPayService = wxPayManager.getWxPayService(wxpayConfig);
try {
//解析支付结果通知
WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(params);
//appid
String appid = result.getAppid();
//支付订单号
String outTradeNo = result.getOutTradeNo();
//微信支付流水号
String transactionId = result.getTransactionId();
//支付金额
String fenToYuan = BaseWxPayResult.fenToYuan(result.getTotalFee());
//支付时间
String timeEnd = result.getTimeEnd();
//校验是否已支付避免重复调用
PayNotifyCheckDto payNotifyCheckDto = new PayNotifyCheckDto();
payNotifyCheckDto.setPayType(EnumPayType.WX_PAY);
payNotifyCheckDto.setPayId(outTradeNo);
payNotifyCheckDto.setPayAmount(fenToYuan);
String notifyCheck = super.payNotifyCheck(payNotifyCheckDto);
if (StringUtils.isNotBlank(notifyCheck)){
return notifyCheck;
}
log.info("微信支付回调,交易正常:封装参数修改内部支付单信息");
EditPayInfoNotifyDto editPayInfoNotifyDto = new EditPayInfoNotifyDto();
editPayInfoNotifyDto.setPayAmount(fenToYuan);
editPayInfoNotifyDto.setPayTime(timeEnd);
editPayInfoNotifyDto.setAppId(appid);
editPayInfoNotifyDto.setPayId(outTradeNo);
editPayInfoNotifyDto.setPayNo(transactionId);
payInfoService.editPayInfoNotify(editPayInfoNotifyDto);
return WxPayNotifyResponse.success("OK");
} catch (Exception e) {
log.error("微信支付回调结果异常,异常原因{}", e.getMessage());
return WxPayNotifyResponse.fail(e.getMessage());
}
}
}

37
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/EditPayInfoNotifyDto.java

@ -0,0 +1,37 @@
package com.bnyer.pay.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author :WXC
* @Date :2023/04/10
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class EditPayInfoNotifyDto {
//appid
private String appId;
//支付号
private String payNo;
//业务系统支付订单号
private String payId;
//交易状态:TRADE_FINISHED,TRADE_SUCCESS,TRADE_CLOSED
private String tradeStatus;
//交易付款时间
private String payTime;
//交易退款时间
private String refundTime;
//订单金额(元)
private String payAmount;
//支付类型
private String payType;
}

32
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/PayNotifyCheckDto.java

@ -0,0 +1,32 @@
package com.bnyer.pay.dto;
import com.bnyer.common.core.enums.EnumPayType;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author :WXC
* @Date :2023/04/13
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class PayNotifyCheckDto {
/**
* 支付方式
*/
private EnumPayType payType;
/**
* 支付单号
*/
private String payId;
/**
* 支付金额
*/
private String payAmount;
}

22
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/WxPayManager.java

@ -12,6 +12,7 @@ import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Objects;
@ -24,16 +25,31 @@ import java.util.Objects;
@Component
public class WxPayManager {
@Autowired
private WxpayConfigMapper wxpayConfigMapper;
/**
* 获取支付配置
* @return
*/
public WxpayConfig getWxPayConfig(String tradeType){
WxpayConfigMapper wxpayConfigMapper = SpringUtils.getBean(WxpayConfigMapper.class);
public WxpayConfig getWxPayConfigByTradeType(String tradeType){
//查询数据库配置:appId,mchId,key,backUrl等
WxpayConfig wxpayConfig = wxpayConfigMapper.selectOne(new LambdaQueryWrapper<WxpayConfig>().eq(WxpayConfig::getTradeType,tradeType).eq(WxpayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (Objects.isNull(wxpayConfig)) {
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR.getCode());
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
return wxpayConfig;
}
/**
* 获取支付配置
* @return
*/
public WxpayConfig getWxPayConfigByAppId(String appId){
//查询数据库配置:appId,mchId,key,backUrl等
WxpayConfig wxpayConfig = wxpayConfigMapper.selectOne(new LambdaQueryWrapper<WxpayConfig>().eq(WxpayConfig::getAppid,appId).eq(WxpayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (Objects.isNull(wxpayConfig)) {
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
return wxpayConfig;
}

8
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/mapper/PayInfoMapper.java

@ -3,6 +3,7 @@ package com.bnyer.pay.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bnyer.common.core.domain.PayInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* @author :WXC
@ -10,4 +11,11 @@ import org.apache.ibatis.annotations.Mapper;
*/
@Mapper
public interface PayInfoMapper extends BaseMapper<PayInfo> {
/**
* 修改支付订单状态和对账信息
* @param payId
* @param payNo
* @return
*/
int editPayInfoForSingle(@Param("payId") String payId, @Param("payTime") String payTime, @Param("payNo") String payNo);
}

8
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java

@ -3,6 +3,7 @@ package com.bnyer.pay.service;
import com.bnyer.common.core.domain.PayInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bnyer.pay.dto.AddPayInfoDto;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.vo.PayInOrderVo;
import javax.servlet.http.HttpServletRequest;
@ -19,4 +20,11 @@ public interface PayInfoService extends IService<PayInfo>{
* @return
*/
PayInOrderVo addPayInOrder(AddPayInfoDto dto, HttpServletRequest request);
/**
* 修改支付单并发消息到订单系统修改订单状态
* @param editPayInfoNotifyDto
*/
void editPayInfoNotify(EditPayInfoNotifyDto editPayInfoNotifyDto);
}

71
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java

@ -1,42 +1,59 @@
package com.bnyer.pay.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bnyer.common.core.context.SecurityContextHolder;
import com.bnyer.common.core.domain.PayInfo;
import com.bnyer.common.core.domain.R;
import com.bnyer.common.core.enums.EnumSceneCode;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.bean.EntityConvertUtil;
import com.bnyer.common.core.utils.ip.IpUtils;
import com.bnyer.common.rocketmq.config.RocketMqConstant;
import com.bnyer.img.api.dto.QueryVipOrderDto;
import com.bnyer.img.api.remote.RemoteVipOrderService;
import com.bnyer.img.api.vo.VipOrderVo;
import com.bnyer.pay.design.factory.PayFactory;
import com.bnyer.pay.design.strategy.IPayStrategy;
import com.bnyer.pay.dto.AddPayInfoDto;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.enums.EnumPayStatus;
import com.bnyer.pay.mapper.PayInfoMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.design.factory.PayFactory;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.pay.design.strategy.PayStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* @author :WXC
* @description :
*/
@Slf4j
@Service
public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> implements PayInfoService {
@Autowired
private PayInfoMapper payInfoMapper;
@Autowired
private RocketMQTemplate vipOrderPayNotifyMqTemplate;
@Autowired
private RemoteVipOrderService remoteVipOrderService;
@ -70,8 +87,8 @@ public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> impl
//构建统一下单请求实体
UnifiedOrderDto unifiedOrderDto = buildUnifiedOrderDto(dto, payAmount, request);
//下单,获取第三方返回信息
PayStrategy payStrategy = PayFactory.getInstance().getConcreteStrategy(dto.getPayType());
PayInOrderVo payInOrderVo = payStrategy.unifiedOrder(unifiedOrderDto);
IPayStrategy IPayStrategy = PayFactory.getInstance().getConcreteStrategy(dto.getPayType());
PayInOrderVo payInOrderVo = IPayStrategy.unifiedOrder(unifiedOrderDto);
//构建支付订单完成入库
PayInfo payInfo = buildPayInfo(payInOrderVo,unifiedOrderDto,dto);
payInfoMapper.insert(payInfo);
@ -125,4 +142,48 @@ public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> impl
unifiedOrderDto.setOpenId(wxCode);
return unifiedOrderDto;
}
/**
* 修改支付单并发消息到订单系统修改订单状态
* @param editPayInfoNotifyDto
*/
@Transactional(propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
@Override
public void editPayInfoNotify(EditPayInfoNotifyDto editPayInfoNotifyDto) {
log.info("开始修改内部支付订单:回调入参, editPayInfoNotifyDto:{}",JSON.toJSONString(editPayInfoNotifyDto));
String payId = editPayInfoNotifyDto.getPayId();
String payNo = editPayInfoNotifyDto.getPayNo();
String payTime = editPayInfoNotifyDto.getPayTime();
PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayId, payId));
if (Objects.isNull(payInfo)){
log.error("查询支付订单数据返回失败");
throw new ServiceException("查询支付订单数据返回失败");
}
int i = payInfoMapper.editPayInfoForSingle(payId,payTime,payNo);
if(i==0){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
log.error("内部支付订单修改失败,payId:{}",payId);
throw new ServiceException("内部支付订单修改失败");
}
//支付场景
Integer sceneCode = payInfo.getSceneCode();
//关联的订单表id
String orderId = payInfo.getOrderId();
EnumSceneCode enumSceneCode = EnumSceneCode.getSceneCodeByCode(sceneCode);
switch (enumSceneCode){
//会员充值场景
case VIP_RECHARGE:
// 发送消息,订单支付成功
JSONObject vipRechargeMsgObj = new JSONObject();
vipRechargeMsgObj.put("orderId",orderId);
String vipRechargeMsgStr = JSON.toJSONString(vipRechargeMsgObj);
SendStatus sendStatus = vipOrderPayNotifyMqTemplate.syncSend(RocketMqConstant.VIP_ORDER_PAY_NOTIFY_TOPIC,
new GenericMessage<>(vipRechargeMsgStr)).getSendStatus();
if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
// 消息发不出去就抛异常,因为订单回调会有多次,几乎不可能每次都无法发送出去,发的出去无所谓
throw new ServiceException(ResponseEnum.SERVER_ERROR);
}
break;
}
}
}

71
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/WXPayUtil.java

@ -0,0 +1,71 @@
package com.bnyer.pay.utils;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @author :WXC
* @Date :2023/04/12
* @description :
*/
@Slf4j
public class WXPayUtil {
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {
Map<String, String> data = new HashMap<String, String>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
try{
//防止XXE攻击,即xml带入一个DTD。
//解决方案1:这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击
String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
documentBuilderFactory.setFeature(FEATURE, true);
//解决方案2:如果不能完全禁用DTDs,最少采取以下措施
// FEATURE = "http://xml.org/sax/features/external-general-entities";
// documentBuilderFactory.setFeature(FEATURE, false);
// FEATURE = "http://xml.org/sax/features/external-parameter-entities";
// documentBuilderFactory.setFeature(FEATURE, false);
// documentBuilderFactory.setXIncludeAware(false);
// documentBuilderFactory.setExpandEntityReferences(false);
}catch (Exception e){
log.info("=============:微信支付XXE尝试攻击失败============");
return data;
}
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes(StandardCharsets.UTF_8));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx=0; idx<nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
}
catch (Exception ex) {
}
return data;
}
}

15
bnyer-services/bnyer-pay/src/main/resources/com/bnyer/pay/mapper/PayInfoMapper.xml

@ -8,6 +8,8 @@
<result column="pay_id" jdbcType="VARCHAR" property="payId" />
<result column="order_id" jdbcType="VARCHAR" property="orderId" />
<result column="pay_status" jdbcType="INTEGER" property="payStatus" />
<result column="single_status" jdbcType="INTEGER" property="singleStatus" />
<result column="single_time" jdbcType="TIMESTAMP" property="singleTime" />
<result column="pay_type" jdbcType="VARCHAR" property="payType" />
<result column="pay_no" jdbcType="VARCHAR" property="payNo" />
<result column="appid" jdbcType="VARCHAR" property="appid" />
@ -28,8 +30,19 @@
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, pay_id, order_id, pay_status, pay_type, pay_no, appid, goods_subject, goods_desc,
id, pay_id, order_id, pay_status,single_status,single_time, pay_type, pay_no, appid, goods_subject, goods_desc,
pay_amount, pay_time, scene_code, ip, third_code, third_msg, third_no, remark, create_time,
update_time,sort,is_show
</sql>
<!-- 修改支付订单状态和对账信息-->
<update id="editPayInfoForSingle">
update pay_pay_info
set order_status = 1001,
set pay_time = STR_TO_DATE(#{payTime},'%Y%m%d%H%i%s'),
set pay_no = #{payNo}
set single_status = 1003,
set single_time = now()
where pay_id = #{payId}
</update>
</mapper>

Loading…
Cancel
Save