说明:本文思路纯粹个人的想法,希望过路大神提点
名词解释
1、电商商户发起支付:得到支付场景、支付方式、电商商户号、订单类型[普通订单或国际订单]
2、筛选 <电商商户与支付通道的关系> 得到 支付通道列表 C1
3、根据支付方式和订单类型筛选[支付通道列表C1] 得到 [支付通道列表 C2]
4、若[支付通道列表C2]只有1条数据,则直接使用该通道调接口进行支付
4.1、若[支付通道列表C2]只有1条数据,则直接使用该通道调接口进行支付
4.2、若[支付通道列表C2]有多条数据,则读取路由策略。
4.2.1、根据路由策略排序得到最优通道,使用最优通道进行支付
1、支付服务统一接口
public interface IPaymentService {
/**
* 第三方pc支付统一接口
* @param payRequest
* @return
*/
ChannelPCPayResponse pay(ChannelPCPayRequest payRequest);
/**
* 第三方wap支付统一接口
* @param payRequest
* @return
*/
ChannelWAPPayResponse pay(ChannelWAPPayRequest payRequest);
/**
* 小程序支付
* @param payRequest
* @return
*/
ChannelXCXPayResponse pay(ChannelXCXPayRequest payRequest);
/**
* 公众号支付
* @param payRequest
* @return
*/
ChannelMPPayResponse pay(ChannelMPPayRequest payRequest);
/**
* APP支付
* @param payRequest
* @return
*/
ChannelAPPPayResponse pay(ChannelAPPPayRequest payRequest);
/**
* 扫码支付
* @param payRequest
* @return
*/
ChannelSCANPayResponse pay(ChannelSCANPayRequest payRequest);
/**
* 被扫支付(商户主扫)
* @param payRequest
* @return
*/
ChannelMercSCANPayResponse pay(ChannelMercSCANPayRequest payRequest);
}
2、路由适配器
public interface IRouterService {
/**
* 支付接口路由,选择合适的支付接口
* 目前根据支付方式,选择微信、支付宝、银联
* 根据订单类型,选择国际通道或普通通道(支付宝国际,或微信国际)
* ...
* @return
*/
public PaymentInterfaceResponse router(RouterModel routerModel);
/**
* 根据通道代码直接查找支付处理类
* @param channelCode
* @return
*/
public PaymentInterfaceResponse router(String channelCode);
}
3、路由适配器返回对象
public class PaymentInterfaceResponse {
/**
* 通道编码
*/
private String channelCode;
/**
* 支付方式
*/
private String payWayCode;
/**
* 支付服务实例对象
*/
private IPaymentService paymentService;
}
4、路由适配器实现原理
public PaymentInterfaceResponse router(RouterModel routerModel) {
// TODO Auto-generated method stub
PayChannel channel = null;
//1、根据电商商户号、支付方式和订单类型查询可使用的通道
List channels = payChannelMapper.findPayChannel(routerModel.getMerchantNo(),
routerModel.getPayWayCode(),routerModel.getPaySence(),routerModel.getOrderType());
//2、对通道进行筛选
if(channels == null || channels.size()<=0){
logger.info("路由没找到对应的支付通道,merchantNo:"+routerModel.getMerchantNo()+",payway:"
+routerModel.getPayWayCode()+",paySence="+routerModel.getPaySence()+",orderType:"+routerModel.getOrderType());
throw new TradeException(ResultEnum.e2001.name(), ResultEnum.e2001.getTitle());
}else if(channels.size()==1){//找到一个通道
PayChannel channel = channels.get(0);
}else{//找到多个通道
//获取路由策略
TpRouteScalePolicy tpRouteScalePolicy = ServiceCacheTool.getCacheValue(CacheConstants.CACHE_RoutePolicyCACHE, CacheConstants.CACHE_RoutePolicyCACHE, TpRouteScalePolicy.class);
if(tpRouteScalePolicy==null){
logger.info("获取不到路由策略");
throw new TradeException(ResultEnum.e3006.name(),ResultEnum.e3006.getDesc());
}
logger.info("当前路由配置策略为:"+tpRouteScalePolicy.getRoutePolicyName());
if(RouterConstant.RATE_ROUTE.equals(tpRouteScalePolicy.getRoutePolicyCode())){//按费率分配
//取最低费率的通道
Optional minFeeChannel = channels.stream().min((e1,e2)->Integer.compare(e1.getRate(),e2.getRate()));
channel = minFeeChannel.get();
}else if(RouterConstant.STABILITY_ROUTE.equals(tpRouteScalePolicy.getRoutePolicyCode())){
//取最稳定的通道
Optional minFeeChannel = channels.stream().max((e1,e2)->Integer.compare(e1.getStability(),e2.getStability()));
channel = minFeeChannel.get();
}else{
logger.info("找不到策略模式,请技术人员扩展后使用");
throw new TradeException(ResultEnum.e3007.name(),ResultEnum.e3007.getDesc());
}
}
logger.info("路由找到支付通道:"+channel.getChannelCode());
PaymentInterfaceResponse paymentInterfaceResponse = new PaymentInterfaceResponse();
paymentInterfaceResponse.setChannelCode(channel.getChannelCode());
paymentInterfaceResponse.setPayWayCode(routerModel.getPayWayCode());
//3、使用通道JavaBean ID实例化通道
IPaymentService paymentService = (IPaymentService) SpringContextHolder.getBean(channel.getBeanId());
paymentInterfaceResponse.setPaymentService(paymentService);
return paymentInterfaceResponse;
}
@Override
public ChannelPCPayResponse pay(ChannelPCPayRequest payRequest) {
// TODO Auto-generated method stub
//初始化返回参数
ChannelPCPayResponse channelPCPayResponse = new ChannelPCPayResponse();
BeanUtils.copyProperties(payRequest, channelPCPayResponse);
//1、获取支付宝接口地址
PaySysParam param = CacheTool.getCacheValue(CacheConstants.SYS_PARAM_CACHE, CacheConstants.ALIPAY_URL, PaySysParam.class);
//2、根据支付通道从缓存中获取对应该通道的技术参数
PayChannelConf conf = CacheTool.getCacheValue(CacheConstants.CHANNEL_CACHE, "channel-"+payRequest.getChannelNo(), PayChannelConf.class);
//3、构建支付宝请求参数
AlipayClient alipayClient = new DefaultAlipayClient(param.getValue(), conf.getPayAppid(), conf.getPrivateKeyStr(), FORMAT, CHARSET, conf.getPublicKeyStr(), SIGN_TYPE);
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(payRequest.getReturnUrl());
alipayRequest.setNotifyUrl(payRequest.getNotifyUrl());
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setBody(payRequest.getBody());
model.setOutTradeNo(payRequest.getPaymentCode());
model.setSubject(payRequest.getSubject());
BigDecimal amount = new BigDecimal(payRequest.getTotalFee());
amount = amount.divide(new BigDecimal(100)).setScale(2,BigDecimal.ROUND_HALF_UP);
model.setTotalAmount(amount.toPlainString());
model.setProductCode("FAST_INSTANT_TRADE_PAY");
if(payRequest.getOrderPeriod() != null){
model.setTimeoutExpress(String.format("%sm", payRequest.getOrderPeriod()));
}
alipayRequest.setBizModel(model);
//4、发送请求
String html = "";
try {
logger.info("支付宝封装支付请求:"+JSONObject.toJSONString(alipayRequest));
html = alipayClient.pageExecute(alipayRequest).getBody();
logger.info("支付宝返回封装支付请求HTML:"+html);
} catch (AlipayApiException e) {
// TODO Auto-generated catch block
logger.error("组装支付宝页面时异常",e);
throw new TradeException(ResultEnum.e1003.name(), ResultEnum.e1003.getDesc());
}
//5、返回请求结果
channelPCPayResponse.setReturnCode(ResultEnum.e0000.name());
channelPCPayResponse.setReturnDesc(ResultEnum.e0000.getDesc());
channelPCPayResponse.setHtml(html);
channelPCPayResponse.setResponseResultType(ResponseResultTypeEnum.HTML.getCode());
return channelPCPayResponse;
}