Browse Source

mq优化,支付请求添加重试机制,统一异常管理,并添加统一订单推送

feature-1.1
wuxicheng 3 years ago
parent
commit
7888562f60
  1. 11
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/constant/RedisKeyConstant.java
  2. 22
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/DypayConfig.java
  3. 5
      bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/constant/RocketMqTopic.java
  4. 21
      bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/domain/pay/ThirdPayOrderPushMessage.java
  5. 6
      bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/handle/EnhanceMessageHandler.java
  6. 2
      bnyer-services/bnyer-img/src/main/java/com/bnyer/img/listener/GoldRewardConsumer.java
  7. 2
      bnyer-services/bnyer-img/src/main/java/com/bnyer/img/listener/ImgReturnMessageConsumer.java
  8. 2
      bnyer-services/bnyer-img/src/main/java/com/bnyer/img/listener/VipRecordCreateConsumer.java
  9. 2
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/OrderReturnMessageConsumer.java
  10. 2
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderCancelConsumer.java
  11. 2
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderPayNotifyConsumer.java
  12. 4
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java
  13. 220
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/DyPushOrderBo.java
  14. 93
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/PushOrderBo.java
  15. 25
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/dto/PushOrderDto.java
  16. 6
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/PayInfoVo.java
  17. 9
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/constant/DYPayConstants.java
  18. 12
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AbstractPayStrategy.java
  19. 96
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java
  20. 7
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/IPayStrategy.java
  21. 28
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/KSPayStrategy.java
  22. 37
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumDyOrderStatus.java
  23. 41
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/exception/PayException.java
  24. 2
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/listener/PayReturnMessageConsumer.java
  25. 67
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/listener/ThirdPayOrderPushConsumer.java
  26. 182
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/DyPayManager.java
  27. 186
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/KsPayManager.java
  28. 1
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java
  29. 15
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/UnifiedPayService.java
  30. 30
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java
  31. 83
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java
  32. 376
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PayRestTemplateUtil.java
  33. 3
      bnyer-services/bnyer-pay/src/main/resources/com/bnyer/pay/mapper/DypayConfigMapper.xml

11
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/constant/RedisKeyConstant.java

@ -166,4 +166,15 @@ public class RedisKeyConstant {
* 支付回调rediskey
*/
public static final String PAY_NOTIFY_LOCK_KEY = "bnyer.pay.notify.lock:";
/**
* 抖音ACCESS_TOKEN
*/
public static final String DY_ACCESS_TOKEN_KEY = "bnyer.pay.dy.access.token";
/**
* 快手ACCESS_TOKEN
*/
public static final String KS_ACCESS_TOKEN_KEY = "bnyer.pay.ks.access.token";
}

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

@ -1,17 +1,10 @@
package com.bnyer.common.core.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.*;
/**
* @author :WXC
@ -36,17 +29,24 @@ public class DypayConfig extends BaseDomain {
private String appid;
/**
* 秘钥
* 应用秘钥
*/
@TableField(value = "appSecret")
@ApiModelProperty(value="应用秘钥")
private String appSecret;
/**
* 支付秘钥
*/
@TableField(value = "salt")
@ApiModelProperty(value="秘钥")
@ApiModelProperty(value="支付秘钥")
private String salt;
/**
* 令牌
*/
@TableField(value = "token")
@ApiModelProperty(value="令牌")
@ApiModelProperty(value="支付令牌")
private String token;
/**

5
bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/constant/RocketMqTopic.java

@ -40,4 +40,9 @@ public class RocketMqTopic {
*/
public static final String GOLD_REWARD_TOPIC = "gold-reward-topic";
/**
* 第三方支付订单推送队列
*/
public static final String THIRD_PAY_ORDER_PUSH_TOPIC = "third-pay-order-push-topic";
}

21
bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/domain/pay/ThirdPayOrderPushMessage.java

@ -0,0 +1,21 @@
package com.bnyer.common.rocketmq.domain.pay;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author :WXC
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class ThirdPayOrderPushMessage {
/**
* 支付单号
*/
private String payId;
}

6
bnyer-common/bnyer-common-rocketmq/src/main/java/com/bnyer/common/rocketmq/handle/EnhanceMessageHandler.java

