Diseño de módulo de pago multiaplicación y multiplataforma: el comienzo del módulo básico

Recientemente, quiero integrar la plataforma de pago de tres partes en el marco del autor para simplificar y desarrollar funciones comerciales posteriores.

Para cumplir con la escalabilidad de esta función, es necesario definir las reglas de "interfaz comercial de pedidos" e "interfaz de método de pago".

Cuando el usuario realiza un pedido, la implementación comercial específica se obtiene de acuerdo con el "tipo de negocio" entrante y los datos del pedido específico se obtienen de acuerdo con el "método de pago".

De esta forma, las funciones comerciales correspondientes pueden implementarse en códigos comerciales específicos.

El comienzo del desarrollo es el diseño. Este artículo es solo un artículo de diseño básico. En la etapa posterior, la clase de implementación de pago de cada plataforma de terceros se mejorará gradualmente.

Prolongado hasta ahora, aquí está la apertura oficial.

El diagrama de diseño de la idea es el siguiente

Aquí, se diseña la estructura específica de la tabla Basado en la idea actual, el autor diseña dos tablas "Tabla de pedidos" y "Tabla de proceso de pedidos".

La estructura de la tabla de la base de datos es la siguiente

El diagrama de relación de tablas es el siguiente

Es decir, el diseño de la tabla está completo y las funciones comerciales se implementarán bajo este.

Al comienzo del capítulo, el autor define primero el "diccionario relacionado con el orden" correspondiente.

El "tipo de negocio de pedidos" no tiene un tipo de diccionario reservado. Cuando la función comercial específica se introduce en esta biblioteca, se puede definir de forma independiente.

Además, el marco actual del método de pago solo implementa el método "WeChat V2JSApi", que se implementará sucesivamente en el período posterior, y se definirán los diccionarios relacionados, y no todos los diccionarios se definirán aquí.

La clase de configuración del diccionario es la siguiente

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";

    }

}

Para lograr la alta escalabilidad del marco, el autor tiene la intención de definir dos conjuntos de especificaciones de interfaz para la realización de métodos comerciales y de pago específicos.

clase de especificación de interfaz

Ordenar clase de extensión comercial

Actualmente, esta interfaz declara dos conjuntos de interfaces, las funciones "Obtener datos de instantánea comercial" y "Procesar devolución de llamada de pago", que se utilizan para una implementación comercial específica.

Más tarde, si necesita implementarlo, puede agregarlo.

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;

}

Especificación de interfaz de método de pago

Esta interfaz, actualmente solo necesita obtener la función de datos de pedidos unificados de cada plataforma de pago.

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;

}

Hasta ahora, la especificación de la interfaz ha sido definida.

Aquí, el autor desea implementar la clase de implementación básica de los métodos de pago para la herencia y la extensión de la lógica comercial específica.

Clase de implementación básica del método de pago

Esta clase básica actualmente solo necesita obtener información de canal de acuerdo con el canal de aplicación específico y llamar al método de implementación de orden unificado de la subclase correspondiente.

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 ;
}

Hasta ahora, se ha implementado la definición de especificación específica. En este caso, se implementará primero la definición de "interfaz de pedido".

Implementación de la interfaz de pedidos unificados

Antes de la implementación específica de esta interfaz, el autor obtiene la clase de implementación comercial especificada de acuerdo con el tipo de negocio y almacena los "datos de instantánea comercial" en la tabla de pedidos, lo cual es conveniente para la operación y el mantenimiento posteriores.

Y después de que la información del pedido se almacene correctamente en el almacén, se obtiene la clase de implementación de pago específica de acuerdo con el método de pago, se obtienen los datos del pedido y se proporciona la "persona que llama" para realizar una solicitud de pago.

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);
    }

}

Hasta ahora, se ha implementado la interfaz de pedido. Cuando el usuario paga con éxito, la interfaz de devolución de llamada de pago correspondiente se activará activamente.

因此,笔者欲定义一套基础支付回调通知处理类,在具体支付回调接口,继承并实现即可。

支付回调接口对象类

实现基础回调实现类之前,笔者考虑片刻,顿觉定义支付回调接口对象,用此作为具体回调接口的接口参数定义类。

此接口,目前定义两个需实现的函数,为“获取订单号”、“支付金额”用于回调接口时使用。

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支付逻辑。

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

Supongo que te gusta

Origin juejin.im/post/7118376095790940197
Recomendado
Clasificación