支付系统设计三:渠道网关设计05-交易持久化

news2025/1/31 11:01:02

文章目录

  • 前言
  • 一、领域模型持久化服务工厂
  • 二、聚合创建工厂
    • 1. 模型创建
      • 1.1 获取域模型Class
      • 1.2 新建模型
      • 1.3 数据填充
    • 2. 模型持久化
      • 2.1 获取域模型对应的仓储
      • 2.2 调用域模型仓储进行持久化
  • 总结


前言

在这里插入图片描述
本篇将解析交易信息入库,即对上送的参数,在进行校验和一些列补全后,需要进行订单的落地了。

 domainDBSaveServiceFactory.getDomainDBSaveService(context.getClientTransCode()).execute(context);

一、领域模型持久化服务工厂

领域模型持久化服务工厂定义,根据transCode+DomainDBSaveServiceImpl获取到领域模型持久化服务,获取不到则采用默认domainDBSaveService服务实现。

/**
 * @author Kkk
 * @Describe: 领域模型持久化服务工厂
 */
@Component
public class DomainDBSaveServiceFactory {
    private static final Logger logger = LoggerFactory.getLogger(DomainDBSaveServiceFactory.class);

    /**
     * 准备数据service bean 后缀
     */
    private final static String DOMAINDBSAVESERVICE_SUFF = "DomainDBSaveServiceImpl";

    /**
     * 领域模型持久化服务
     */
    @Autowired
    private Map<String, DomainDBSaveService> domainDBSaveServiceMap;

    /**
     * 默认数据持久化服务
     */
    @Resource(name = "domainDBSaveService")
    private DomainDBSaveService defaultDomainDBSaveService;

    /**
     * 获取数据持久化服务
     * @param transCode
     * @return
     */
    public DomainDBSaveService getDomainDBSaveService(String transCode) {
        String dbTransCode = TransactionManager.getTransCode(transCode);
        StringBuilder key = new StringBuilder();
        if (StringUtils.isNotBlank(dbTransCode)) {
            key.append(dbTransCode).append(DOMAINDBSAVESERVICE_SUFF);
        } else {
            key.append(transCode).append(DOMAINDBSAVESERVICE_SUFF);
        }
        DomainDBSaveService domainDBSaveService = domainDBSaveServiceMap.get(key.toString());
        if (domainDBSaveService == null) {
            LoggerUtil.info(logger, "交易({})-未获取到交易入库服务-采用默认服务", transCode);
            domainDBSaveService = defaultDomainDBSaveService;
        }
        return domainDBSaveService;
    }
}

二、聚合创建工厂

域模型工厂的bean名称为域模型类名简称+BuildFactory。
持久化相关服务类关系如下:
在这里插入图片描述
默认数据持久化服务:

/**
 * @author Kkk
 * @Describe: 域模型保存服务实现
 */
@Service("domainDBSaveService")
public class DomainDBSaveServiceImpl extends AbstractDomainDBSaveService {

    @Override
    public void execute(PayGwContext context) {
        super.save(context);
    }
}
/**
 * @author Kkk
 * @Describe: 域模型保存服务实现抽象层
 */
@Service
public abstract class AbstractDomainDBSaveService extends AbstractTransactionService implements DomainDBSaveService {
    private static final Logger logger = LoggerFactory.getLogger(AbstractDomainDBSaveService.class);

    /**
     * 聚合创建工厂
     */
    @Resource(name = "defaultAggregateBuildFactory")
    private DefaultAggregateBuildFactory defaultAggregateBuildFactory;

    public void save(PayGwContext context) {
        String transNo = StringUtils.valueOf(context.getMessageDescription().getData(PayGwConstant.PAYGW_TRANS_NO));

        LoggerUtil.info(logger, "交易({})-交易入库-网关流水号({})-开始", context.getClientTransCode(), transNo);

        defaultAggregateBuildFactory.save(context.getMessageDescription().getDatas());

        LoggerUtil.info(logger, "交易({})-交易入库-网关流水号({})-结束", context.getClientTransCode(), transNo);
    }
}

下面我们看默认聚合创建工厂

defaultAggregateBuildFactory.save(context.getMessageDescription().getDatas());
/**
 * @author Kkk
 * @Describe: 默认域模型工厂
 */
@Component("defaultAggregateBuildFactory")
public class DefaultAggregateBuildFactory {
    private static final Logger logger = LoggerFactory.getLogger(DefaultAggregateBuildFactory.class);

