支付路由适配服务技术实现

说明:本文思路纯粹个人的想法,希望过路大神提点


名词解释



接入模式
1、服务商接入模式:指由支付公司审核且签约合作的,有一定技术能力的第三方开发者。服务商可为所拓展的特约商户完成支付申请、技术接入、活动营销等全生态服务。
2、普通商户接入模式:指电商公司自行与支付公司签约合作的,自身具有技术能力完成支付申请、技术接入、活动营销等全生态服务。


支付方式:第三方账户支付或通过第三方银行卡快捷支付。


支付供应商:微信、支付宝、翼支付、威富通、富有 等等,一个支付供应商提供一种或多种支付方式


支付商户号:电商或平台在支付供应商唯一标识。




一、基础配置


1、建立支付场景:PC网站支付、WAP网站支付、扫码支付、被扫支付、公众号支付、小程序支付、APP支付


2、建立支付方式:微信、支付宝、银联、翼支付、通联等等


3、确定支付方式支持的支付场景。例:支付宝支持[PC网站支付、wap网站支付、扫码支付、被扫支付、APP支付]
银联支持[PC网站支付、wap网站支付、APP支付]


4、创建支付通道:
决定通道的因素:1、支付方式 2、接入模式(服务商模式、普通商户模式) 2、支付商户号 3、费率 4、支持的订单类型[普通订单或国际订单]
通道自身属性:1、网络稳定性 2、通道实现类(JavaBean名称)


5、确定电商商户与支付通道的关系:1、电商商户编号 2、支付通道编号


6、确定相同支付方式下的路由策略:1、按费率  2、按网络稳定性 3、[自定义扩展]


7、支付通道接入支付技术配置:1、接入模式 2、支付商户号 3、技术参数配置


二、智能路由适配

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<PayChannel> 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<PayChannel> minFeeChannel = channels.stream().min((e1,e2)->Integer.compare(e1.getRate(),e2.getRate()));
        channel = minFeeChannel.get();
			}else if(RouterConstant.STABILITY_ROUTE.equals(tpRouteScalePolicy.getRoutePolicyCode())){
				//取最稳定的通道
				Optional<PayChannel> 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;
}

5、使用通道进行支付。以支付宝pc支付为例
@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;
}


猜你喜欢

转载自blog.csdn.net/xiasihua88/article/details/79716349