多应用多平台支付模块设计-基础模块开篇
近来,欲将三方支付平台对接入笔者框架内,简化,后期业务功能的开发。
为满足此功能的可扩展性,欲定义“订单业务接口”、“支付方式接口”规则。
当,用户下单时,根据传入的“业务类型”获取具体的业务实现,根据“支付方式”获取具体的下单数据。
如此,即可在具体的业务代码中,实现对应的业务功能。
开发之始,即为设计,此篇仅为基础设计篇,后期将会逐渐完善各三方平台支付实现类。
啰嗦至此,此下,正式开文。
思路设计图如下
此下,设计具体的表结构,笔者基于目前想法,设计两张表“订单表”、“订单过程表”。
数据库表结构如下
表关系图如下
既,表设计完成,此下将具体实现业务功能。
开篇之始,笔者先定义对应的“订单相关字典”。
其中“订单业务类型”未预留字典类型,具体业务功能引入此库实现时,自主定义即可。
另,支付方式目前框架仅实现“微信V2JSApi”方式,后期陆续实现,并定义相关字典,此处暂不定义全部字典。
字典配置类如下
package com.threeox.biz.order.config;import com.threeox.drivenlibrary.engine.annotation.config.DictionaryConfig;/*** 订单字典常量类** @author 赵屈犇* @version 1.0* @date 创建时间: 2022/4/18 22:24*/
public class OrderDictConstants {/*** 订单业务类型*/@DictionaryConfig(dictionaryCode = OrderBizType.DICTIONARY_CODE, dictionaryName = "订单业务类型", remark = "订单业务类型", version = 2)public static class OrderBizType {public static final String DICTIONARY_CODE = "2008";}/*** 订单状态*/@DictionaryConfig(dictionaryCode = OrderStatus.DICTIONARY_CODE, dictionaryName = "订单状态", remark = "订单状态", version = 2)public static class OrderStatus {public static final String DICTIONARY_CODE = "2009";/*** 已下单*/@DictionaryConfig(dictionaryName = "已下单")public static final String HAVE_ORDER = "200901";/*** 支付成功*/@DictionaryConfig(dictionaryName = "支付成功")public static final String PAYMENT_SUCCESS = "200902";/*** 支付失败*/@DictionaryConfig(dictionaryName = "支付失败")public static final String PAYMENT_FAILED = "200903";/*** 支付金额有误*/@DictionaryConfig(dictionaryName = "支付金额有误")public static final String PAYMENT_AMOUNT_WRONG = "200904";}/*** 支付方式*/@DictionaryConfig(dictionaryCode = PayWay.DICTIONARY_CODE, dictionaryName = "支付方式", remark = "支付方式", version = 2)public static class PayWay {public static final String DICTIONARY_CODE = "2010";/*** 微信JSAPI支付*/@DictionaryConfig(dictionaryName = "微信JSAPI_V2支付")public static final String WX_JS_API_V2 = "201001";/*** 微信APP支付*/@DictionaryConfig(dictionaryName = "微信APP_V2支付")public static final String WX_APP_API_V2 = "201002";}}
为实现框架高扩展性,笔者欲定义两套接口规范,供具体业务、支付方式实现。
接口规范类
订单业务扩展类
此接口目前暂声明两套接口,“获取业务快照数据”、“处理支付回调”函数,用于具体业务实现。
后期,如需具体实现再添加。
package com.threeox.biz.order.factory.inter;import com.threeox.biz.order.entity.OrderInfo;
import com.threeox.biz.order.entity.inter.IOrderBizInfo;
import com.threeox.biz.order.entity.inter.IPayNotifyInfo;
import com.threeox.dblibrary.executor.inter.ISqlExecutor;/*** 订单接口扩展类** @author 赵屈犇* @version 1.0* @date 创建时间: 2022/4/13 23:43*/
public interface IOrderExtend<T extends IOrderBizInfo> {/*** 获取业务快照数据** @param executor* @param orderInfo* @return a* @throws Exception* @author 赵屈犇* @date 创建时间: 2022/4/18 21:30* @version 1.0*/T getBizSnapshot(ISqlExecutor executor, OrderInfo orderInfo) throws Exception;/*** 处理支付回调** @param executor* @param orderInfo* @param notifyInfo* @param currentStatus* @return a* @throws Exception* @author 赵屈犇* @date 创建时间: 2022/5/28 23:52* @version 1.0*/void handlePayNotify(ISqlExecutor executor, OrderInfo orderInfo, IPayNotifyInfo notifyInfo, String currentStatus) throws Exception;}
支付方式接口规范
此接口,目前仅需获取各支付平台获取统一下单数据函数。
package com.threeox.biz.order.factory.inter;import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.order.entity.OrderInfo;/*** 支付接口定义** @author 赵屈犇* @version 1.0* @date 创建时间: 2022/4/12 21:59*/
public interface IPaymentFactory {/*** 统一下单** @param orderInfo* 订单对象* @author 赵屈犇* @return* @date 2022/4/23 17:45*/JSONObject placeOrder(OrderInfo orderInfo) throws Exception;}
至此,接口规范已定义。
此下,笔者欲实现支付方式基础实现类,供具体业务逻辑继承扩展。
支付方式基础实现类
此基础类,目前仅需根据具体的应用渠道获取渠道信息,调用对应子类的统一下单实现方法。
package com.threeox.biz.order.factory.impl.base;import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.order.entity.OrderInfo;
import com.threeox.biz.order.factory.inter.IPaymentFactory;
import com.threeox.drivenlibrary.engine.config.DrivenEngineConfig;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.enums.ResponseResult;
import com.threeox.drivenlibrary.exception.ResponseException;/*** 基础支付工厂** @author 赵屈犇* @version 1.0* @date 创建时间: 2022/4/23 17:37*/
public abstract class BasePaymentFactory implements IPaymentFactory {@Overridepublic JSONObject placeOrder(OrderInfo orderInfo) throws Exception {OpenPlatformConfigMessage openPlatform = DrivenEngineConfig.getInstance().getOpenPlatform(orderInfo.getAppChannelCode());if (openPlatform == null) {throw ResponseException.newInstance(ResponseResult.UN_CONFIG_OPEN_INFO);}return placeOrder(orderInfo, openPlatform);}/*** 统一下单实现方法** @param orderInfo* @param openPlatform* @author 赵屈犇* @return* @date 2022/4/23 17:50*/protected abstract JSONObject placeOrder(OrderInfo orderInfo, OpenPlatformConfigMessage openPlatform) throws Exception ;
}
以上至此,已实现具体规范定义。此下将首先实现“下单接口”定义。
统一下单接口实现
此接口,笔者在具体实现之前,根据业务类型,获取了指定的业务实现类,并给订单表中存储了“业务快照数据”,方便后期运维查看。
并在订单信息入库成功后,根据支付方式获取具体的支付实现类,获取下单数据,提供给“调用方”进行支付请求。
package com.threeox.biz.order.api;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.order.config.OrderDictConstants;
import com.threeox.biz.order.config.OrderRequestConfig;
import com.threeox.biz.order.entity.OrderInfo;
import com.threeox.biz.order.entity.inter.IOrderBizInfo;
import com.threeox.biz.order.factory.inter.IOrderExtend;
import com.threeox.biz.order.factory.inter.IPaymentFactory;
import com.threeox.drivenlibrary.engine.ExtendFactory;
import com.threeox.drivenlibrary.engine.annotation.api.Api;
import com.threeox.drivenlibrary.engine.annotation.api.ApiVerifyConfig;
import com.threeox.drivenlibrary.engine.config.entity.request.base.RequestMessage;
import com.threeox.drivenlibrary.engine.entity.params.RequestParam;
import com.threeox.drivenlibrary.engine.function.impl.AbstractApiExtend;
import com.threeox.drivenlibrary.engine.request.build.RequestBuilder;
import com.threeox.drivenlibrary.engine.util.RequestUtils;
import com.threeox.utillibrary.date.TimeUtils;
import com.threeox.utillibrary.java.IDGenerate;import java.util.Date;/*** 下单api扩展** @author 赵屈犇* @version 1.0* @date 创建时间: 2022/4/13 22:21*/
@Api(apiUrl = "placeOrder", apiName = "统一下单", verifyConfigs = {@ApiVerifyConfig(paramCode = "orderName", emptyHint = "请传入订单名称"),@ApiVerifyConfig(paramCode = "payWay", emptyHint = "请传入支付方式"),@ApiVerifyConfig(paramCode = "bizType", emptyHint = "请传入业务类型"),@ApiVerifyConfig(paramCode = "bizKey", emptyHint = "请传入业务主键")
}, moduleUrl = "pay", requestCodes = {OrderRequestConfig.SAVE_ORDER_INFO,OrderRequestConfig.SAVE_ORDER_PROCESS_INFO
})
public class PlaceOrderExtend extends AbstractApiExtend<OrderInfo> {@Overridepublic boolean onBeforeApiExecute() throws Exception {OrderInfo requestParams = getRequestParams();// 获取业务类型String bizType = requestParams.getBizType();// 根据业务类型IOrderExtend orderExtend = ExtendFactory.getInstance().getOrderExtend(bizType);if (orderExtend != null) {IOrderBizInfo bizSnapshot = orderExtend.getBizSnapshot(getSqlExecutor(), requestParams);if (bizSnapshot != null) {putRequestParam("bizSnapshot", JSON.toJSONString(bizSnapshot));requestParams.setBizSnapshot(getParamValue("bizSnapshot"));}putRequestParam("payMoney", bizSnapshot.getPayMoney());requestParams.setPayMoney(bizSnapshot.getPayMoney());} else {errorResult("未找到对应支付业务!");return false;}String orderNum = IDGenerate.getOrderNum();putRequestParam("orderNum", orderNum);requestParams.setOrderNum(orderNum);Date nowTimeDate = TimeUtils.getNowTimeDate();putRequestParam("operateTime", nowTimeDate);requestParams.setOperateTime(nowTimeDate);String ipAddress = RequestUtils.getIPAddress(servletRequest());putRequestParam("ipAddress", ipAddress);requestParams.setIpAddress(ipAddress);putRequestParam("accountId", getParamValue("accountId"));requestParams.setAccountId(getParamValue("accountId"));putRequestParam("currentStatus", OrderDictConstants.OrderStatus.HAVE_ORDER);requestParams.setCurrentStatus(OrderDictConstants.OrderStatus.HAVE_ORDER);return super.onBeforeApiExecute();}@Overridepublic void handlerRequestBuilder(RequestMessage requestInfo, RequestBuilder requestBuilder, RequestParam requestParam) {super.handlerRequestBuilder(requestInfo, requestBuilder, requestParam);if (OrderRequestConfig.SAVE_ORDER_PROCESS_INFO.equals(requestInfo.getRequestCode())) {requestParam.putRequestParam("ipAddress", getParamValue("ipAddress"));requestParam.putRequestParam("orderTime", getParamValue("operateTime"));requestParam.putRequestParam("orderStatus", getParamValue("currentStatus"));requestParam.putRequestParam("orderId", getResultValue(OrderRequestConfig.SAVE_ORDER_INFO));}}@Overridepublic boolean onAfterApiExecute(JSONObject resultSet) throws Exception {// 根据支付方式获取订单信息IPaymentFactory paymentExtend = ExtendFactory.getInstance().getPaymentExtend(getRequestParams().getPayWay());if (paymentExtend != null) {successResult(paymentExtend.placeOrder(getRequestParams()));}return super.onAfterApiExecute(resultSet);}}
至此,下单接口已实现,当用户支付成功后,会主动调起对应的支付回调接口。
因此,笔者欲定义一套基础支付回调通知处理类,在具体支付回调接口,继承并实现即可。
支付回调接口对象类
实现基础回调实现类之前,笔者考虑片刻,顿觉定义支付回调接口对象,用此作为具体回调接口的接口参数定义类。
此接口,目前定义两个需实现的函数,为“获取订单号”、“支付金额”用于回调接口时使用。
package com.threeox.biz.order.entity.inter;import java.math.BigDecimal;/*** 支付通知对象** @author 赵屈犇* @version 1.0* @date 创建时间: 2022/5/27 22:44*/
public interface IPayNotifyInfo {/*** 获取订单号** @return*/String getOrderNum();/*** 获取支付金额** @return*/BigDecimal getPayMoney();}
基础支付回调实现类
此类,先根据订单编号查询具体的订单信息。
当查询到具体订单信息时,调用子类实现的“是否支付成功”函数。
若,支付成功后,在此之下,校验支付金额是否一致。
若,支付金额一致时,更新订单信息,并存储订单过程记录。
在此之后,即是通知具体业务实现类回调。
package com.threeox.biz.order.api.notify.base;import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.order.config.OrderDictConstants;
import com.threeox.biz.order.config.OrderRequestConfig;
import com.threeox.biz.order.entity.OrderInfo;
import com.threeox.biz.order.entity.inter.IPayNotifyInfo;
import com.threeox.biz.order.factory.inter.IOrderExtend;
import com.threeox.dblibrary.constants.GeneratedKeyInfo;
import com.threeox.drivenlibrary.engine.ExtendFactory;
import com.threeox.drivenlibrary.engine.config.DrivenEngineConfig;
import com.threeox.drivenlibrary.engine.constants.config.DrivenModelDBConstants;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.engine.function.impl.AbstractApiExtend;
import com.threeox.drivenlibrary.engine.request.build.SqlBuilder;
import com.threeox.drivenlibrary.engine.request.execute.ExecuteRequestFactory;
import com.threeox.drivenlibrary.engine.request.inter.OnExecuteRequest;
import com.threeox.drivenlibrary.engine.util.RequestUtils;
import com.threeox.drivenlibrary.enums.dictionary.QueryType;
import com.threeox.utillibrary.date.TimeUtils;/*** 基础支付回调扩展类** @author 赵屈犇* @version 1.0* @date 创建时间: 2022/5/24 22:18*/
public abstract class BasePayNotifyExtend<T extends IPayNotifyInfo> extends AbstractApiExtend<T> {@Overridepublic boolean onBeforeApiExecute() throws Exception {// 当前状态String currentStatus = null;IOrderExtend orderExtend = null;ExecuteRequestFactory requestFactory = ExecuteRequestFactory.builder().setSqlExecutor(getSqlExecutor());// 查询对应的订单信息OrderInfo orderInfo = requestFactory.configCode(DrivenModelDBConstants.DRIVEN_MANAGE_MODEL_DB_CODE).requestCode(OrderRequestConfig.QUERY_ORDER_INFO).execute((OnExecuteRequest<SqlBuilder>) builder -> builder.and("order_num", QueryType.EQUAL, getRequestParams().getOrderNum()));if (orderInfo != null) {JSONObject updateData = new JSONObject();OpenPlatformConfigMessage openPlatform = DrivenEngineConfig.getInstance().getOpenPlatform(orderInfo.getAppChannelCode());if (openPlatform != null) {boolean isPaySuccess = isPaySuccess(orderInfo, openPlatform);if (isPaySuccess) {// 校验支付金额是否一致if (orderInfo.getPayMoney().compareTo(getRequestParams().getPayMoney()) == 0) {currentStatus = OrderDictConstants.OrderStatus.PAYMENT_SUCCESS;} else {currentStatus = OrderDictConstants.OrderStatus.PAYMENT_AMOUNT_WRONG;errorResult("支付金额不一致,请检查!");}} else {currentStatus = OrderDictConstants.OrderStatus.PAYMENT_FAILED;errorResult("验证失败,支付回调不成功!");}updateData.put("currentStatus", currentStatus);updateData.put("operateTime", TimeUtils.getNowTimeDate());updateData.put("ipAddress", RequestUtils.getIPAddress(servletRequest()));// 更新订单信息GeneratedKeyInfo keyInfo = requestFactory.requestCode(OrderRequestConfig.UPDATE_ORDER_INFO).requestParam(updateData).execute((OnExecuteRequest<SqlBuilder>) builder ->builder.and("order_id", QueryType.EQUAL, orderInfo.getOrderId()));if (keyInfo.toInteger() > 0) {JSONObject processData = new JSONObject();processData.put("processSnapshot", getParams().toJSONString());processData.put("orderId", orderInfo.getOrderId());processData.put("orderTime", updateData.get("operateTime"));processData.put("orderStatus", updateData.get("currentStatus"));processData.put("ipAddress", updateData.getString("ipAddress"));// 保存订单过程requestFactory.requestCode(OrderRequestConfig.SAVE_ORDER_PROCESS_INFO).requestParam(processData).execute();}} else {errorResult("未找到配置的开放信息!");}// 更新订单信息orderExtend = ExtendFactory.getInstance().getOrderExtend(orderInfo.getBizType());} else {errorResult("未查询到对应的订单信息!");}if (orderExtend != null) {orderExtend.handlePayNotify(getSqlExecutor(), orderInfo, getRequestParams(), currentStatus);}return super.onBeforeApiExecute();}/*** 是否支付成功** @param orderInfo* @param openPlatform* @return a* @author 赵屈犇* date 创建时间: 2022/5/27 21:03* @version 1.0*/protected abstract boolean isPaySuccess(OrderInfo orderInfo, OpenPlatformConfigMessage openPlatform) throws Exception;}
至此,业已实现支付基础模块设计,下篇具体实现微信V2支付逻辑。
文至于此,诸君加油、共勉。
多应用多平台支付模块设计-基础模块开篇相关推荐
- 模块设计之“模块”与“模块化”
模块设计之"模块"与"模块化" 模块泛指软件系统的功能部件.在软件的体系结构设计完成之际,我们就已经确定了所有模块的功能,并且把模块安放在体系结构的恰当位置上. ...
- 计算机基础模块,计算机基础模块练习 (1)
1 模块二模块二 一 选择 1 按 C C 键能退出DOS 回到Windows A QUIT B F4 C C EXITEXIT D Alt F4 2 单击窗口的 B B 可以把窗口拖放到桌面的任何地 ...
- Verilog基础模块总结
verilog基础模块 verilog基础模块包括数据类型,运算符,组合逻辑和时序逻辑四个部分.数据类型包括常量和变量,在常量中有整数,X和Z以及参数.X代表不定制,Z代表高阻值.下划线不具有任何意义 ...
- Java开源生鲜电商平台-支付模块的设计与架构(源码可下载
Java开源生鲜电商平台-支付模块的设计与架构(源码可下载) Java开源生鲜电商平台-支付模块的设计与架构(源码可下载) 开源生鲜电商平台支付目前支持支付宝与微信.针对的是APP端(android ...
- 【餐厅点餐平台|三】模块设计
餐厅点餐平台导航 [餐厅点餐平台|一]项目描述+需求分析 https://blog.csdn.net/weixin_46291251/article/details/126414430 [餐厅点餐平台 ...
- Java生鲜电商平台-团购模块设计与架构
Java生鲜电商平台-团购模块设计与架构 说明:任何一个电商系统中,对于促销这块是必不可少的,毕竟这块是最吸引用户的,用户也是最爱的模块之一,理由很简单,便宜. 我的经验是无论是大的餐饮点还是小的餐饮 ...
- 电商平台-团购模块设计与架构
说明:任何一个电商系统中,对于促销这块是必不可少的,毕竟这块是最吸引用户的,用户也是最爱的模块之一,理由很简单,便宜. 我的经验是无论是大的餐饮点还是小的餐饮店,优惠与折扣永远是说福他们进入平台的最好 ...
- 基于SET协议的电子支付系统模块设计
基于Internet的电子商务以其具有传统商务模式不可比拟的优点而在当今世界蓬勃发展.电子商务发展的关键问题就是交易的安全性,也就是网络上的信息安全,即网上电子支付的安全实现.SET安全电子交易协议是 ...
- java 团购开发_Java生鲜电商平台-团购模块设计与架构
Java生鲜电商平台-团购模块设计与架构 说明:任何一个电商系统中,对于促销这块是必不可少的,毕竟这块是最吸引用户的,用户也是最爱的模块之一,理由很简单,便宜. 我的经验是无论是大的餐饮点还是小的餐饮 ...
最新文章
- R使用neuralnet包构建神经网络回归模型并与线性回归模型对比实战
- 文思海辉口碑很差_文思海辉·金融打造全自动、100%话务覆盖的智能质检系统
- 全国数据中心分布图上线 轻轻松松找机房
- 在mysql-workbench中运行function
- mysql_query 资源标识符_借助PHP的mysql_query()函数来创建MySQL数据库的教程
- centos 新装mysql 进入,centos5安装 mysql 提示需要用户及密码进入?Duplicate entry 'localhost-' for key 1...
- jsonp react 获取返回值_必须要会的 50 个React 面试题(下)
- Vue报错:Elements in iteration expect to have ‘v-bind:key‘ directives的解决办法
- 在python中如何判断数组中的数据为空值_缓存穿透问题,开发中真实解决方案
- [AHOI2006]Editor文本编辑器Splay Pascal
- 考勤系统——代码分析datagrid
- html获取元素的rgb值,使用javascript提取支持的HTML或X11颜色名称及其RGB值的列表
- Flink在流处理上的Source和sink操作、Flink--sink到kafka
- Assuming drive cache: write through 因为硬盘内存不足VM虚拟机开不了机的问题
- 灵猫二维码 - 二维码中间加图片的方法
- 智能电视以及机顶盒屏幕截取的方法
- 每周论文精读05-A2J:AnchortoJointRegressionNetwork for 3D ArticulatedPoseEstimation from a SingleDepthImage
- 十一、MySQL触发器
- 微型计算机的体积虽小 但是性价比比较高,[问答题,简答题] 简述公共管理与企业管理的区别。...
- 阿里云国际站:阿里云linux扩充磁盘大小常见问题