    private static final String DOMAIN_FACTORY_SUFF = "BuildFactory";//域模型构建工厂后缀
    private static final String DOMAIN_SUFF = "Domain";//domain后缀
    private static final String ENTITY_SUFF = "Entity";//entity后缀
    private static final String DOMAIN_REPOSITORY_SIMPLE_SUFF = "RepositoryImpl";//简略的域模型仓储后缀
    private static final String DOMAIN_REPOSITORY_SUFF = "DomainRepositoryImpl";//域模型仓储后缀
    
    /**
     * 交易数据入库
     * @param data
     */
    public void save(Map<String, Object> data) {
        LoggerUtil.info(logger, "交易({})-交易入库-开始", data.get(PayGwConstant.PAYGW_TRANS_CODE));
        //1、模型创建
        BusinessModel model = (BusinessModel) build(data);

        //2、模型持久化
        if (model != null) {
            store(model);
        }
        LoggerUtil.info(logger, "交易({})-交易入库-结束", data.get(PayGwConstant.PAYGW_TRANS_CODE));
    }

    /**
     * 模型构建
     * @param data
     * @return
     */
    public AggregateBase build(Map<String, Object> data) {
        //1、获取域模型Class
        String transCode = StringUtils.valueOf(data.get(PayGwConstant.PAYGW_TRANS_CODE));
        Class<? extends AggregateBase> domainClass = getDomainClassByTransCode(transCode);

        //2、新建模型
        AggregateBase domain = null;
        try {
            domain = domainClass.newInstance();
        } catch (Exception e) {
            LoggerUtil.error(logger, "交易({})-模型构建-构建模型异常", transCode);
            throw new PayGwException(SystemErrorCode.SYSTEM_ERROR, e);
        }

        //3、模型数据填充
        domain.fill(data);

        return domain;
    }

    /**
     * 根据交易码获取域模型
     * @param transCode
     * @return
     */
    public Class<? extends AggregateBase> getDomainClassByTransCode(String transCode) {
        return TransactionManager.getDomainClass(transCode);
    }

    /**
     * 模型存储
     * @param domain
     */
    public void store(AggregateBase domain) {
        //1、获取模型对应的仓储;
        BusinessModelRepository businessModelRepository = getBusinessModelRepository(domain.getClass());

        //2、调用仓储进行持久化;
        businessModelRepository.store(domain);
    }

    /**
     * @Description 模型修改
     * @Params
     * @Return
     * @Exceptions
     */
    public int modify(Map<String, Object> data) {
        //1、获取域模型
        String transCode = StringUtils.valueOf(data.get(PayGwConstant.PAYGW_TRANS_CODE));
        Class<? extends AggregateBase> domainClass = getDomainClassByTransCode(transCode);

        //2、获取模型对应的仓储
        BusinessModelRepository businessModelRepository = getBusinessModelRepository(domainClass);

        //3、调用仓储进行修改
        return businessModelRepository.modify(data);
    }

    /**
     * @Description 获取域模型仓储
     * @Params
     * @Return
     * @Exceptions
     */
    public BusinessModelRepository getBusinessModelRepository(Class domainClass) {
        String domainClassName = StringUtils.convertFirstCharToLower(domainClass.getSimpleName());
        String beanName = "";
        if (domainClassName.endsWith(DOMAIN_SUFF) || domainClassName.endsWith(ENTITY_SUFF)) {
            beanName = domainClassName + DOMAIN_REPOSITORY_SIMPLE_SUFF;
        } else {
            beanName = domainClassName + DOMAIN_REPOSITORY_SUFF;
        }
        return ApplicationContextUtil.getBean(beanName, BusinessModelRepository.class);
    }
    // ... ...
}

1. 模型创建

 //1、模型创建
 BusinessModel model = (BusinessModel) build(data);

1.1 获取域模型Class

在这里插入图片描述

 /**
  * 交易-模型映射
  */
 private static final Map<TransactionEnum, Class<? extends AggregateBase>> demainMapping = new HashMap<TransactionEnum, Class<? extends AggregateBase>>();

从交易-模型映射对应关系中根据transCode获取到领域模型Class。

AggregateBase 模型聚合基类定义如下:

/**
 * @author Kkk
 * @Describe: 聚合基类
 */
public abstract class AggregateBase implements Domain {

    /**
     * @Description 聚合自我检查
     * @Params
     * @Return void
     * @Exceptions
     */
    public abstract void selfCheck();

    /**
     * @Description 利用数据进行模型自我填充
     * @Params
     * @Return void
     * @Exceptions
     */
    public abstract void fill(PayGwContext context);

    /**
     * @Description 模型填充
     * @Params
     * @Return
     * @Exceptions
     */
    public abstract void fill(Map<String, Object> data);
}

1.2 新建模型

