diff --git a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/PayInfo.java b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/PayInfo.java index 6e9cd84..93c9dda 100644 --- a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/PayInfo.java +++ b/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; + /** * 支付单号(第三方返回) */ diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumPayStatus.java b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayStatus.java similarity index 89% rename from bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumPayStatus.java rename to bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayStatus.java index cf3f9ec..9797bc9 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumPayStatus.java +++ b/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; diff --git a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/exception/ServiceException.java b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/exception/ServiceException.java index fc213cd..e828fa7 100644 --- a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/exception/ServiceException.java +++ b/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(); } } diff --git a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/utils/DateUtils.java b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/utils/DateUtils.java index d423aff..cf62174 100644 --- a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/utils/DateUtils.java +++ b/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); } diff --git a/bnyer-common/bnyer-common-redis/src/main/java/com/bnyer/common/redis/service/RedisService.java b/bnyer-common/bnyer-common-redis/src/main/java/com/bnyer/common/redis/service/RedisService.java index 335f92f..ccec3a2 100644 --- a/bnyer-common/bnyer-common-redis/src/main/java/com/bnyer/common/redis/service/RedisService.java +++ b/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"; diff --git a/bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/config/RocketMqConstant.java b/bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/config/RocketMqConstant.java index d0d1a2a..a8600bb 100644 --- a/bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/config/RocketMqConstant.java +++ b/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"; } diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/config/RocketMqConfig.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/config/RocketMqConfig.java index da710d7..9bf6cd9 100644 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/config/RocketMqConfig.java +++ b/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); + } } diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/controller/VipOrderController.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/controller/VipOrderController.java index a005e2e..a25eed5 100644 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/controller/VipOrderController.java +++ b/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 { diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPayNotifyConsumer.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPayNotifyConsumer.java new file mode 100644 index 0000000..14799f8 --- /dev/null +++ b/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 { + + @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().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); + } +} diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPaySuccessConsumer.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPaySuccessConsumer.java deleted file mode 100644 index 2d901ba..0000000 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPaySuccessConsumer.java +++ /dev/null @@ -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 { -// -//} diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/mapper/VipOrderMapper.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/mapper/VipOrderMapper.java index d9835d6..f7bbb27 100644 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/mapper/VipOrderMapper.java +++ b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/mapper/VipOrderMapper.java @@ -26,5 +26,11 @@ public interface VipOrderMapper extends BaseMapper { * 取消订单 * @param orderIds */ - void cancelVipOrder(@Param("orderIds") List orderIds, @Param("close_type") Integer close_type); + void cancelVipOrder(@Param("orderIds") List orderIds, @Param("closeType") Integer closeType); + + /** + * 修改订单表状态为已支付 + * @param orderId + */ + void updateByToPaySuccess(@Param("orderId") String orderId); } diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java index 1a12077..5596d1b 100644 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java +++ b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java @@ -86,7 +86,7 @@ public class VipOrderServiceImpl extends ServiceImpl 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 i } List 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; diff --git a/bnyer-services/bnyer-order/src/main/resources/com/bnyer/order/mapper/VipOrderMapper.xml b/bnyer-services/bnyer-order/src/main/resources/com/bnyer/order/mapper/VipOrderMapper.xml index 47ed9fb..424e057 100644 --- a/bnyer-services/bnyer-order/src/main/resources/com/bnyer/order/mapper/VipOrderMapper.xml +++ b/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} + + update order_vip_order + set + order_status = 1, + pay_status = 1001, + pay_time = now(), + update_time = now() + where order_id = #{orderId} + diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/config/RocketMqConfig.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/config/RocketMqConfig.java index 88fe05f..3b4cc5f 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/config/RocketMqConfig.java +++ b/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); } } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/AliPayController.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/AliPayController.java index a61c177..82a0b8a 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/AliPayController.java +++ b/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 inMap = new HashMap<>(); + Map 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()); + } } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayController.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayInfoController.java similarity index 95% rename from bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayController.java rename to bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayInfoController.java index 462fadd..8af909d 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayController.java +++ b/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; diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/WxPayController.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/WxPayController.java index 01558c9..a09cda5 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/WxPayController.java +++ b/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); + } } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/factory/PayFactory.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/factory/PayFactory.java index a150478..2905b36 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/factory/PayFactory.java +++ b/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 strategyMap = new ImmutableMap.Builder() + private static final Map strategyMap = new ImmutableMap.Builder() .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); } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AbstractPayStrategy.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AbstractPayStrategy.java new file mode 100644 index 0000000..5434186 --- /dev/null +++ b/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 payNotify(Object o,Class 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().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; + } + +} diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AliPayStrategy.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AliPayStrategy.java index da852ea..b049aaa 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AliPayStrategy.java +++ b/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 alipayConfigList = alipayConfigMapper.selectList(new LambdaQueryWrapper().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 inMap = JSON.parseObject(params, new TypeReference>() {}); + 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 alipayConfigList = alipayConfigMapper.selectList(new LambdaQueryWrapper() + .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; } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/IPayStrategy.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/IPayStrategy.java new file mode 100644 index 0000000..47e1666 --- /dev/null +++ b/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(); +} diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/PayStrategy.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/PayStrategy.java deleted file mode 100644 index 2a35b1b..0000000 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/PayStrategy.java +++ /dev/null @@ -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(); -} diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java index 3bb18e9..0b206bb 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java +++ b/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 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()); } } } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/EditPayInfoNotifyDto.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/EditPayInfoNotifyDto.java new file mode 100644 index 0000000..5d997b5 --- /dev/null +++ b/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; + + +} diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/PayNotifyCheckDto.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/PayNotifyCheckDto.java new file mode 100644 index 0000000..5f0b28f --- /dev/null +++ b/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; +} diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/WxPayManager.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/WxPayManager.java index c59678b..14162a2 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/WxPayManager.java +++ b/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().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().eq(WxpayConfig::getAppid,appId).eq(WxpayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode())); + if (Objects.isNull(wxpayConfig)) { + throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR); } return wxpayConfig; } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/mapper/PayInfoMapper.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/mapper/PayInfoMapper.java index 0be8867..9f1b3c9 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/mapper/PayInfoMapper.java +++ b/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 { + /** + * 修改支付订单状态和对账信息 + * @param payId + * @param payNo + * @return + */ + int editPayInfoForSingle(@Param("payId") String payId, @Param("payTime") String payTime, @Param("payNo") String payNo); } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java index 3f64e62..bff2c2a 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java +++ b/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{ * @return */ PayInOrderVo addPayInOrder(AddPayInfoDto dto, HttpServletRequest request); + + /** + * 修改支付单、并发消息到订单系统修改订单状态 + * @param editPayInfoNotifyDto + */ + void editPayInfoNotify(EditPayInfoNotifyDto editPayInfoNotifyDto); + } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java index 6aef9d3..00e0408 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java +++ b/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 implements PayInfoService { @Autowired private PayInfoMapper payInfoMapper; + @Autowired + private RocketMQTemplate vipOrderPayNotifyMqTemplate; + @Autowired private RemoteVipOrderService remoteVipOrderService; @@ -70,8 +87,8 @@ public class PayInfoServiceImpl extends ServiceImpl 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 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().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; + } + } } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/WXPayUtil.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/WXPayUtil.java new file mode 100644 index 0000000..2d807cb --- /dev/null +++ b/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 xmlToMap(String strXML) throws Exception { + Map data = new HashMap(); + 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 + + @@ -28,8 +30,19 @@ - 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 + + + + 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} +