@ -121,6 +121,12 @@ public abstract class EnhanceMessageHandler {
public void dispatchMessage(BnyerMessage message) {
// 基础日志记录被父类处理了
log.info("消费者收到消息[{}]", JSONObject.toJSON(message));
//消息去重
if (handleMsgRepeat(message)){
log.info("消息id{}属于重复消息,已过滤。",message.getMessageKey());
return;
}
//自定义消息过滤规则
if (filter(message)) {
log.info("消息id{}不满足消费条件,已过滤。",message.getMessageKey());
return;

2
bnyer-services/bnyer-img/src/main/java/com/bnyer/img/listener/GoldRewardConsumer.java

@ -137,7 +137,7 @@ public class GoldRewardConsumer extends EnhanceMessageHandler implements RocketM
@Override
protected boolean filter(BnyerMessage message) {
return super.handleMsgRepeat(message);
return false;
}

2
bnyer-services/bnyer-img/src/main/java/com/bnyer/img/listener/ImgReturnMessageConsumer.java

@ -40,7 +40,7 @@ public class ImgReturnMessageConsumer extends EnhanceMessageHandler implements R
@Override
protected boolean filter(BnyerMessage message) {
return super.handleMsgRepeat(message);
return false;
}
@Override

2
bnyer-services/bnyer-img/src/main/java/com/bnyer/img/listener/VipRecordCreateConsumer.java

@ -45,7 +45,7 @@ public class VipRecordCreateConsumer extends EnhanceMessageHandler implements Ro
@Override
protected boolean filter(BnyerMessage message) {
return super.handleMsgRepeat(message);
return false;
}
@Override

2
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/OrderReturnMessageConsumer.java

@ -42,7 +42,7 @@ public class OrderReturnMessageConsumer extends EnhanceMessageHandler implements
@Override
protected boolean filter(BnyerMessage message) {
return super.handleMsgRepeat(message);
return false;
}
@Override

2
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/listener/vip/VipOrderCancelConsumer.java

@ -50,7 +50,7 @@ public class VipOrderCancelConsumer extends EnhanceMessageHandler implements Roc
@Override
protected boolean filter(BnyerMessage message) {
return super.handleMsgRepeat(message);
return false;
}

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

@ -63,7 +63,7 @@ public class VipOrderPayNotifyConsumer extends EnhanceMessageHandler implements
@Override
protected boolean filter(BnyerMessage message) {
return super.handleMsgRepeat(message);
return false;
}
@Override

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

@ -1,9 +1,7 @@
package com.bnyer.order.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.domain.R;
@ -262,13 +260,11 @@ public class VipOrderServiceImpl implements VipOrderService {
//发消息,添加用户会员记录
AddUserVipRecordMessage addUserVipRecordMessage = buildVipRecordMsg(vipOrder);
// rocketMQEnhanceTemplate.sendAsyncMsg(RocketMqTopic.VIP_RECORD_CREATE_TOPIC,null, addUserVipRecordMessage);
orderMqMessageRecordService.sendAsyncMsg(RocketMqTopic.VIP_RECORD_CREATE_TOPIC,null, addUserVipRecordMessage);
//发送开会员画意值奖励并写入记录消息
GoldRewardMessage goldMsg = buildGoldRewardMsg(vipOrder.getUserId(),GoldEnum.BUY_VIP.getGoldNum(), GoldEnum.BUY_VIP.getCode(),null,vipOrder.getUserClientType());
// rocketMQEnhanceTemplate.sendAsyncMsg(RocketMqTopic.GOLD_REWARD_TOPIC,null,goldMsg);
orderMqMessageRecordService.sendAsyncMsg(RocketMqTopic.GOLD_REWARD_TOPIC,null,goldMsg);
}

220
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/DyPushOrderBo.java

@ -0,0 +1,220 @@
package com.bnyer.pay.bean.bo;
import com.bnyer.pay.enums.EnumDyOrderStatus;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.List;
/**
* 抖音推送订单入参
*/
@Getter
@Setter
@NoArgsConstructor
public class DyPushOrderBo implements Serializable {
private static final long serialVersionUID = 1866990048913415295L;
/**
* 第三方在抖音开放平台申请的 ClientKey
* 注意POI 订单必传
* 是否必填
*/
@SerializedName(value = "client_key")
private String clientKey;
/**
* 服务端 API 调用标识通过 getAccessToken 获取
* 是否必填
*/
@SerializedName(value = "access_token")
private String accessToken;
/**
* POI 店铺同步时使用的开发者侧店铺 ID购买店铺 ID长度 < 256 byte
*
* 注意POI 订单必传
* 是否必填
*/
@SerializedName(value = "ext_shop_id")
private String extShopId;
/**
* 做订单展示的字节系 app 名称目前为固定值douyin
* 是否必填
*/
@SerializedName(value = "app_name")
private String appName;
/**
* 小程序用户的 open_id通过 code2Session 获取
* 是否必填
*/
@SerializedName(value = "open_id")
private String openId;
/**
* json string根据不同订单类型有不同的结构体请参见 order_detail 字段说明json string
* 是否必填
*/
@SerializedName(value = "order_detail")
private String orderDetail;
/**
* 普通小程序订单订单状态POI 订单可以忽略
0待支付
1已支付
2已取消用户主动取消或者超时未支付导致的关单
4已核销核销状态是整单核销,即一笔订单买了 3 个券核销是指 3 个券核销的整单
5退款中
6已退款
8退款失败
注意普通小程序订单必传担保支付分账依赖该状态
是否必填
*/
@SerializedName(value = "order_status")
private Integer orderStatus;
/**
* 订单类型枚举值:
*
* 0普通小程序订单非POI订单
* 9101团购券订单POI 订单
* 9001景区门票订单POI订单
* 是否必填
*/
@SerializedName(value = "order_type")
private Integer orderType;
/**
* 订单信息变更时间13 位毫秒级时间戳
* 是否必填
*/
@SerializedName(value = "update_time")
private Integer updateTime;
/**
* 自定义字段用于关联具体业务场景下的特殊参数长度 < 2048byte
* 是否必填
*/
@SerializedName(value = "extra")
private String extra;
@Getter
@Setter
@NoArgsConstructor
public static class OrderDetails implements Serializable {
private static final long serialVersionUID = 3320384952853603934L;
/**
* 开发者侧业务单号用作幂等控制该订单号是和担保支付的支付单号绑定的也就是预下单时传入的 out_order_no 字段长度 <= 64byte
* 是否必填
*/
@SerializedName(value = "order_id")
private String orderId;
/**
* 订单创建的时间13 位毫秒时间戳
* 是否必填
*/
@SerializedName(value = "create_time")
private Integer createTime;
/**
* 订单状态建议采用以下枚举值
*
* 待支付
* 已支付
* 已取消
* 已超时
* 已核销
* 退款中
* 已退款
* 退款失败
* 是否必填
*/
@SerializedName(value = "status")
private EnumDyOrderStatus status;
/**
* 订单商品总数
* 是否必填
*/
@SerializedName(value = "amount")
private Integer amount;
/**
* 订单总价单位为分
* 是否必填
*/
@SerializedName(value = "total_price")
private Integer totalPrice;
/**
* 小程序订单详情页 path长度<=1024 byte
* 是否必填
*/
@SerializedName(value = "detail_url")
private String detailUrl;
/**
* 子订单商品列表不可为空
* 是否必填
*/
@SerializedName(value = "item_list")
private List<Goods> itemList;
@Getter
@Setter
@NoArgsConstructor
public static class Goods implements Serializable {
private static final long serialVersionUID = 1418159270677457444L;
/**
* 开发者侧商品 ID长度 <= 64 byte
* 是否必填
*/
@SerializedName(value = "item_code")
private String itemCode;
/**
* 子订单商品图片 URL长度 <= 512 byte
* 是否必填
*/
@SerializedName(value = "img")
private String img;
/**
* 子订单商品介绍标题长度 <= 256 byte
* 是否必填
*/
@SerializedName(value = "title")
private String title;
/**
* 子订单商品介绍副标题长度 <= 256 byte
* 是否必填
*/
@SerializedName(value = "sub_title")
private String subTitle;
/**
* 单类商品的数目
* 是否必填
*/
@SerializedName(value = "amount")
private Integer amount;
/**
* 单类商品的总价单位为分
* 是否必填
*/
@SerializedName(value = "price")
private Integer price;
}
}
}

93
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/PushOrderBo.java

@ -0,0 +1,93 @@
package com.bnyer.pay.bean.bo;
import com.bnyer.common.core.enums.EnumPayStatus;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Date;
import java.util.List;
/**
* @author :WXC
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class PushOrderBo {
/**
* 开发者侧业务单号
*/
private String payId;
/**
* 订单创建的时间
*/
private Date createTime;
/**
* 订单变更的时间
*/
private Date updateTime;
/**
* 支付状态
*/
private EnumPayStatus payStatus;
/**
* 商品总数
*/
private Integer goodsNum;
/**
* 订单总价单位为分
*/
private Integer totalPrice;
/**
* 商品列表
*/
private List<Goods> goodsList;
/**
* 商品列表
*/
@Getter
@Setter
@NoArgsConstructor
public static class Goods{
/**
* 开发者侧商品 ID
*/
private String itemCode;
/**
* 子订单商品图片 URL
*/
private String img;
/**
* 子订单商品介绍标题
*/
private String title;
/**
* 子订单商品介绍副标题
*/
private String subTitle;
/**
* 单类商品的数目
*/
private Integer goodsNum;
/**
* 单类商品的总价单位为分
*/
private Integer price;
}
}

25
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/dto/PushOrderDto.java

@ -0,0 +1,25 @@
package com.bnyer.pay.bean.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* @author :WXC
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class PushOrderDto {
/**
* 支付单号
*/
@NotBlank(message = "支付单号不能为空")
@ApiModelProperty(value = "支付单号")
private String payId;
}

6
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/PayInfoVo.java

@ -35,6 +35,12 @@ public class PayInfoVo {
@ApiModelProperty(value="单笔对账时间")
private Date singleTime;
@ApiModelProperty(value="创建时间")
private Date createTime;
@ApiModelProperty(value="修改时间")
private Date updateTime;
@ApiModelProperty(value="支付类型:wxpay/alipay/kspay/dypay")
private String payType;

9
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/constant/DYPayConstants.java

@ -10,6 +10,10 @@ public class DYPayConstants {
* 登陆
*/
public static final String CODE_2_SESSION = "https://developer.toutiao.com/api/apps/v2/jscode2session";
/**
* 获取AccessToken
*/
public static final String GET_ACCESS_TOKEN = "https://developer.toutiao.com/api/apps/v2/token";
/**
* 生成预支付单
*/
@ -27,5 +31,10 @@ public class DYPayConstants {
* 退款
*/
public static final String CREATE_REFUND = "https://developer.toutiao.com/api/apps/ecpay/v1/create_refund";
/**
* 订单推送
*/
public static final String ORDER_PUSH = "https://developer.toutiao.com/api/apps/order/v2/push";
}

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

@ -6,6 +6,7 @@ import com.alipay.api.msg.MsgConstants;
import com.bnyer.common.core.constant.RedisKeyConstant;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.redis.service.RedissonService;
import com.bnyer.pay.bean.bo.PushOrderBo;
import com.bnyer.pay.bean.dto.PayNotifyCheckDto;
import com.bnyer.pay.bean.vo.PayInfoDetailsVo;
import com.bnyer.pay.service.PayInfoService;
@ -29,7 +30,8 @@ public abstract class AbstractPayStrategy implements IPayStrategy {
private static RedissonService redissonService;
@Autowired
public void setBean(PayInfoService payInfoService, RedissonService redissonService) {
public void setBean(PayInfoService payInfoService,
RedissonService redissonService) {
AbstractPayStrategy.payInfoService = payInfoService;
AbstractPayStrategy.redissonService = redissonService;
}
@ -109,4 +111,12 @@ public abstract class AbstractPayStrategy implements IPayStrategy {
return result;
}
/**
* 推送订单由各子类实现
* @param pushOrderBo
*/
public void pushOrder(PushOrderBo pushOrderBo) {
}
}

96
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java

@ -10,33 +10,30 @@ 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.StringUtils;
import com.bnyer.pay.bean.bo.QueryOrderBo;
import com.bnyer.pay.bean.bo.RefundBo;
import com.bnyer.pay.bean.bo.UnifiedOrderBo;
import com.bnyer.pay.constant.DYPayConstants;
import com.bnyer.pay.bean.bo.*;
import com.bnyer.pay.bean.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.bean.dto.PayNotifyCheckDto;
import com.bnyer.pay.bean.vo.ThirdQueryOrderVo;
import com.bnyer.pay.bean.vo.ThirdRefundVo;
import com.bnyer.pay.bean.vo.ThirdUnifiedOrderVo;
import com.bnyer.pay.constant.DYPayConstants;
import com.bnyer.pay.enums.EnumDyOrderStatus;
import com.bnyer.pay.enums.EnumDyPayStatus;
import com.bnyer.pay.enums.EnumPayChannel;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.exception.PayException;
import com.bnyer.pay.mapper.DypayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.utils.DYPayUtil;
import com.bnyer.pay.manager.DyPayManager;
import com.bnyer.pay.utils.MoneyUtil;
import com.bnyer.pay.utils.PayRestTemplateUtil;
import com.bnyer.pay.bean.vo.ThirdRefundVo;
import com.bnyer.pay.bean.vo.ThirdUnifiedOrderVo;
import com.bnyer.pay.bean.vo.ThirdQueryOrderVo;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.*;
/**
* @author :WXC
@ -49,8 +46,6 @@ public class DYPayStrategy extends AbstractPayStrategy{
private static DYPayUtil dyPayUtil;
private static PayRestTemplateUtil payRestTemplateUtil;
private static PayInfoService payInfoService;
private static DypayConfigMapper dypayConfigMapper;
@ -58,10 +53,9 @@ public class DYPayStrategy extends AbstractPayStrategy{
private final static String failThirdCode = "-1";
@Autowired
public void setBean(DYPayUtil dyPayUtil, PayRestTemplateUtil payRestTemplateUtil,
public void setBean(DYPayUtil dyPayUtil,
PayInfoService payInfoService, DypayConfigMapper dypayConfigMapper) {
DYPayStrategy.dyPayUtil = dyPayUtil;
DYPayStrategy.payRestTemplateUtil = payRestTemplateUtil;
DYPayStrategy.payInfoService = payInfoService;
DYPayStrategy.dypayConfigMapper = dypayConfigMapper;
}
@ -75,17 +69,18 @@ public class DYPayStrategy extends AbstractPayStrategy{
if (CollUtil.isEmpty(dypayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
DypayConfig dypayConfig = dypayConfigList.get(0);
return dypayConfig;
return dypayConfigList.get(0);
}
@Override
public ThirdUnifiedOrderVo unifiedOrder(UnifiedOrderBo bo) {
String result = "";
DypayConfig dypayConfig = getDypayConfig();
DyPayManager dyPayManager = new DyPayManager(dypayConfig);
String appId = dypayConfig.getAppid();
String backurl = dypayConfig.getBackurl();
String salt = dypayConfig.getSalt();
String requestStr = "";
try {
//加签验签的参数需要排序
Map<String, Object> params = new TreeMap<>();
@ -123,9 +118,9 @@ public class DYPayStrategy extends AbstractPayStrategy{
payJson.put("notify_url",backurl);
log.info("请求参数{}", payJson);
//预下单接口
result = payRestTemplateUtil.dyPostRequest(payJson, DYPayConstants.CREATE_ORDER);
} catch (Exception e) {
e.printStackTrace();
requestStr = JSON.toJSONString(payJson);
result = dyPayManager.postRequest(requestStr, DYPayConstants.CREATE_ORDER);
} catch (PayException e) {
log.error("抖音支付:支付异常,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
@ -245,6 +240,7 @@ public class DYPayStrategy extends AbstractPayStrategy{
@Override
public ThirdQueryOrderVo queryOrder(QueryOrderBo bo) {
DypayConfig dypayConfig = getDypayConfig();
DyPayManager dyPayManager = new DyPayManager(dypayConfig);
String appId = dypayConfig.getAppid();
String salt = dypayConfig.getSalt();
String result = "";
@ -262,9 +258,8 @@ public class DYPayStrategy extends AbstractPayStrategy{
queryOrderJson.put("out_order_no", bo.getPayId());
queryOrderJson.put("sign", sign);
//发起请求
result = payRestTemplateUtil.dyPostRequest(queryOrderJson, DYPayConstants.QUERY_ORDER);
}catch (Exception e){
e.printStackTrace();
result = dyPayManager.postRequest(JSON.toJSONString(queryOrderJson), DYPayConstants.QUERY_ORDER);
}catch (PayException e){
log.error("抖音支付:订单查询异常,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
@ -318,4 +313,57 @@ public class DYPayStrategy extends AbstractPayStrategy{
public ThirdRefundVo refund(RefundBo bo) {
return null;
}
@Override
public void pushOrder(PushOrderBo pushOrderBo) {
log.info("开始订单推送......,request:{}",JSON.toJSONString(pushOrderBo));
DypayConfig dypayConfig = getDypayConfig();
DyPayManager dyPayManager = new DyPayManager(dypayConfig);
String requestStr = "";
String resultStr = "";
try {
//获取accessToken
String accessToken = dyPayManager.getAccessToken(false);
DyPushOrderBo dyPushOrderBo = new DyPushOrderBo();
dyPushOrderBo.setAccessToken(accessToken);
dyPushOrderBo.setAppName("douyin");
dyPushOrderBo.setOpenId(dypayConfig.getAppid());
dyPushOrderBo.setOrderStatus(EnumDyOrderStatus.getEnumDyOrderStatusByPayStatus(pushOrderBo.getPayStatus()).getStatus());
dyPushOrderBo.setOrderType(0);
dyPushOrderBo.setUpdateTime(Integer.parseInt(String.valueOf(pushOrderBo.getUpdateTime().getTime())));
//订单详情
DyPushOrderBo.OrderDetails orderDetails = new DyPushOrderBo.OrderDetails();
orderDetails.setOrderId(pushOrderBo.getPayId());
orderDetails.setAmount(pushOrderBo.getGoodsNum());
orderDetails.setCreateTime(Integer.parseInt(String.valueOf(pushOrderBo.getCreateTime().getTime())));
orderDetails.setDetailUrl("www.baidu.com");
orderDetails.setStatus(EnumDyOrderStatus.getEnumDyOrderStatusByPayStatus(pushOrderBo.getPayStatus()));
orderDetails.setTotalPrice(pushOrderBo.getTotalPrice());
//封装商品列表
List<PushOrderBo.Goods> goodsList = pushOrderBo.getGoodsList();
List<DyPushOrderBo.OrderDetails.Goods> pushItemList = new ArrayList<>();
goodsList.forEach(goods -> {
DyPushOrderBo.OrderDetails.Goods pushItem = new DyPushOrderBo.OrderDetails.Goods();
pushItem.setItemCode(goods.getItemCode());
pushItem.setAmount(goods.getGoodsNum());
pushItem.setImg(goods.getImg());
pushItem.setPrice(goods.getPrice());
pushItem.setSubTitle(goods.getSubTitle());
pushItem.setTitle(goods.getTitle());
pushItemList.add(pushItem);
});
orderDetails.setItemList(pushItemList);
dyPushOrderBo.setOrderDetail(JSON.toJSONString(orderDetails.toString()));
//发起请求
requestStr = JSON.toJSONString(dyPushOrderBo);
resultStr = dyPayManager.postRequest(JSON.toJSONString(dyPushOrderBo), DYPayConstants.ORDER_PUSH);
log.info("抖音支付:抖音订单推送接口调用成功,request:{},result:{}",requestStr,resultStr);
}catch (PayException e){
log.error("抖音支付:抖音订单推送接口调用异常,request:{},error{}", requestStr, e.getMessage());
}
}
}

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

@ -1,5 +1,6 @@
package com.bnyer.pay.design.strategy;
import com.bnyer.pay.bean.bo.PushOrderBo;
import com.bnyer.pay.bean.bo.QueryOrderBo;
import com.bnyer.pay.bean.bo.RefundBo;
import com.bnyer.pay.bean.bo.UnifiedOrderBo;
@ -46,6 +47,12 @@ public interface IPayStrategy {
*/
ThirdRefundVo refund(RefundBo bo);
/**
* 推送订单
* @param pushOrderBo
*/
void pushOrder(PushOrderBo pushOrderBo);
//===========待完成================
// TODO: 2023/04/03 退款查询
// void refundQuery();

28
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/KSPayStrategy.java

@ -14,19 +14,19 @@ import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.pay.bean.bo.QueryOrderBo;
import com.bnyer.pay.bean.bo.RefundBo;
import com.bnyer.pay.bean.bo.UnifiedOrderBo;
import com.bnyer.pay.constant.KSPayConstants;
import com.bnyer.pay.bean.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.bean.dto.PayNotifyCheckDto;
import com.bnyer.pay.bean.vo.ThirdQueryOrderVo;
import com.bnyer.pay.bean.vo.ThirdRefundVo;
import com.bnyer.pay.bean.vo.ThirdUnifiedOrderVo;
import com.bnyer.pay.constant.KSPayConstants;
import com.bnyer.pay.enums.EnumPayChannel;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.manager.KsPayManager;
import com.bnyer.pay.mapper.KspayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.utils.KSPayUtil;
import com.bnyer.pay.utils.MoneyUtil;
import com.bnyer.pay.utils.PayRestTemplateUtil;
import com.bnyer.pay.bean.vo.ThirdRefundVo;
import com.bnyer.pay.bean.vo.ThirdUnifiedOrderVo;
import com.bnyer.pay.bean.vo.ThirdQueryOrderVo;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
@ -49,8 +49,6 @@ public class KSPayStrategy extends AbstractPayStrategy{
private static KSPayUtil ksPayUtil;
private static PayRestTemplateUtil payRestTemplateUtil;
private static PayInfoService payInfoService;
private static KspayConfigMapper kspayConfigMapper;
@ -58,10 +56,9 @@ public class KSPayStrategy extends AbstractPayStrategy{
private final static String failThirdCode = "-1";
@Autowired
public void setBean(KSPayUtil ksPayUtil, PayRestTemplateUtil payRestTemplateUtil,
public void setBean(KSPayUtil ksPayUtil,
PayInfoService payInfoService, KspayConfigMapper kspayConfigMapper) {
KSPayStrategy.ksPayUtil = ksPayUtil;
KSPayStrategy.payRestTemplateUtil = payRestTemplateUtil;
KSPayStrategy.payInfoService = payInfoService;
KSPayStrategy.kspayConfigMapper = kspayConfigMapper;
}
@ -75,14 +72,14 @@ public class KSPayStrategy extends AbstractPayStrategy{
if (CollUtil.isEmpty(kspayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
KspayConfig kspayConfig = kspayConfigList.get(0);
return kspayConfig;
return kspayConfigList.get(0);
}
@Override
public ThirdUnifiedOrderVo unifiedOrder(UnifiedOrderBo bo) {
String result = "";
KspayConfig kspayConfig = getKspayConfig();
KsPayManager ksPayManager = new KsPayManager(kspayConfig);
String openId = bo.getOpenId();
String appId = kspayConfig.getAppid();
String backurl = kspayConfig.getBackurl();
@ -125,13 +122,11 @@ public class KSPayStrategy extends AbstractPayStrategy{
payJson.put("notify_url", bo.getCurrDate());
log.info("请求参数{}", payJson);
//预下单接口
String ksPayAccessToken = payRestTemplateUtil.ksPostRequestUrlencoded(kspayConfig);
result = payRestTemplateUtil.ksPostRequestJson(payJson, KSPayConstants.CREATE_ORDER, appId, ksPayAccessToken);
result = ksPayManager.postRequest(payJson.toJSONString(), KSPayConstants.CREATE_ORDER);
log.info("==================================");
log.info("快手预下单result{}", result);
log.info("==================================");
} catch (Exception e) {
e.printStackTrace();
log.error("快手支付:支付异常,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
@ -246,12 +241,11 @@ public class KSPayStrategy extends AbstractPayStrategy{
@Override
public ThirdQueryOrderVo queryOrder(QueryOrderBo bo) {
KspayConfig kspayConfig = getKspayConfig();
KsPayManager ksPayManager = new KsPayManager(kspayConfig);
String appId = kspayConfig.getAppid();
String secret = kspayConfig.getSecret();
String result = "";
try {
//accessToken
String ksPayAccessToken = payRestTemplateUtil.ksPostRequestUrlencoded(kspayConfig);
//加签验签的参数需要排序
Map<String, Object> params = new TreeMap<>();
//小程序APPID
@ -264,7 +258,7 @@ public class KSPayStrategy extends AbstractPayStrategy{
queryOrderJson.put("out_order_no", bo.getPayId());
queryOrderJson.put("sign", sign);
//发起请求
result = payRestTemplateUtil.ksPostRequestJson(queryOrderJson, KSPayConstants.QUERY_ORDER, appId, ksPayAccessToken);
result = ksPayManager.postRequest(queryOrderJson.toJSONString(), KSPayConstants.QUERY_ORDER);
}catch (Exception e){
e.printStackTrace();
log.error("快手支付:订单查询异常,payId:{},error{}", bo.getPayId(), e.getMessage());

37
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumDyOrderStatus.java

@ -0,0 +1,37 @@
package com.bnyer.pay.enums;
import com.bnyer.common.core.enums.EnumPayStatus;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@AllArgsConstructor
public enum EnumDyOrderStatus {
待支付(1,EnumPayStatus.NO_PAY),
已支付(2,EnumPayStatus.SUCCESS),
已取消(3,null),
已超时(4,null),
已核销(5,null),
退款中(6,null),
已退款(7,null),
退款失败(8,null),
;
private final int status;
private final EnumPayStatus payStatus;
public static EnumDyOrderStatus getEnumDyOrderStatusByPayStatus(EnumPayStatus status) {
return Arrays.stream(values())
.filter(dyOrderStatus -> dyOrderStatus.getPayStatus() == status)
.findFirst().orElseThrow(() -> new SecurityException("status 未匹配上对应的支付状态"));
}
}

41
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/exception/PayException.java

@ -0,0 +1,41 @@
package com.bnyer.pay.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author :WXC
* @description :
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class PayException extends Exception {
private static final long serialVersionUID = -7296122902130895085L;
/**
* 自定义错误讯息.
*/
private String customErrorMsg;
/**
* 错误代码.
*/
private String errCode;
/**
* 错误代码描述.
*/
private String errCodeDes;
public PayException(String customErrorMsg) {
super(customErrorMsg);
this.customErrorMsg = customErrorMsg;
}
public PayException(String customErrorMsg, Throwable tr) {
super(customErrorMsg, tr);
this.customErrorMsg = customErrorMsg;
}
}

2
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/listener/PayReturnMessageConsumer.java

@ -42,7 +42,7 @@ public class PayReturnMessageConsumer extends EnhanceMessageHandler implements R
@Override
protected boolean filter(BnyerMessage message) {
return super.handleMsgRepeat(message);
return false;
}
@Override

67
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/listener/ThirdPayOrderPushConsumer.java

@ -0,0 +1,67 @@
package com.bnyer.pay.listener;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.rocketmq.constant.RocketMqTopic;
import com.bnyer.common.rocketmq.domain.BnyerMessage;
import com.bnyer.common.rocketmq.domain.pay.ThirdPayOrderPushMessage;
import com.bnyer.common.rocketmq.handle.EnhanceMessageHandler;
import com.bnyer.pay.bean.dto.PushOrderDto;
import com.bnyer.pay.service.UnifiedPayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author :WXC
* @description :第三方支付订单推送
*/
@Slf4j
@Component
@RocketMQMessageListener(topic = RocketMqTopic.THIRD_PAY_ORDER_PUSH_TOPIC,consumerGroup = RocketMqTopic.THIRD_PAY_ORDER_PUSH_TOPIC)
public class ThirdPayOrderPushConsumer extends EnhanceMessageHandler implements RocketMQListener<BnyerMessage> {
@Resource
private UnifiedPayService unifiedPayService;
@Override
protected void handleMessage(BnyerMessage message) throws Exception {
super.dispatchMessage(message);
try {
ThirdPayOrderPushMessage thirdPayOrderPushMessage = message.getObject(ThirdPayOrderPushMessage.class);
PushOrderDto pushOrderDto = new PushOrderDto();
pushOrderDto.setPayId(thirdPayOrderPushMessage.getPayId());
unifiedPayService.pushOrder(pushOrderDto);
} catch (ServiceException e) {
log.error("订单推送失败:"+e.getMessage());
}
}
@Override
protected void handleMaxRetriesExceeded(BnyerMessage message) {
}
@Override
protected boolean filter(BnyerMessage message) {
return false;
}
@Override
protected boolean isRetry() {
return true;
}
@Override
protected boolean throwException() {
return false;
}
@Override
public void onMessage(BnyerMessage message) {
}
}

182
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/DyPayManager.java

@ -0,0 +1,182 @@
package com.bnyer.pay.manager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bnyer.common.core.constant.RedisKeyConstant;
import com.bnyer.common.core.domain.DypayConfig;
import com.bnyer.common.core.utils.SpringUtils;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.common.redis.service.RedisService;
import com.bnyer.pay.constant.DYPayConstants;
import com.bnyer.pay.exception.PayException;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.json.GsonParser;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;
import java.text.MessageFormat;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* @author :WXC
* @Date :2023/04/24
* @description :
*/
@Slf4j
public class DyPayManager {
private RestTemplate restTemplate;
private RedisService redisService;
private final DypayConfig dypayConfig;
private final int MAX_RETRY_TIMES = 2;
public DyPayManager(DypayConfig dypayConfig){
this.dypayConfig = dypayConfig;
init();
}
private void init() {
this.restTemplate = SpringUtils.getBean(RestTemplate.class);
this.redisService = SpringUtils.getBean(RedisService.class);
}
/**
* 抖音小程序获取accessToken
* 为了保障应用的数据安全只能在开发者服务器使用 AppSecret如果小程序存在泄露 AppSecret 的问题字节小程序平台将有可能下架该小程序并暂停该小程序相关服务
*
* access_token 是小程序的全局唯一调用凭据开发者调用小程序支付时需要使用 access_tokenaccess_token 的有效期为 2 个小时需要定时刷新 access_token重复获取会导致之前一次获取的 access_token 的有效期缩短为 5 分钟
*/
public String getAccessToken(boolean isRefresh) throws PayException {
if (!isRefresh){
Object cacheObject = redisService.getCacheObject(RedisKeyConstant.DY_ACCESS_TOKEN_KEY);
if (Objects.nonNull(cacheObject)){
return cacheObject.toString();
}
}
String requestStr = "";
try {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> formEntity = new HttpEntity<>(MessageFormat.format("app_id={0}&app_secret={1}&&grant_type={2}"
, dypayConfig.getAppid(), dypayConfig.getAppSecret(), "client_credentials"), headers);
String resultStr = restTemplate.postForObject(DYPayConstants.GET_ACCESS_TOKEN, formEntity, String.class);
String url = DYPayConstants.GET_ACCESS_TOKEN;
requestStr = formEntity.getBody();
if (StringUtils.isBlank(resultStr) || !resultStr.startsWith("{")){
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, resultStr);
throw convertDyException(GsonParser.parse("第三方返回格式有误!"));
}
JSONObject resultObj = JSONObject.parseObject(resultStr);
String errNo = StringUtils.isNotBlank(resultObj.getString("err_no"))?resultObj.getString("err_no"):resultObj.getString("err_code");
if ("0".equals(errNo)) {
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, resultObj, resultStr);
//存入redis
String accessToken = resultObj.getJSONObject("data").getString("access_token");
String expiresIn = resultObj.getJSONObject("data").getString("expires_in");
redisService.setCacheObject(RedisKeyConstant.DY_ACCESS_TOKEN_KEY,accessToken,Long.parseLong(expiresIn), TimeUnit.SECONDS);
return accessToken;
}else {
throw convertDyException(GsonParser.parse(resultStr));
}
} catch (Exception e) {
log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", DYPayConstants.GET_ACCESS_TOKEN, requestStr, e.getMessage());
throw (e instanceof PayException) ? (PayException) e : new PayException(e.getMessage(), e);
}
}
/**
* post请求
*/
public String postRequest(String requestStr, String url) throws PayException {
return postRequest(0,requestStr,url);
}
/**
* post请求
*/
public String postRequest(int retryTimes, String requestStr, String url) throws PayException {
String resultStr = "";
try {
HttpHeaders headers = new HttpHeaders();
//所有的请求需要用JSON格式发送
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> formEntity = new HttpEntity<>(requestStr, headers);
resultStr = restTemplate.postForObject(url, formEntity, String.class);
if (StringUtils.isBlank(resultStr) || !resultStr.startsWith("{")){
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, resultStr);
throw new PayException("第三方返回格式有误!");
}
JSONObject resultObj = JSONObject.parseObject(resultStr);
String errNo = StringUtils.isNotBlank(resultObj.getString("err_no"))?resultObj.getString("err_no"):resultObj.getString("err_code");
if ("0".equals(errNo)) {
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, resultObj, resultStr);
return resultStr;
}else {
throw convertDyException(GsonParser.parse(resultStr));
}
}catch (PayException e){
log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
if (retryTimes > MAX_RETRY_TIMES){
throw new PayException("抖音接口调用失败,已超过最大重试次数");
}
//如果是access_token过期,刷新token在重试
if ("40004".equals(e.getErrCode())){
String accessToken = refreshAccessToken();
JSONObject requestJsonObj = JSON.parseObject(requestStr);
requestJsonObj.put("access_token",accessToken);
requestStr = requestJsonObj.toJSONString();
}
retryTimes ++;
postRequest(retryTimes,requestStr,url);
}
return resultStr;
}
/**
* 刷新access_token
*/
public String refreshAccessToken() throws PayException {
return refreshAccessToken(0);
}
/**
* 刷新access_token
* @param retryTimes
*/
public String refreshAccessToken(int retryTimes) throws PayException {
String accessToken = "";
try {
accessToken = getAccessToken( true);
} catch (PayException e) {
if (retryTimes > MAX_RETRY_TIMES){
throw new PayException("抖音接口获取AccessToken调用失败,已超过最大重试次数");
}
retryTimes ++;
refreshAccessToken(retryTimes);
}
return accessToken;
}
/**
* 转换异常
* @param jsonObject
* @return
*/
private PayException convertDyException(JsonObject jsonObject) {
JsonElement codeElement = jsonObject.get("err_no") != null ? jsonObject.get("err_no"):jsonObject.get("err_code");
String code = codeElement == null ? null : codeElement.getAsString();
String message = jsonObject.get("error_msg").getAsString();
PayException payException = new PayException(message);
payException.setErrCode(code);
payException.setErrCodeDes(message);
return payException;
}
}

186
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/manager/KsPayManager.java

@ -0,0 +1,186 @@
package com.bnyer.pay.manager;
import com.alibaba.fastjson.JSONObject;
import com.bnyer.common.core.constant.RedisKeyConstant;
import com.bnyer.common.core.domain.KspayConfig;
import com.bnyer.common.core.utils.SpringUtils;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.common.redis.service.RedisService;
import com.bnyer.pay.constant.KSPayConstants;
import com.bnyer.pay.exception.PayException;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.json.GsonParser;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* @author :WXC
* @Date :2023/04/24
* @description :
*/
@Slf4j
public class KsPayManager {
private RestTemplate restTemplate;
private RedisService redisService;
private final KspayConfig kspayConfig;
private final int MAX_RETRY_TIMES = 2;
public KsPayManager(KspayConfig kspayConfig){
this.kspayConfig = kspayConfig;
init();
}
private void init() {
this.restTemplate = SpringUtils.getBean(RestTemplate.class);
this.redisService = SpringUtils.getBean(RedisService.class);
}
/**
* 该授权方式使用 OAuth2 client credentials 模式获取小程序全局唯一后台接口调用凭据
*
* 说明access_token48小时内有效未超出有效截止时间开发者重新调用获取新的access_token则新老token同时有效避免token过期开发者可根据业务实际情况注意间隔请求时间不要超出48小时
* @param isRefresh
* @return
* @throws PayException
*/
public String getAccessToken(boolean isRefresh) throws PayException {
if (!isRefresh){
Object cacheObject = redisService.getCacheObject(RedisKeyConstant.KS_ACCESS_TOKEN_KEY);
if (Objects.nonNull(cacheObject)){
return cacheObject.toString();
}
}
String requestStr = "";
try {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> formEntity = new HttpEntity<>(MessageFormat.format("app_id={0}&app_secret={1}&&grant_type={2}"
, kspayConfig.getAppid(), kspayConfig.getSecret(), "client_credentials"), headers);
String resultStr = restTemplate.postForObject(KSPayConstants.GET_ACCESS_TOKEN, formEntity, String.class);
String url = KSPayConstants.GET_ACCESS_TOKEN;
requestStr = formEntity.getBody();
if (StringUtils.isBlank(resultStr) || !resultStr.startsWith("{")){
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, resultStr);
throw convertDyException(GsonParser.parse("第三方返回格式有误!"));
}
JSONObject resultObj = JSONObject.parseObject(resultStr);
String resultCode = resultObj.getString("result");
if ("1".equals(resultCode)) {
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, resultObj, resultStr);
//存入redis
String accessToken = resultObj.getString("access_token");
String expiresIn = resultObj.getString("expires_in");
redisService.setCacheObject(RedisKeyConstant.KS_ACCESS_TOKEN_KEY,accessToken,Long.parseLong(expiresIn), TimeUnit.SECONDS);
return accessToken;
}else {
throw convertDyException(GsonParser.parse(resultStr));
}
} catch (Exception e) {
log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", KSPayConstants.GET_ACCESS_TOKEN, requestStr, e.getMessage());
throw (e instanceof PayException) ? (PayException) e : new PayException(e.getMessage(), e);
}
}
/**
* post请求
*/
public String postRequest(String requestStr, String url) throws PayException {
Map<String, String> urlParams = new HashMap<>();
urlParams.put("app_id", kspayConfig.getAppid());
urlParams.put("access_token", getAccessToken(false));
return postRequest(0,urlParams,requestStr,url);
}
/**
* post请求
*/
public String postRequest(int retryTimes,Map<String, String> urlParams, String requestStr, String url) throws PayException {
String resultStr = "";
try {
HttpHeaders headers = new HttpHeaders();
//所有的请求需要用JSON格式发送
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> formEntity = new HttpEntity<>(requestStr, headers);
resultStr = restTemplate.postForObject(url + "/?app_id={app_id}&access_token={access_token}", formEntity, String.class, urlParams);
if (StringUtils.isBlank(resultStr) || !resultStr.startsWith("{")){
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, resultStr);
throw new PayException("第三方返回格式有误!");
}
JSONObject resultObj = JSONObject.parseObject(resultStr);
String resultCode = resultObj.getString("result");
if ("1".equals(resultCode)) {
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, resultObj, resultStr);
return resultStr;
}else {
throw convertDyException(GsonParser.parse(resultStr));
}
}catch (PayException e){
log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
if (retryTimes > MAX_RETRY_TIMES){
throw new PayException("快手接口调用失败,已超过最大重试次数");
}
//如果是access_token过期,刷新token在重试
if ("10000011".equals(e.getErrCode())){
urlParams.put("app_id", kspayConfig.getAppid());
urlParams.put("access_token", refreshAccessToken());
}
retryTimes ++;
postRequest(retryTimes,urlParams,requestStr,url);
}
return resultStr;
}
/**
* 刷新access_token
*/
public String refreshAccessToken() throws PayException {
return refreshAccessToken(0);
}
/**
* 刷新access_token
* @param retryTimes
*/
public String refreshAccessToken(int retryTimes) throws PayException {
String accessToken = "";
try {
accessToken = getAccessToken( true);
} catch (PayException e) {
if (retryTimes > MAX_RETRY_TIMES){
throw new PayException("快手接口获取AccessToken调用失败,已超过最大重试次数");
}
retryTimes ++;
refreshAccessToken(retryTimes);
}
return accessToken;
}
/**
* 转换异常
* @param jsonObject
* @return
*/
private PayException convertDyException(JsonObject jsonObject) {
JsonElement codeElement = jsonObject.get("result");
String code = codeElement == null ? null : codeElement.getAsString();
String message = jsonObject.get("error_msg").getAsString();
PayException payException = new PayException(message);
payException.setErrCode(code);
payException.setErrCodeDes(message);
return payException;
}
}

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

@ -28,4 +28,5 @@ public interface PayInfoService {
* @return
*/
PayInfoDetailsVo queryPayInfoDetails(String payId);
}

15
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/UnifiedPayService.java

@ -1,14 +1,11 @@
package com.bnyer.pay.service;
import com.bnyer.pay.bean.dto.RefundDto;
import com.bnyer.pay.bean.dto.UnifiedOrderDto;
import com.bnyer.pay.bean.dto.PushOrderDto;
import com.bnyer.pay.bean.dto.QueryOrderDto;
import com.bnyer.pay.bean.dto.RefundDto;
import com.bnyer.pay.bean.dto.UnifiedOrderExtDto;
import com.bnyer.pay.bean.vo.ThirdRefundVo;
import com.bnyer.pay.bean.vo.UnifiedOrderVo;
import com.bnyer.pay.bean.vo.QueryOrderVo;
import javax.servlet.http.HttpServletRequest;
import com.bnyer.pay.bean.vo.UnifiedOrderVo;
/**
* @author :WXC
@ -36,4 +33,10 @@ public interface UnifiedPayService {
* @param dto
*/
void refund(RefundDto dto);
/**
* 统一推送订单(目前暂时只有抖音支付需要)
* @param pushOrderDto
*/
void pushOrder(PushOrderDto pushOrderDto);
}

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

@ -4,6 +4,9 @@ import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.domain.PayInfo;
import com.bnyer.common.core.domain.R;
import com.bnyer.common.core.enums.EnumPayStatus;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.core.enums.EnumSceneCode;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
@ -11,20 +14,29 @@ import com.bnyer.common.core.utils.bean.EntityConvertUtil;
import com.bnyer.common.rocketmq.constant.RocketMqTag;
import com.bnyer.common.rocketmq.constant.RocketMqTopic;
import com.bnyer.common.rocketmq.domain.order.VipOrderPayNotifyMessage;
import com.bnyer.common.rocketmq.domain.pay.ThirdPayOrderPushMessage;
import com.bnyer.common.rocketmq.template.RocketMQEnhanceTemplate;
import com.bnyer.order.api.bean.query.VipOrderExtQuery;
import com.bnyer.order.api.bean.vo.VipOrderVo;
import com.bnyer.pay.bean.bo.PushOrderBo;
import com.bnyer.pay.bean.dto.AddPayInfoDto;
import com.bnyer.pay.bean.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.bean.dto.EditPayInfoSingleDto;
import com.bnyer.pay.bean.vo.PayInfoDetailsVo;
import com.bnyer.pay.design.factory.PayFactory;
import com.bnyer.pay.design.strategy.IPayStrategy;
import com.bnyer.pay.mapper.PayInfoMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.service.PayMqMessageRecordService;
import com.bnyer.pay.utils.MoneyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
@ -51,15 +63,8 @@ public class PayInfoServiceImpl implements PayInfoService {
*/
@Override
public void addPayInfo(AddPayInfoDto dto) {
//判断是否是原来的订单表订单号支付,如果是更新信息即可,否则创建支付单信息
PayInfo oldPayInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getOrderNo, dto.getOrderNo()));
PayInfo payInfo = dto.toEntity();
if (ObjectUtil.isNull(oldPayInfo)){
payInfoMapper.insert(payInfo);
}else {
payInfo.setId(oldPayInfo.getId());
payInfoMapper.updateById(payInfo);
}
}
/**
@ -94,9 +99,17 @@ public class PayInfoServiceImpl implements PayInfoService {
// 发送消息,订单支付成功
VipOrderPayNotifyMessage vipOrderPayNotifyMessage = new VipOrderPayNotifyMessage();
vipOrderPayNotifyMessage.setOrderNo(orderNo);
// rocketMQEnhanceTemplate.sendAsyncMsg(RocketMqTopic.ORDER_PAY_NOTIFY_TOPIC, RocketMqTag.ORDER_VIP_TAG, vipOrderPayNotifyMessage);
mqMessageRecordService.sendAsyncMsg(RocketMqTopic.ORDER_PAY_NOTIFY_TOPIC, RocketMqTag.ORDER_VIP_TAG, vipOrderPayNotifyMessage);
break;
default:
throw new ServiceException("未匹配上对应的支付场景");
}
//推送订单
EnumPayType enumPayType = EnumPayType.getEnumPayTypeByType(payInfo.getPayType());
if (EnumPayType.DY_PAY == enumPayType){
ThirdPayOrderPushMessage thirdPayOrderPushMessage = new ThirdPayOrderPushMessage();
thirdPayOrderPushMessage.setPayId(payInfo.getPayId());
mqMessageRecordService.sendAsyncMsg(RocketMqTopic.THIRD_PAY_ORDER_PUSH_TOPIC,null,thirdPayOrderPushMessage);
}
}
@ -129,4 +142,5 @@ public class PayInfoServiceImpl implements PayInfoService {
PayInfoDetailsVo payInfoDetailsVo = EntityConvertUtil.copy(payInfo, PayInfoDetailsVo.class);
return payInfoDetailsVo;
}
}

83
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java

@ -3,6 +3,7 @@ package com.bnyer.pay.service.impl;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.domain.PayInfo;
import com.bnyer.common.core.domain.R;
@ -11,12 +12,14 @@ import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.OrderUtil;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.common.core.utils.bean.EntityConvertUtil;
import com.bnyer.common.core.utils.ip.IpUtils;
import com.bnyer.common.core.vo.UserInfoVo;
import com.bnyer.common.rocketmq.constant.RocketMqTopic;
import com.bnyer.common.rocketmq.domain.pay.ThirdPayOrderPushMessage;
import com.bnyer.common.security.utils.SecurityUtils;
import com.bnyer.order.api.bean.query.VipOrderExtQuery;
import com.bnyer.order.api.bean.vo.VipOrderVo;
import com.bnyer.order.api.remote.RemoteVipOrderService;
import com.bnyer.pay.bean.bo.PushOrderBo;
import com.bnyer.pay.bean.bo.QueryOrderBo;
import com.bnyer.pay.bean.bo.RefundBo;
import com.bnyer.pay.bean.bo.UnifiedOrderBo;
@ -31,14 +34,18 @@ import com.bnyer.pay.enums.EnumKsPayStatus;
import com.bnyer.pay.enums.EnumWxPayStatus;
import com.bnyer.pay.mapper.PayInfoMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.service.PayMqMessageRecordService;
import com.bnyer.pay.service.UnifiedPayService;
import com.bnyer.pay.utils.MoneyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
@ -56,6 +63,9 @@ public class UnifiedPayServiceImpl implements UnifiedPayService {
@Autowired
private PayInfoService payInfoService;
@Resource
private PayMqMessageRecordService mqMessageRecordService;
@Autowired
private RemoteVipOrderService remoteVipOrderService;
@ -114,6 +124,13 @@ public class UnifiedPayServiceImpl implements UnifiedPayService {
AddPayInfoDto addPayInfoDto = buildPayInfo(thirdUnifiedOrderVo, unifiedOrderBo,dto);
payInfoService.addPayInfo(addPayInfoDto);
UnifiedOrderVo unifiedOrderVo = EntityConvertUtil.copy(thirdUnifiedOrderVo, UnifiedOrderVo.class);
//推送订单
EnumPayType enumPayType = EnumPayType.getEnumPayTypeByType(addPayInfoDto.getPayType());
if (EnumPayType.DY_PAY == enumPayType){
ThirdPayOrderPushMessage thirdPayOrderPushMessage = new ThirdPayOrderPushMessage();
thirdPayOrderPushMessage.setPayId(addPayInfoDto.getPayId());
mqMessageRecordService.sendAsyncMsg(RocketMqTopic.THIRD_PAY_ORDER_PUSH_TOPIC,null,thirdPayOrderPushMessage);
}
return unifiedOrderVo;
}
@ -332,4 +349,68 @@ public class UnifiedPayServiceImpl implements UnifiedPayService {
return payInfo;
}
/**
* 推送订单
* @param pushOrderDto
*/
@Override
public void pushOrder(PushOrderDto pushOrderDto) {
PayInfo payInfo = null;
if (StringUtils.isNotBlank(pushOrderDto.getPayId())){
payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayId, pushOrderDto.getPayId()));
}
if (Objects.isNull(payInfo)){
log.error("推送失败,订单信息不存在,pushOrderDto:{}",JSON.toJSONString(pushOrderDto));
throw new ServiceException("订单信息不存在");
}
EnumSceneCode enumSceneCode = EnumSceneCode.getSceneCodeByCode(payInfo.getSceneCode());
PushOrderBo pushOrderBo = null;
//构建各个场景推送订单,并统一入口参数
switch (enumSceneCode){
case VIP_RECHARGE:
pushOrderBo = buildVipPushOrder(payInfo);
break;
case UNKNOWN:
throw new ServiceException("未匹配上对应的场景编码");
}
IPayStrategy payStrategy = PayFactory.getInstance().getConcreteStrategy(payInfo.getPayType());
//开始推送
payStrategy.pushOrder(pushOrderBo);
}
/**
* 构建会员场景推送订单信息
* @param payInfo
* @return
*/
private PushOrderBo buildVipPushOrder(PayInfo payInfo) {
//查询订单服务:会员订单信息表
VipOrderExtQuery vipOrderExtQuery = new VipOrderExtQuery();
vipOrderExtQuery.setOrderNo(payInfo.getOrderNo());
R<VipOrderVo> vipOrderVoR = remoteVipOrderService.queryVipOrder(vipOrderExtQuery);
if (!vipOrderVoR.isSuccess()){
log.error("内部接口:查询会员订单调用失败:request:{} result{}", JSON.toJSONString(vipOrderExtQuery),JSON.toJSONString(vipOrderVoR));
throw new ServiceException(vipOrderVoR.getMsg());
}
PushOrderBo pushOrderBo = new PushOrderBo();
VipOrderVo vipOrderVo = vipOrderVoR.getData();
List<PushOrderBo.Goods> goodsList = new ArrayList<>();
//封装商品信息
PushOrderBo.Goods goods = new PushOrderBo.Goods();
// TODO: 2023/06/08 会员写死1,目前只支持一个订单买一个商品,不可以选择购买多个商品下单所以会员场景写死成1即可,若以后需求有变动在说
goods.setGoodsNum(1);
goods.setImg("");
goods.setItemCode(vipOrderVo.getVipCode());
goods.setPrice(Integer.parseInt(MoneyUtil.yuanToFen(vipOrderVo.getPayAmount().toString())));
goods.setTitle(payInfo.getGoodsSubject());
pushOrderBo.setGoodsNum(goodsList.size());
pushOrderBo.setUpdateTime(payInfo.getUpdateTime());
pushOrderBo.setCreateTime(payInfo.getCreateTime());
pushOrderBo.setPayStatus(EnumPayStatus.getEnumPayStatusByStatus(payInfo.getPayStatus()));
pushOrderBo.setPayId(payInfo.getPayId());
pushOrderBo.setGoodsList(goodsList);
return pushOrderBo;
}
}

376
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PayRestTemplateUtil.java

@ -1,107 +1,269 @@
package com.bnyer.pay.utils;
import com.alibaba.fastjson.JSONObject;
import com.bnyer.common.core.domain.KspayConfig;
import com.bnyer.pay.constant.KSPayConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
/**
* @author :WXC
* @Date :2023/04/24
* @description :
*/
@Slf4j
@Component
public class PayRestTemplateUtil {
@Autowired
private RestTemplate restTemplate;
/**
* 快手小程序post请求
* code2session
*/
public String ksPostRequestUrlencoded(JSONObject jsonObject, String url) {
String result = "";
try {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> formEntity = new HttpEntity<>(MessageFormat.format("js_code={0}&app_id={1}&&app_secret={2}", jsonObject.get("js_code"), jsonObject.get("appid"), jsonObject.get("secret")), headers);
result = restTemplate.postForObject(url, formEntity, String.class);
} catch (Exception e) {
log.error("快手小程序post请求异常{}", url);
log.error("post请求异常:{}", e.getMessage());
e.printStackTrace();
}
return result;
}
/**
* 快手小程序获取accessToken
*/
public String ksPostRequestUrlencoded(KspayConfig kspayConfig) {
String result = "";
try {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> formEntity = new HttpEntity<>(MessageFormat.format("app_id={0}&app_secret={1}&&grant_type={2}"
, kspayConfig.getAppid(), kspayConfig.getSecret(), "client_credentials"), headers);
result = restTemplate.postForObject(KSPayConstants.GET_ACCESS_TOKEN, formEntity, String.class);
} catch (Exception e) {
log.error("快手小程序post请求异常{}", KSPayConstants.GET_ACCESS_TOKEN);
log.error("post请求异常:{}", e.getMessage());
e.printStackTrace();
}
return result;
}
/**
* 快手
* 支付 退款 结算
*/
public String ksPostRequestJson(JSONObject jsonObject, String url, String appId, String accessToken) {
String result = "";
try {
Map<String, String> map = new HashMap<>();
map.put("app_id", appId);
map.put("access_token", accessToken);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> formEntity = new HttpEntity<>(jsonObject, headers);
result = restTemplate.postForObject(url + "/?app_id={app_id}&access_token={access_token}", formEntity, String.class, map);
} catch (Exception e) {
log.error("快手小程序post请求异常{}", url);
log.error("post请求异常:{}", e.getMessage());
e.printStackTrace();
}
return result;
}
/**
* 抖音小程序post请求
*/
public String dyPostRequest(JSONObject jsonObject, String url) {
String result = "";
try {
HttpHeaders headers = new HttpHeaders();
//所有的请求需要用JSON格式发送
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> formEntity = new HttpEntity<>(jsonObject, headers);
result = restTemplate.postForObject(url, formEntity, String.class);
} catch (Exception e) {
log.error("抖音小程序post请求异常{}", url);
e.printStackTrace();
}
return result;
}
}
//package com.bnyer.pay.utils;
//
//import com.alibaba.fastjson.JSONObject;
//import com.bnyer.common.core.constant.RedisKeyConstant;
//import com.bnyer.common.core.domain.DypayConfig;
//import com.bnyer.common.core.domain.KspayConfig;
//import com.bnyer.common.core.exception.ServiceException;
//import com.bnyer.common.core.utils.StringUtils;
//import com.bnyer.common.redis.service.RedisService;
//import com.bnyer.pay.constant.DYPayConstants;
//import com.bnyer.pay.constant.KSPayConstants;
//import com.bnyer.pay.exception.DyPayException;
//import com.google.gson.JsonElement;
//import com.google.gson.JsonObject;
//import lombok.extern.slf4j.Slf4j;
//import me.chanjar.weixin.common.util.json.GsonParser;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.http.HttpEntity;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.MediaType;
//import org.springframework.stereotype.Component;
//import org.springframework.web.client.RestTemplate;
//
//import java.text.MessageFormat;
//import java.util.HashMap;
//import java.util.Map;
//import java.util.Objects;
//import java.util.concurrent.TimeUnit;
//
///**
// * @author :WXC
// * @Date :2023/04/24
// * @description :
// */
//@Slf4j
//@Component
//public class PayRestTemplateUtil {
//
// @Autowired
// private RestTemplate restTemplate;
//
// @Autowired
// private RedisService redisService;
//
// private final int MAX_RETRY_TIMES = 2;
//
// /**
// * 快手小程序post请求
// * code2session
// */
// public String ksPostRequestUrlencoded(JSONObject jsonObject, String url) {
// String result = "";
// try {
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// HttpEntity<String> formEntity = new HttpEntity<>(MessageFormat.format("js_code={0}&app_id={1}&&app_secret={2}", jsonObject.get("js_code"), jsonObject.get("appid"), jsonObject.get("secret")), headers);
// result = restTemplate.postForObject(url, formEntity, String.class);
// } catch (Exception e) {
// log.error("快手小程序post请求异常{}", url);
// log.error("post请求异常:{}", e.getMessage());
// e.printStackTrace();
// }
// return result;
// }
//
// /**
// * 快手小程序获取accessToken
// */
// public String ksPostRequestUrlencoded(KspayConfig kspayConfig,boolean isRefresh) {
// if (!isRefresh){
// Object cacheObject = redisService.getCacheObject(RedisKeyConstant.KS_ACCESS_TOKEN_KEY);
// if (Objects.nonNull(cacheObject)){
// return cacheObject.toString();
// }
// }
// String accessToken = "";
// try {
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// HttpEntity<String> formEntity = new HttpEntity<>(MessageFormat.format("app_id={0}&app_secret={1}&&grant_type={2}"
// , kspayConfig.getAppid(), kspayConfig.getSecret(), "client_credentials"), headers);
// accessToken = restTemplate.postForObject(KSPayConstants.GET_ACCESS_TOKEN, formEntity, String.class);
// //存入redis
// redisService.setCacheObject(RedisKeyConstant.KS_ACCESS_TOKEN_KEY,accessToken,2L, TimeUnit.HOURS);
// } catch (Exception e) {
// log.error("快手小程序post请求异常{}", KSPayConstants.GET_ACCESS_TOKEN);
// log.error("post请求异常:{}", e.getMessage());
// e.printStackTrace();
// }
// return accessToken;
// }
//
// /**
// * 快手
// * 支付 退款 结算
// */
// public String ksPostRequestJson(JSONObject jsonObject, String url, String appId, String accessToken) {
// String result = "";
// try {
// Map<String, String> map = new HashMap<>();
// map.put("app_id", appId);
// map.put("access_token", accessToken);
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_JSON);
// HttpEntity<Object> formEntity = new HttpEntity<>(jsonObject, headers);
// result = restTemplate.postForObject(url + "/?app_id={app_id}&access_token={access_token}", formEntity, String.class, map);
// } catch (Exception e) {
// log.error("快手小程序post请求异常{}", url);
// log.error("post请求异常:{}", e.getMessage());
// e.printStackTrace();
// }
// return result;
// }
//
// /**
// * 抖音小程序获取accessToken
// * 为了保障应用的数据安全,只能在开发者服务器使用 AppSecret,如果小程序存在泄露 AppSecret 的问题,字节小程序平台将有可能下架该小程序,并暂停该小程序相关服务。
// *
// * access_token 是小程序的全局唯一调用凭据,开发者调用小程序支付时需要使用 access_token。access_token 的有效期为 2 个小时,需要定时刷新 access_token,重复获取会导致之前一次获取的 access_token 的有效期缩短为 5 分钟。
// */
// public String dyGetAccessToken(DypayConfig dypayConfig,boolean isRefresh) throws DyPayException {
// if (!isRefresh){
// Object cacheObject = redisService.getCacheObject(RedisKeyConstant.DY_ACCESS_TOKEN_KEY);
// if (Objects.nonNull(cacheObject)){
// return cacheObject.toString();
// }
// }
// String requestStr = "";
// try {
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// HttpEntity<String> formEntity = new HttpEntity<>(MessageFormat.format("app_id={0}&app_secret={1}&&grant_type={2}"
// , dypayConfig.getAppid(), dypayConfig.getAppSecret(), "client_credentials"), headers);
// String resultStr = restTemplate.postForObject(DYPayConstants.GET_ACCESS_TOKEN, formEntity, String.class);
// String url = DYPayConstants.GET_ACCESS_TOKEN;
// requestStr = formEntity.getBody();
// if (StringUtils.isBlank(resultStr) || !resultStr.startsWith("{")){
// log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, resultStr);
// throw convertDyException(GsonParser.parse("第三方返回格式有误!"));
// }
// JSONObject resultObj = JSONObject.parseObject(resultStr);
// String errNo = StringUtils.isNotBlank(resultObj.getString("err_no"))?resultObj.getString("err_no"):resultObj.getString("err_code");
// if (!"0".equals(errNo)) {
// log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, resultObj, resultStr);
// //存入redis
// String accessToken = resultObj.getJSONObject("data").getString("access_token");
// String expiresIn = resultObj.getJSONObject("data").getString("expires_in");
// redisService.setCacheObject(RedisKeyConstant.DY_ACCESS_TOKEN_KEY,accessToken,Long.parseLong(expiresIn), TimeUnit.SECONDS);
// return accessToken;
// }else {
// throw convertDyException(GsonParser.parse(resultStr));
// }
// } catch (Exception e) {
// log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", DYPayConstants.GET_ACCESS_TOKEN, requestStr, e.getMessage());
// throw (e instanceof DyPayException) ? (DyPayException) e : new DyPayException(e.getMessage(), e);
// }
// }
//
// /**
// * 抖音小程序post请求
// */
// public String dyPostRequest(String requestStr, String url) throws DyPayException {
// return dyPostRequest(0,requestStr,url);
// }
//
// /**
// * 抖音小程序post请求
// */
// public String dyPostRequest(int retryTimes, String requestStr, String url) throws DyPayException {
// String resultStr = "";
// try {
// HttpHeaders headers = new HttpHeaders();
// //所有的请求需要用JSON格式发送
// headers.setContentType(MediaType.APPLICATION_JSON);
// HttpEntity<Object> formEntity = new HttpEntity<>(requestStr, headers);
// resultStr = restTemplate.postForObject(url, formEntity, String.class);
// if (StringUtils.isBlank(resultStr) || !resultStr.startsWith("{")){
// log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, resultStr);
// throw new DyPayException("第三方返回格式有误!");
// }
// JSONObject resultObj = JSONObject.parseObject(resultStr);
// String errNo = StringUtils.isNotBlank(resultObj.getString("err_no"))?resultObj.getString("err_no"):resultObj.getString("err_code");
// if (!"0".equals(errNo)) {
// log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, resultObj, resultStr);
// return resultStr;
// }else {
// throw convertDyException(GsonParser.parse(resultStr));
// }
// }catch (DyPayException e){
// log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
// String accessToken = refreshAccessToken(dypayConfig, requestStr, DYPayConstants.ORDER_PUSH, e);
// if (retryTimes > MAX_RETRY_TIMES){
// throw new DyPayException("抖音接口调用失败,已超过最大重试次数");
// }
// retryTimes ++;
// dyPostRequest(retryTimes,requestStr,url);
// }
// return resultStr;
// }
//
// /**
// * token过期请求重试
// * @param dypayConfig
// * @param requestStr
// * @param e
// */
// private String refreshAccessToken(DypayConfig dypayConfig,String url, String requestStr, DyPayException e) {
// //如果token过期的话,刷新token并重试
// String accessToken = "";
// if ("4004".equals(e.getErrCode())){
// try {
// accessToken = dyRefreshAccessToken(dypayConfig);
// } catch (DyPayException dyPayException) {
// throw new ServiceException(dyPayException.getMessage());
// }
// }
// String result = "";
// if ("4004".equals(e.getErrCode())){
// try {
// result = dyPostRequest(requestStr, url);
// } catch (DyPayException dyPayException) {
// log.error("抖音支付:抖音订单推送接口调用异常,request:{},error{}", requestStr, e.getMessage());
// }
// }
// return accessToken;
// }
//
// /**
// * 刷新抖音token
// * @param dypayConfig
// */
// public String dyRefreshAccessToken(DypayConfig dypayConfig) throws DyPayException {
// return dyRefreshAccessToken(0,dypayConfig);
// }
//
// /**
// * 刷新抖音token
// * @param retryTimes
// * @param dypayConfig
// */
// public String dyRefreshAccessToken(int retryTimes, DypayConfig dypayConfig) throws DyPayException {
// String accessToken = "";
// try {
// accessToken = dyGetAccessToken(dypayConfig, true);
// } catch (DyPayException e) {
// if (retryTimes > MAX_RETRY_TIMES){
// throw new DyPayException("抖音接口调用失败,已超过最大重试次数");
// }
// retryTimes ++;
// dyRefreshAccessToken(retryTimes, dypayConfig);
// }
// return accessToken;
// }
//
// /**
// * 抖音转换异常
// * @param jsonObject
// * @return
// */
// private DyPayException convertDyException(JsonObject jsonObject) {
// JsonElement codeElement = jsonObject.get("err_no") != null ? jsonObject.get("err_no"):jsonObject.get("err_code");
// String code = codeElement == null ? null : codeElement.getAsString();
// String message = jsonObject.get("error_msg").getAsString();
// DyPayException dyPayException = new DyPayException(message);
// dyPayException.setErrCode(code);
// dyPayException.setErrCodeDes(message);
// return dyPayException;
// }
//}

3
bnyer-services/bnyer-pay/src/main/resources/com/bnyer/pay/mapper/DypayConfigMapper.xml

@ -6,6 +6,7 @@
<!--@Table pay_dypay_config-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="appid" jdbcType="VARCHAR" property="appid" />
<result column="app_secret" jdbcType="VARCHAR" property="appSecret" />
<result column="salt" jdbcType="VARCHAR" property="salt" />
<result column="token" jdbcType="VARCHAR" property="token" />
<result column="backurl" jdbcType="VARCHAR" property="backurl" />
@ -18,6 +19,6 @@
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, appid,salt, token, backurl, `status`, remark, create_time, update_time,sort,is_show
id, appid,app_secret,salt, token, backurl, `status`, remark, create_time, update_time,sort,is_show
</sql>
</mapper>

Loading…
Cancel
Save