支付服务接口设计

支付服务接口设计

支付抽象类 (实现基础支付接口类)

基础支付接口类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Payment {

/**
* 发起交易执行的过程
* @param request
* @return
* @throws BizException
*/
<T extends AbstractResponse> T process(AbstractRequest request) throws BizException;

/**
* 完成交易结果的处理
* @param request
* @return
* @throws BizException
*/
<T extends AbstractResponse> T completePayment(PaymentNotifyRequest request) throws BizException;
}

支付抽象类

  • 创建上下文数据
  • 验证器验证数据
  • 执行前准备数据
  • 执行操作
  • 执行后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public abstract class BasePayment implements Payment {

protected final Logger log = LoggerFactory.getLogger(this.getClass());

public static Map<String, BasePayment> paymentMap = new ConcurrentHashMap<String, BasePayment>();

@PostConstruct
public void init() {
paymentMap.put(getPayChannel(), this);
}

/**
* 获取验证器
*
* @return
*/
public abstract Validator getValidator();

/**
* 创建上下文信息
*
* @param request
* @return
*/
public abstract Context createContext(AbstractRequest request);

/**
* 为下层的支付渠道的数据做好准备
*
* @param request
* @param context
* @throws BizException
*/
public void prepare(AbstractRequest request, Context context)throws BizException{
SortedMap<String, Object> sParaTemp = new TreeMap<String, Object>();
context.setsParaTemp(sParaTemp);
};


/**
* 基本业务处理
*
* @param request
* @param context
* @return AbstractResponse
* @throws BizException
*/
public abstract AbstractResponse generalProcess(AbstractRequest request, Context context) throws BizException;

/***
* 基本业务处理完成后执行的后续操作
* @param request
* @param respond
* @param context
* @return
* @throws BizException
*/
public abstract void afterProcess(AbstractRequest request, AbstractResponse respond,Context context) throws BizException;

/**
* 核心处理器
*/
@Override
public <T extends AbstractResponse> T process(AbstractRequest request) throws BizException {
log.info("Begin BasePayment.process:{}", JSON.toJSONString(request));
AbstractResponse response = null;
//创建上下文
Context context = createContext(request);
//验证
getValidator().validate(request);
//准备
prepare(request, context);
//执行
response = generalProcess(request, context);
//善后
afterProcess(request, response, context);
return (T) response;
}

/**
* 获取支付渠道
*
* @return
*/
public abstract String getPayChannel();
}