//2、新建模型
 AggregateBase domain = null;
 try {
     domain = domainClass.newInstance();
 } catch (Exception e) {
     LoggerUtil.error(logger, "交易({})-模型构建-构建模型异常", transCode);
     throw new PayGwException(SystemErrorCode.SYSTEM_ERROR, e);
 }

1.3 数据填充

 //3、数据填充
 domain.fill(data);

单笔代扣模型Deduct数据填充,即将MessageDescription中的datas属性中值映射到Deduct对象属性。

   @Override
   public void fill(Map<String, Object> data) {
       BeanUtils.populate(this, data);
   }

2. 模型持久化

 //2、模型持久化
 if (model != null) {
     store(model);
 }

2.1 获取域模型对应的仓储

根据模型名称拼装特定后缀,找到模型对应的仓储。

//1、获取模型对应的仓储;
BusinessModelRepository businessModelRepository = getBusinessModelRepository(domain.getClass());

部分模型对应的类图如下:
在这里插入图片描述

2.2 调用域模型仓储进行持久化

 //2、调用仓储进行持久化;
 businessModelRepository.store(domain);
/**
 * @author Kkk
 * @Describe: 代扣模型仓储
 */
@Repository
public class DeductDomainRepositoryImpl implements DeductDomainRepository {

    @Autowired
    private DeductTransRepository deductTransRepository;
    @Autowired
    private CardErrorManagerRepository managerRepository;

    @Override
    public void store(AggregateBase domain) {
        DeductTrans deductTrans = new DeductTrans();
        BeanUtils.copyProperties(deductTrans, (Deduct) domain);
        deductTransRepository.saveAndFlush(deductTrans);
    }
    //... ...

}

总结

本篇对交易持久化实现做了详细的介绍,大概实现思路根据上送报文的transCode从领域模型持久化服务工厂获取到领域模型持久化服务,然后进行交易数据入库工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/521201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于ASA广告归因接入方法

投放苹果ASA广告&#xff0c;提高 app 曝光率、下载量的增长&#xff0c;那么我们该如何从后台看到投放广告的效果呢&#xff1f; 我们可以借助Apple Ads归因API。那什么是归因&#xff1f;什么又是API呢&#xff1f; 归因&#xff1a;可以给用户打标签&#xff0c;然后看他在…

[GUET-CTF2019]encrypt 题解

本题是输入了一个字符串&#xff0c;进行了rc4加密&#xff0c;和魔改的base64加密 RC4算法初始化函数 RC4加密过程 魔改的base64加密 最后加密的字符串是byte_602080 我们可以将byte_602080提取出来&#xff0c;下面是提取数据的IDC脚本&#xff0c;得到了密文 #include<…

赫夫曼树和赫夫曼编码详解

目录 何为赫夫曼树&#xff1f; 赫夫曼树算法 赫夫曼编码 编程实现赫夫曼树 编程实现赫夫曼编码 编程实现WPL 总代码及分析 何为赫夫曼树&#xff1f; 树的路径长度&#xff1a;从树根到每一结点的路径长度之和 结点的带权路径长度&#xff1a;从树根到该结点的路径长度…

2023网络安全十大顶级工具

从事网络安全工作&#xff0c;手上自然离不开一些重要的网络安全工具。今天&#xff0c;分享10大网络安全工具。 一、Kali Linux Kali 是一个基于 Debian 的 Linux 发行版。它的目标就是为了简单&#xff1a;在一个实用的工具包里尽可能多的包含渗透和审计工具。Kali 实现了这…

【AI面试】CNN 和 transformer 的问题汇总

​ CNN卷积神经网络和transformer相关的知识&#xff0c;是AI的一个基础的&#xff0c;也是前言的知识点。一般面试官会从以下这些问题入手&#xff1a; 卷积神经网络&#xff0c;有什么特点&#xff1f;1*1卷积核有什么作用&#xff1f;计算经过卷积的输出尺寸大小空洞卷积你…

机器学习之朴素贝叶斯三、拉普拉斯平滑技术、优化改进情感分析

文章目录 一、前文问题1. 先看下改进前我们的代码计算部分2. 问题分析&#xff1a; 二、针对问题进行解决1. 什么是拉普拉斯平滑技术2. 拉普拉斯优化-下溢上溢问题3. 改进地方分析&#xff1a;4.改进优化1.优化一&#xff0c;对条件概率计算进行优化2.优化二&#xff0c;对后延…

从小白到黑客高手:一份全面详细的学习路线指南

前言 黑客从入门到精通需要经过深入的学习和实践&#xff0c;这是一个需要长时间投入和大量精力的过程。在这份学习路线中&#xff0c;我将为你介绍黑客学习的基本知识和技能&#xff0c;帮助你逐步掌握黑客技能。 黑客 一、入门阶段 1.了解计算机基础知识 学习计算机基础知…

