近来,欲将三方付出途径对接入笔者框架内,简化,后期事务功用的开发。

为满意此功用的可扩展性,欲界说“订单事务接口”、“付出办法接口”规则。

当,用户下单时,依据传入的“事务类型”获取详细的事务完结,依据“付出办法”获取详细的下单数据。

如此,即可在详细的事务代码中,完结对应的事务功用。

开发之始,即为规划,此篇仅为根底规划篇,后期将会逐渐完善各三方途径付出完结类。

烦琐至此,此下,正式开文。

思路规划图如下

多应用多平台支付模块设计-基础模块开篇

此下,规划详细的表结构,笔者依据现在主意,规划两张表“订单表”、“订单进程表”。

数据库表结构如下

多应用多平台支付模块设计-基础模块开篇

多应用多平台支付模块设计-基础模块开篇

表联系图如下

多应用多平台支付模块设计-基础模块开篇

既,表规划完结,此下将详细完结事务功用。

开篇之始,笔者先界说对应的“订单相关字典”。

其中“订单事务类型”未预留字典类型,详细事务功用引入此库完结时,自主界说即可。

另,付出办法现在框架仅完结“微信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 {
    @Override
    public 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> {
    @Override
    public 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();
    }
    @Override
    public 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));
        }
    }
    @Override
    public 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> {
    @Override
    public 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付出逻辑。

文至于此,诸君加油、共勉。