支付接口类 – 接口实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface PayCoreService {


/**
* 执行支付操作
* @param request
* @return
*/
PaymentResponse execPay(PaymentRequest request);


/**
* 支付、退款结果通知处理(等待微信或者支付宝异步通知支付结果)
* @param request
* @return
*/
PaymentNotifyResponse paymentResultNotify(PaymentNotifyRequest request);

/**
* 执行退款
* @param refundRequest
* @return
*/
RefundResponse execRefund(RefundRequest refundRequest);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@Slf4j
@Service(cluster = "failover")
public class PayCoreServiceImpl implements PayCoreService {

/**
* 执行支付操作
* @param request
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public PaymentResponse execPay(PaymentRequest request) {

PaymentResponse paymentResponse=new PaymentResponse();
try {
paymentResponse=BasePayment.paymentMap.get(request.getPayChannel()).process(request);
}catch (Exception e){
log.error("PayCoreServiceImpl.execPay Occur Exception :"+e);
ExceptionProcessorUtils.wrapperHandlerException(paymentResponse,e);
}
return paymentResponse;
}

/**
* 支付、退款结果通知处理(等待微信或者支付宝异步通知支付结果)
* @param request
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public PaymentNotifyResponse paymentResultNotify(PaymentNotifyRequest request) {
log.info("paymentResultNotify request:{}", JSON.toJSONString(request));
PaymentNotifyResponse response=new PaymentNotifyResponse();
try{
response=BasePayment.paymentMap.get
(request.getPayChannel()).completePayment(request);

}catch (Exception e){
log.error("paymentResultNotify occur exception:"+e);
ExceptionProcessorUtils.wrapperHandlerException(response,e);
}finally {
log.info("paymentResultNotify return result:{}",JSON.toJSONString(response));
}
return response;
}

/**
* 执行退款
* @param refundRequest
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public RefundResponse execRefund(RefundRequest refundRequest) {
RefundResponse refundResponse=new RefundResponse();
try {
refundResponse=BasePayment.paymentMap.get(refundRequest.getPayChannel()).process(refundRequest);
}catch (Exception e){
log.error("PayCoreServiceImpl.execRefund Occur Exception :{}",e);
ExceptionProcessorUtils.wrapperHandlerException(refundResponse,e);
}
return refundResponse;
}
}

统一支付接口、退款接口 、支付退款通知回调接口

  • 区分 渠道channel (微信 支付宝)
  • 待扩张 【支付方式 ( pay Mode 主要区分微信多种支付方式)】
  • 每一种支付方式一个实现类来实现支付接口类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
@Slf4j
@Service("wechatPayment")
public class WechatPayment extends BasePayment {

@Autowired
private WechatPaymentConfig wechatPaymentConfig;

@Resource(name = "wechatPaymentValidator")
private Validator validator;

@Autowired
private PaymentMapper paymentMapper;

@Autowired
GlobalIdGeneratorUtil globalIdGeneratorUtil;

private final String COMMENT_GLOBAL_ID_CACHE_KEY = "COMMENT_ID";

@Reference(timeout = 3000)
OrderCoreService orderCoreService;

@Override
public Validator getValidator() {
return validator;
}

@Override
public Context createContext(AbstractRequest request) {
WechatPaymentContext wechatPaymentContext = new WechatPaymentContext();
PaymentRequest paymentRequest = (PaymentRequest) request;
wechatPaymentContext.setOutTradeNo(paymentRequest.getTradeNo());
wechatPaymentContext.setProductId(paymentRequest.getTradeNo());
wechatPaymentContext.setSpbillCreateIp(paymentRequest.getSpbillCreateIp());
wechatPaymentContext.setTradeType(PaymentConstants.TradeTypeEnum.NATIVE.getType());
wechatPaymentContext.setTotalFee(paymentRequest.getTotalFee());
wechatPaymentContext.setBody(paymentRequest.getSubject());
return wechatPaymentContext;
}

@Override
public void prepare(AbstractRequest request, Context context) throws BizException {
super.prepare(request, context);
SortedMap paraMap = context.getsParaTemp();
WechatPaymentContext wechatPaymentContext = (WechatPaymentContext) context;
paraMap.put("body", wechatPaymentContext.getBody());
paraMap.put("out_trade_no", wechatPaymentContext.getOutTradeNo());
//单位分
paraMap.put("total_fee", wechatPaymentContext.getTotalFee().multiply(new BigDecimal("100")).intValue());
paraMap.put("spbill_create_ip", wechatPaymentContext.getSpbillCreateIp());
paraMap.put("appid", wechatPaymentConfig.getWechatAppid());
paraMap.put("mch_id", wechatPaymentConfig.getWechatMch_id());
paraMap.put("nonce_str", WeChatBuildRequest.getNonceStr());
paraMap.put("trade_type", wechatPaymentContext.getTradeType());
paraMap.put("product_id", wechatPaymentContext.getProductId());
// 此路径是微信服务器调用支付结果通知路径
paraMap.put("device_info", "WEB");
paraMap.put("notify_url", wechatPaymentConfig.getWechatNotifyurl());
//二维码的失效时间(5分钟)
paraMap.put("time_expire", UtilDate.getExpireTime(30 * 60 * 1000L));
String sign = WeChatBuildRequest.createSign(paraMap, wechatPaymentConfig.getWechatMchsecret());
paraMap.put("sign", sign);
log.info("微信生成sign:{}", JSON.toJSONString(paraMap));
String xml = WeChatBuildRequest.getRequestXml(paraMap);
wechatPaymentContext.setXml(xml);
}

@Override
public AbstractResponse generalProcess(AbstractRequest request, Context context) throws BizException {
PaymentResponse response = new PaymentResponse();
WechatPaymentContext wechatPaymentContext = (WechatPaymentContext) context;
log.info("微信支付组装的请求参数:{}", wechatPaymentContext.getXml());
String xml = HttpClientUtil.httpPost(wechatPaymentConfig.getWechatUnifiedOrder(), wechatPaymentContext.getXml());
log.info("微信支付同步返回的结果:{}", xml);
Map<String, String> resultMap = WeChatBuildRequest.doXMLParse(xml);
if ("SUCCESS".equals(resultMap.get("return_code"))) {
if ("SUCCESS".equals(resultMap.get("result_code"))) {
response.setPrepayId(resultMap.get("prepay_id"));
response.setCodeUrl(resultMap.get("code_url"));
response.setCode(PayReturnCodeEnum.SUCCESS.getCode());
response.setMsg(PayReturnCodeEnum.SUCCESS.getMsg());
} else {
String errMsg = resultMap.get("err_code") + ":" + resultMap.get("err_code_des");
response.setCode(PayReturnCodeEnum.PAYMENT_PROCESSOR_FAILED.getCode());
response.setMsg(PayReturnCodeEnum.PAYMENT_PROCESSOR_FAILED.getMsg(errMsg));
}
} else {
response.setCode(PayReturnCodeEnum.PAYMENT_PROCESSOR_FAILED.getCode());
response.setMsg(PayReturnCodeEnum.PAYMENT_PROCESSOR_FAILED.getMsg(resultMap.get("return_msg")));
}
return response;
}

@Override
public void afterProcess(AbstractRequest request, AbstractResponse respond, Context context) throws BizException {
//插入支付表
log.info("Alipayment begin - afterProcess -request:" + request + "\n response:" + respond);
PaymentRequest paymentRequest = (PaymentRequest) request;
//插入支付记录表
PaymentResponse response = (PaymentResponse) respond;
Payment payment = new Payment();
payment.setCreateTime(new Date());
BigDecimal amount = paymentRequest.getOrderFee();
payment.setOrderAmount(amount);
payment.setOrderId(paymentRequest.getTradeNo());
//payment.setTradeNo(globalIdGeneratorUtil.getNextSeq(COMMENT_GLOBAL_ID_CACHE_KEY, 1));
payment.setPayerAmount(amount);
payment.setPayerUid(paymentRequest.getUserId());
payment.setPayerName("");//TODO
payment.setPayWay(paymentRequest.getPayChannel());
payment.setProductName(paymentRequest.getSubject());
payment.setStatus(PayResultEnum.TRADE_PROCESSING.getCode());//
payment.setRemark("微信支付");
payment.setPayNo(response.getPrepayId());//第三方的交易id
payment.setUpdateTime(new Date());
paymentMapper.insert(payment);
}

@Override
public String getPayChannel() {
return PayChannelEnum.WECHAT_PAY.getCode();
}


@Override
public AbstractResponse completePayment(PaymentNotifyRequest request) throws BizException {
request.requestCheck();
PaymentNotifyResponse response = new PaymentNotifyResponse();
Map xmlMap = new HashMap();
String xml = request.getXml();
try {
xmlMap = WXPayUtil.xmlToMap(xml);
} catch (Exception e) {
e.printStackTrace();
}
SortedMap<Object, Object> paraMap = new TreeMap<>();
xmlMap.forEach(paraMap::put);
//组装返回的结果的签名字符串
String rsSign = paraMap.remove("sign").toString();
String sign = WeChatBuildRequest.createSign(paraMap, wechatPaymentConfig.getWechatMchsecret());
//验证签名
if (rsSign.equals(sign)) {
//SUCCESS、FAIL
String resultCode = paraMap.get("return_code").toString();
if ("SUCCESS".equals(resultCode)) {
if ("SUCCESS".equals(paraMap.get("result_code"))) {
//更新支付表
Payment payment = new Payment();
payment.setStatus(PayResultEnum.TRADE_SUCCESS.getCode());
payment.setPaySuccessTime((UtilDate.parseStrToDate(UtilDate.simple,paraMap.get("time_end").toString(),new Date())));
Example example = new Example(Payment.class);
example.createCriteria().andEqualTo("orderId", paraMap.get("out_trade_no"));
paymentMapper.updateByExampleSelective(payment, example);
//更新订单表状态
orderCoreService.updateOrder(1, paraMap.get("out_trade_no").toString());
response.setResult(WeChatBuildRequest.setXML("SUCCESS", "OK"));
}
}
} else {
throw new BizException("微信返回结果签名验证失败");
}
return response;
}
}