红黑树(小白教学)

分享一个动画展示的网址&#xff1a;Red/Black Tree Visualization (lerogo.com) 将红黑树之前&#xff0c;我们先来了解一下什么叫做2-3树&#xff01;&#xff01;&#xff01; 在我们以前学习的过程中&#xff08;二分搜索树、完全二叉树等&#xff09;结点都是存放了一个元…

Auto_GPT:如何使用Auto-GPT、安装、开发

文章目录 前言一、使用前提二、如何在您的 PC 上安装 Auto-GPT第 1 步&#xff1a;安装 Python第 2 步&#xff1a;获取 Auto-GPT 源代码和 OpenAI API 密钥第 3 步&#xff1a;在 Windows、MacOS和 Linux上安装 Auto-GPT 三、如何在你的 PC 上运行Auto-GPT总结 前言 Auto-GPT…

Redis消息队列(1)

一)消息队列:从字面意思上来看是存储消息的队列&#xff0c;最简单的消息队列包含三个元素: 1)消息队列:存储和管理消息&#xff0c;也被称之为是消息代理 2)生产者:发送消息到消息队列 3)消费者:从消息队列中获取消息并处理消息 4)当有用户想要进行秒杀下单的时候&#xff0c;…

CENTO OS上的网络安全工具(二十一)Hadoop HA swarm容器化集群部署

如果使用swarm来构建Hadoop、Spark之类的集群&#xff0c;一个绕不过去的问题每个容器都需要支持SSH免密互联——因为Hadoop需要。这就需要事先准备可以一键进行集群化部署的SSH镜像。 一、SSH集群及镜像的构建 1. 准备更换镜像源的Centos7 由于Centos7已经停止维护&#xff0c…

stm32 iic驱动ds1307实际使用驱动

本文使用的工程代码如下&#xff1a; (1条消息) stm32iic驱动ds1307实际使用驱动&#xff0c;参考博客&#xff1a;资源-CSDN文库 上次我记得写了一个使用开发板测试DS1307的测试例程&#xff0c;DS1307也是使用测试板&#xff0c;后面项目上具体使用了&#xff0c;又优化了驱…

HelloSpring

1.beans.xml配置文件 在resource资源文件夹下创建beans.xml文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&qu…

我们的愿景是在个人计算机上实现量子霸权

奥维尔号量子计算机 简介 采用扩展的量子二进制算法。在经典计算机上实现量子计算机。我们的景愿是在个人计算机上实现量子霸权。 此计算机的字长是64位&#xff0c;等效数据位为32位字长的量子计算机。我们采用量子扩展二进制&#xff0c;共有&#xff14;个字符:0,1,Q,P可以…

Redis---主从复制 哨兵

目录 一、主从复制 1、什么是主从复制呢&#xff1f; 2、案例演示 2.1 配置文件 2.2 一主二仆 2.2.1 相关题目&#xff1a; 2.3 薪火相传 & 反客为主 3、复制原理和工作流程 3.1、slave启动&#xff0c;同步清初 3.2 首次连接&#xff0c;全量复制 3.…

【CNN】卷积神经网络(LeNet)是什么?如何实现LeNet?

系列文章目录 第一章 深度学习 CNN中的卷积神经网络&#xff08;LeNet&#xff09; 目录 系列文章目录 文章目录 前言 一、卷积神经网络&#xff08;LeNet&#xff09;是什么&#xff1f; 二、LeNet的网络结构 三、实现LeNet模型 ​​​​ 总结 前言 本文主要是介绍卷…

【改进粒子群优化算法】自适应惯性权重粒子群算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【软考|软件设计师】某计算机系统的CPU主频为2.8GHz

目录 题&#xff1a; CPI MIPS 题&#xff1a; 某计算机系统的CPU主频为2.8GHz。某应用程序包括3类指令&#xff0c;各类指令的CPI &#xff08;执行每条指令所需要的时钟周期&#xff09;及指令比例如下表所示。执行该应用程序时 的平均CPI为______&#xff1b; 运算速度…

面试了一个00后,绝对能称为是内卷届的天花板

前言 公司前段缺人&#xff0c;也面了不少测试&#xff0c;结果竟然没有一个合适的。一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资也不低&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。令我印象最深的是一个00后测试员&#xf…

DelphiMVCFrameWork 源码分析(三)

中间件(MiddleWare) 文档中是这样说的&#xff1a; Middleware is a powerful and flexible layer within DMVCFramework. Middleware allows you to write SOLID code and separate the processing or each request into smaller steps to be invoked during the request ha…