大家好!今天让小编来大家介绍下关于聚合支付接口设计的问题,以下是酷知号的小编对此问题的归纳整理,让我们一起来看看吧。
前段时间对接了微信支付,于是乎,从网上找了一下别人写过的一顿copy后,修修改改终于实现完成了。
本以为万事大吉, 但是项目经理review代码时候,发现我写的支付功能和系统业务功能高度耦合, 搅和在一起结果就扣了我一部分绩效(mmp…) 。
为了避免以后扣绩效,所以决定研究一下,怎么设计支付接口比较合理。末尾附上 git传送门代码
1. if 编码方式
支付渠道暂时虽然只有微信,但是保不齐后面再加支付宝,银联啥的。到时候,代码就会像这样
if (paytype.equals ("微信")) { //dosomething }else if (paytype.equals ("支付宝")) { //dosomething }else if(paytype.equals ("银联")) { //dosomething }
每多一个支付渠道,改动的地方包括:支付接口、支付配置、退款、统计业务。
2.聚合支付
万能的百度上搜索了一下对接多个系统的方案(参考末尾的链接),其中聚合支付的方案比较合理。虽然可能用不到其中一部分的功能,比如结算功能。
1) 什么是聚合支付呢?
说白了就是一个项目接入了多个支付渠道,而且能够使用任意一个渠道进行支付、退款等操作,而且任何渠道之间没有任何关系,彼此不会互相干扰。
2) 简单梳理一下聚合支付的业务
•需要对接多个支付渠道
• 所有的支付能够兼容任意渠道
• 所有的退款能够兼容任何渠道
• 任何渠道都能需要独立进行配置
• 任何渠道都有统计功能
• 渠道之间能够无缝进行切换(比如某个渠道奔溃了,能够切换到其他渠道)
如果想满足上面的功能,又不影响原有的业务的情况下,就需要将原有的支付模块独立抽离开来,单独作为一个服务,也就是聚合支付,凡是项目里面的任何支付、退款、查询、统计等都要通过聚合支付来处理。
3) 如何设计
设计模式是面试时候经常问的,那么,大胆地使用合理的设计模式对功能进行设计吧!
工厂模式: 每个支付渠道可以看成一个工厂
适配器模式: 不同的支付渠道使用的api,参数或者返回结果都可能不一样
策略模式: 根据支付类型创建对应的支付通道
3.工厂模式
1) 创建一个支付的统一接口 , 这里列举几个接口
/** * 支付接口, 所有支付类的接口,系统所有支付功能类都需要实现它; */ public interface pay { /** * 下单 */ doordervo doorder(doorderso so); /** * 支付或者退款通知 */ paynotifyvo paynotify(paynotifyso so); /** * 查询退款 */ queryrefundvo queryrefund(queryrefundso so); }
2) ag真人官方网址的支付方式枚举类
/** * 支付类型枚举类 ** 每增加一种支付渠道,需要同时在工厂类{@link payfactory}里面配置 *
*/ public enum paywayenum { /** * wx_app */ wx_app("wx_app"), /** * wx_native */ wx_native("wx_native"), /** * ali_app */ ali_app("ali_app"), /** * ali_web */ ali_web("ali_web"); paywayenum(string key) { } }
3) 实现类
支付渠道有微信,支付宝,银联或者第三方支付等, 而微信又有native支付,native支付,手机支付等方式....
使用工厂方式可以根据ag真人官方网址的支付方式枚举出来具体实现, 结构如下
图一 支付接口
4) 工厂获取实例对象 (又要用if...或者switch....,不过后面再优化....)
@service public class payfactory { //根据类型获取结果处理的实现类 public pay getpayimpl(paywayenum paywayenum) { assert.notnull(paywayenum, "付款渠道不能为空"); if (paywayenum.equals(paywayenum.wx_app)) { return new wxpayappimpl(); } else if (paywayenum.equals(paywayenum.wx_native)) { return new wxpaynativeimpl(); } else if (paywayenum.equals(paywayenum.ali_app)) { return new alipayappimpl(); } else if (paywayenum.equals(paywayenum.ali_web)) { return new alipaywebimpl(); } else { return null; } } }
4.适配器模式
1) 多个实现pay接口问题
图一里面,通过观察发现:
①4个实现类都统一实现了pay的接口,如果再在pay接口中增加一个接口void doaction(),那么4个接口都得重新加上
②微信支付的api有些是通用的,比如统一下单,签名和验签,没必要在每个实现类里面都加上
2) 接口适配器模式 (缺省适配器模式)
适用场景: 当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
微信支付抽象类:
/** * 微信支付底层抽象类 *为对接第三方支付接口的支付抽象类,需要实现第三方支付接口的所有api交互,为支付功能类提供功能方法
*每一种支付方法,都可以继承该抽象类,并拥有自己的独立的支付流程,
*/ public abstract class wxpay implements pay { //=============================下面是支付的业务功能接口================== @override public wxdoordervo doorder(doorderso so) { //子类实现 return null; } @override public paynotifyvo paynotify(paynotifyso so) { //子类实现 return null; } @override public queryrefundvo queryrefund(queryrefundso so) { //子类实现 return null; } //=============================下面是微信支付的基础api和相关方法================== /** * 统一下单接口 * * @param so */ public wxunifiedordervo unifiedorder(wxunifiedorderso so) { system.out.println("wxpay->unifiedorder :" so.tostring()); /** * 这里调用微信支付api 发送下单请求,返回二维码链接等信息 , */ // 创建签名 createsign(so.tostring()); //发送请求 string resultxml = paymenutils.dopost("www.weixinpay/unifiedorder", so.tostring()); //解析结果成实体,并返回 wxunifiedordervo wxunifiedordervo = paymenutils.parsewxunifiedorderresult(resultxml); return wxunifiedordervo; } /** * 生成签名 */ public void createsign(string params) { system.out.println("wxpay->createsign :" params); } /** * 验证签名 */ public void checksign(string params) { system.out.println("wxpay->checksign :" params); } }
微信nativeag真人官方网址的支付方式实现类 (假如我只想使用native下单,其他功能不需要,只需要重写一下doorder方法,其他的不需要重写)
@service public class wxpaynativeimpl extends wxpay { @override public wxdoordervo doorder(doorderso so) { system.out.println("------微信-app方式-------"); //调用统一下单逻辑 wxunifiedorderso unifiedorderso = new wxunifiedorderso(); wxunifiedordervo unifiedordervo = super.unifiedorder(unifiedorderso); wxnativedoordervo wxnativedoordervo = new wxnativedoordervo(); wxnativedoordervo.setnativeflag("------nativeflag------"); wxnativedoordervo.setwxunifiedordervo(unifiedordervo); return wxnativedoordervo; } }
接口设计如下图
5.策略模式
1) 策略模式的定义
策略模式是对算法的包装,把使用算法的责任和算法本身分隔开,委派给不同的对象管理。策略模式通常把一系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。
2) payfactory 工厂优化
前面工厂类,是根据if判断各种支付类型来new xxxpayimpl() 实例创建对象,
根据类型来实例化不同的对象,可以看做是多种实现策略,可以使用策略模式来优化一下;
3) 建立ag真人官方网址的支付方式->实现类的对应关系
/** * 具体ag真人官方网址的支付方式的配置 * key 表示ag真人官方网址的支付方式, * value 表示支付具体实现类,** 注意这里类名小写 */ public static final mappay_map = new hashmap<>(8); static { pay_map.put(paywayenum.wx_app, "wxpayappimpl"); pay_map.put(paywayenum.wx_native, "wxpaynativeimpl"); pay_map.put(paywayenum.ali_app, "alipayappimpl"); pay_map.put(paywayenum.ali_web, "alipaywebimpl"); }
4) spring实例化bean(而不是手动new xxx)
spring工具类
/** * 直接通过spring 上下文获取springbean,用于多线程环境 */ @component public class springcontextutil implements applicationcontextaware { // spring应用上下文环境 private static applicationcontext applicationcontext; /** * 实现applicationcontextaware接口的回调方法。设置上下文环境 */ @override public void setapplicationcontext(applicationcontext applicationcontext) { springcontextutil.applicationcontext = applicationcontext; } public static applicationcontext getapplicationcontext() { return applicationcontext; } /** * 获取对象 * * @param name * @return object * @throws beansexception */ public static object getbean(string name) throws beansexception { return applicationcontext.getbean(name); } public static void main(string[] args) { //具体使用: // alipay alipayimpl =(alipay) springcontextutil.getbean("alipayimpl"); // alipayimpl.pay(); } }
根据类型获取支付渠道的实现类
//根据类型获取结果处理的实现类 public pay getpay(paywayenum paywayenum) { assert.notnull(paywayenum, "付款渠道不能为空"); return (pay) springcontextutil.getbean(pay_after_map.get(paywayenum)); }
6.controller调用
1) 请求接口
@autowired
private payfactory payfactory;
@getmapping("/hellopay/{typeenum}") public string hello(@pathvariable("typeenum") string typeenumstr) { paywayenum typeenum = paywayenum.valueof(typeenumstr); //由工厂获取具体的pay实现类 pay pay = payfactory.getpay(typeenum); system.out.println("pay:" pay); doorderso doorderso = new doorderso(); doorderso.setorderno("下单的单号orderno_00001"); doorderso.settradeno("下单的外部单号tradeno_111111"); //获取处理结果,这里实际转换成了具体的结果实现类 doordervo doordervo = pay.doorder(doorderso); // 这里其实是具体的vo system.out.println("调用doorder返回结果:doordervo :" doordervo); return null; }
说明: 这里的xxxso 表示参数, xxxvo表示返回值, (可以自行定义), so和so之间存在父子关系,vo和vo之间也存在父子关系,
这样设计主要是: 方便支付的api处理逻辑有一个统一的返回,然后再交给系统进行db等业务处理~
2) 测试请求
http://localhost:8088/demo/testpay/hellopay/wx_native
http://localhost:8088/demo/testpay/hellopay/zfb_web
请求会看到不同的效果,(zfb_web的实现类需要按照上面那样写一点逻辑就可以看到效果)
7.支付结果后处理
doordervo 是调用支付的api后,统一处理的实体,我们需要根据不同的类型,转发到不同的后处理service的具体业务实现类中,
主要是在系统中记录一些db信息和订单等信息,仿照上面的接口设计,
//工厂获取支付后处理的实现类 payafter payafter = payfactory.getpayafter(typeenum); system.out.println("payafter:" payafter); payafter.doorderafter(doordervo);
payafter是后处理统一接口,doorderafter是doorder支付接口的后处理逻辑;
8.调用效果
请求:
http://localhost:8088/demo/testpay/hellopay/wx_native
http://localhost:8088/demo/testpay/hellopay/ali_web
结果:
git传送门代码: https://github.com/colozhu/paydemo
参考:
https://blog.csdn.net/think2017/article/details/79820786?utm_medium=distribute.pc_relevant.none-task-blog-blogcommendfrommachinelearnpai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-blogcommendfrommachinelearnpai2-1.channel_param ,
https://www.cnblogs.com/lyc94620/p/13055116.html ,
以上就是小编对于聚合支付接口设计问题和相关问题的解答了,聚合支付接口设计的问题希望对你有用!