阿里状态机引擎实现

news2025/4/21 14:15:50

状态机的技术选型看这篇就够了,最后一个直叫好! - 掘金

实现一个状态机引擎,教你看清DSL的本质_cola状态机-CSDN博客

一、引入jar包

<!--阿里状态机jar-->
<dependency>
	<groupId>com.alibaba.cola</groupId>
	<artifactId>cola-component-statemachine</artifactId>
	<version>4.3.2</version>
</dependency>        

二、引入流转类型枚举

package com.lx.designPattern.statepattern.statemachine.enums;

/**
 * 流转类型枚举
 * @author lwp
 * @date 2023-07-06 14:56:27
 * @version 1.0
 */
public enum TransitionTypeEnum {

    /**
     * 内部流转
     */
    INTERNAL,

    /**
     * 外部流转
     */
    EXTERNAL,

    /**
     * 多状态外部流转
     */
    EXTERNALS;
}

三、引入事件枚举

package com.lx.designPattern.statepattern.statemachine.enums;

/**
 * 履约状态事件枚举
 *
 * @author lwp
 * @version 1.0
 * @date 2023-07-06 13:40:11
 */
public enum FulfillmentStatusEventEnum {

    /**
     * 开始租赁非标商品履约
     */
    BEGIN_RENT_NON_STANDARD_GOODS_FULFILLMENT,

    /**
     * 完成资源匹配
     */
    MATCH_RESOURCE,

    /**
     * 完成租赁交付
     */
    COMPLETE_RENT_DELIVER,

    /**
     * 重置履约计划
     */
    RESET_FULFILLMENT,

    /**
     * 取消履约单
     */
    CANCEL_FULFILLMENT,

    /**
     * 创建售车交付履约单
     */
    CREATE_SALE_DELIVER_FULFILLMENT,

    /**
     * 完成服务执行中
     */
    COMPLETE_SERVICE_FULFILLMENT,

    /**
     * 非灰度履约单交付
     */
    NON_GRAY_DELIVER,

    /**
     * 欢乐租备车
     */
    HAPPY_RENT_PLAN_CAR,

    /**
     * 开始替换车履约
     */
    START_REPLACE_DELIVER_FULFILLMENT,
    /**
     * 开始常规租赁退车履约
     */
    START_RENT_BACK_CAR_FULFILLMENT,
    /**
     * 完成替换车车退车
     */
    COMPLETE_REPLACE_BACK_CAR_FULFILLMENT,
    /**
     * 完成租赁退车
     */
    COMPLETE_RENT_BACK_CAR_FULFILLMENT,
    /**
     * 取消履约 (新的)
     */
    CANCEL_FULFILLMENT_2ND,
    /**
     * 完成服务履约
     */
    COMPLETE_VEHICLE_SERVICE,

    /**
     * 渠道商履约
     */
    CHANNEL_FULFILLMENT,
    ;
}

四、引入流转状态枚举

package com.lx.designPattern.statepattern.statemachine.enums;

import com.lx.exception.BusinessException;

import java.util.Objects;

/**
 * 履约单状态枚举
 * @author lwp
 * @date 2023/1/5 9:16
 * @version 1.0
 */
public enum FulfillmentStatusEnum {

    /**
     * 初始状态
     */
    INITIAL(0, "初始状态"),

    /**
     * 待匹配
     */
    WAIT_MATCH(2, "待匹配"),
    /**
     * 进行中
     */
    IN_PROGRESS(3, "进行中"),
    /**
     * 已完成
     */
    COMPLETED(4, "已完成"),
    /**
     * 已取消
     */
    CANCELED(5, "已取消"),
    ;

    private Integer status;
    private String desc;

    FulfillmentStatusEnum(Integer status, String desc) {
        this.status = status;
        this.desc = desc;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public static FulfillmentStatusEnum getByStatus(Integer status) {
        for (FulfillmentStatusEnum fulfillmentStatusEnum : FulfillmentStatusEnum.values()) {
            if (Objects.equals(status, fulfillmentStatusEnum.getStatus())) {
                return fulfillmentStatusEnum;
            }
        }
        throw new BusinessException("未找到履约状态枚举");
    }
}
 1.需要处理的业务参数类
package com.lx.designPattern.statepattern.statemachine.dto;

import lombok.Data;

/**
 * 履约单dto
 * @author lwp
 * @date 2023-07-25 16:22:04
 * @version 1.0
 */
@Data
public class FulfillmentBillDTO {

    /**
     * 交易订单
     */
    private A a;

    /**
     * 履约主单
     */
    private B b;

    /**
     * 车辆履约子单
     */
    private C c;
}

五、准备状态机

package com.lx.designPattern.statepattern.statemachine;

import com.alibaba.cola.statemachine.StateMachine;
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
import com.lx.designPattern.statepattern.statemachine.statustransition.FulfillmentStatusTransition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * 履约状态机
 *
 * @author lwp
 * @version 1.0
 * @date 2023-07-27 10:31:27
 */
@Slf4j
@Lazy
@Component
public class FulfillmentStatusStateMachine {

    /**
     * 状态机ID
     */
    private static final String MACHINE_ID = "FulfillmentStatusStateMachine";

    /**
     * 状态机
     */
    private StateMachine<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> stateMachine;

    @Autowired
    private List<FulfillmentStatusTransition> fulfillmentStatusTransitions;

    /* ******************************* 履约单状态流转 *****************************/

    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        // 创建状态机
        StateMachineBuilder<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> stateMachineBuilder
                = StateMachineBuilderFactory.create();
        // 添加没有命中配置规则时的回调
        stateMachineBuilder.setFailCallback(this::stateMachineFailCallback);
        // 初始化transition
        initTransition(stateMachineBuilder);
        stateMachine = stateMachineBuilder.build(MACHINE_ID);
    }

    /**
     * 触发流转
     */
    public FulfillmentStatusEnum fireEvent(FulfillmentStatusEnum status,
                                           FulfillmentStatusEventEnum event,
                                           FulfillmentBillDTO fulfillmentBill) {
        FulfillmentStatusEnum resultStatus = stateMachine.fireEvent(status, event, fulfillmentBill);
        // 如果结果状态和源状态相同,代表流转失败
        if (resultStatus == status) {
            log.warn("履约单{}状态流转失败, from:{}, to:{}, event:{}",
                    fulfillmentBill.getMainFulfillmentBill().getFulfillmentCode(),
                    status.getStatus(),
                    resultStatus.getDesc(),
                    event);
        } else {
            log.info("履约单{}状态流转, from:{}, to:{}, event:{}",
                    fulfillmentBill.getMainFulfillmentBill().getFulfillmentCode(),
                    status.getStatus(),
                    resultStatus.getDesc(),
                    event);
        }
        return resultStatus;
    }

    /**
     * 没有命中配置规则时的回调
     */
    private void stateMachineFailCallback(FulfillmentStatusEnum status,
                                          FulfillmentStatusEventEnum event,
                                          FulfillmentBillDTO fulfillmentBill) {
        log.error("履约单{}状态流转失败: 未找到匹配的流转规则, from:{}, event:{}",
                fulfillmentBill.getMainFulfillmentBill().getId(),
                status.getDesc(),
                event);
    }

    /**
     * 初始化transition
     */
    private void initTransition(StateMachineBuilder<FulfillmentStatusEnum, FulfillmentStatusEventEnum,
            FulfillmentBillDTO> builder) {
        fulfillmentStatusTransitions.forEach(transition -> {
            switch (transition.getTransitionType()) {
                case INTERNAL:
                    if (transition.getWithin().isPresent()) {
                        builder.internalTransition()
                                .within(transition.getWithin().get())
                                .on(transition.getEvent())
                                .when(transition.getCondition())
                                .perform(transition.getAction());
                    } else {
                        log.error("初始化履约单内部状态流转错误: 缺少within参数");
                        throw new IllegalArgumentException("履约状态状态机初始化失败");
                    }
                    break;
                case EXTERNAL:
                    if (transition.getFrom().isPresent() && transition.getTo().isPresent()) {
                        builder.externalTransition()
                                .from(transition.getFrom().get())
                                .to(transition.getTo().get())
                                .on(transition.getEvent())
                                .when(transition.getCondition())
                                .perform(transition.getAction());
                    } else {
                        log.error("初始化履约单外部状态流转错误: 缺少from或to参数");
                        throw new IllegalArgumentException("履约状态状态机初始化失败");
                    }
                    break;
                case EXTERNALS:
                    if (transition.getFromAmong().isPresent() && transition.getTo().isPresent()) {
                        builder.externalTransitions()
                                .fromAmong(transition.getFromAmong().get())
                                .to(transition.getTo().get())
                                .on(transition.getEvent())
                                .when(transition.getCondition())
                                .perform(transition.getAction());
                    } else {
                        log.error("初始化履约单多状态外部状态流转错误: 缺少fromAmong或to参数");
                        throw new IllegalArgumentException("履约状态状态机初始化失败");
                    }
                    break;
                default:
                    log.error("不支持的流转类型:{}", transition.getTransitionType());
            }
        });
    }
}

六、准备流转接口

package com.lx.designPattern.statepattern.statemachine.statustransition;

import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import com.lx.designPattern.statepattern.statemachine.enums.TransitionTypeEnum;

import java.util.Optional;

/**
 * 履约单状态流转
 * @author lwp
 * @date 2023-07-06 15:08:18
 * @version 1.0
 */
public interface FulfillmentStatusTransition {

    /**
     * 获取类转类型
     * @return 流转类型
     */
    TransitionTypeEnum getTransitionType();

    /**
     * 获取within参数(内部流转必需)
     * @return within
     */
    default Optional<FulfillmentStatusEnum> getWithin() {
        return Optional.empty();
    }

    /**
     * 获取from参数(外部流转必需)
     * @return from
     */
    default Optional<FulfillmentStatusEnum> getFrom() {
        return Optional.empty();
    }

    /**
     * 获取fromAmong参数(多状态外部流转必需)
     * @return fromAmong
     */
    default Optional<FulfillmentStatusEnum[]> getFromAmong() {
        return Optional.empty();
    }

    /**
     * 获取to参数(外部流转和多状态外部流转必需)
     * @return to
     */
    default Optional<FulfillmentStatusEnum> getTo() {
        return Optional.empty();
    };

    /**
     * 获取event
     * @return on参数
     */
    FulfillmentStatusEventEnum getEvent();

    /**
     * 获取condition
     * @return when
     */
    Condition<FulfillmentBillDTO> getCondition();

    /**
     * 获取action
     * @return preform
     */
    Action<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> getAction();
}

七、实现流转接口和定义流转规则

package com.lx.designPattern.statepattern.statemachine.statustransition;

import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.dto.MainFulfillmentBill;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import com.lx.designPattern.statepattern.statemachine.enums.TransitionTypeEnum;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * 完成履约状态流转
 * @author lwp
 * @date 2023-07-12 10:30:32
 * @version 1.0
 */
@Component
public class CompleteFulfillmentTransition implements FulfillmentStatusTransition {

    //@Autowired
    //private FulfillmentBillDaoService fulfillmentBillDaoService;

    @Override
    public TransitionTypeEnum getTransitionType() {
        return TransitionTypeEnum.EXTERNAL;
    }

    @Override
    public Optional<FulfillmentStatusEnum> getFrom() {
        return Optional.of(FulfillmentStatusEnum.IN_PROGRESS);
    }

    @Override
    public Optional<FulfillmentStatusEnum> getTo() {
        return Optional.of(FulfillmentStatusEnum.COMPLETED);
    }

    @Override
    public FulfillmentStatusEventEnum getEvent() {
        return FulfillmentStatusEventEnum.COMPLETE_RENT_DELIVER;
    }

    @Override
    public Condition<FulfillmentBillDTO> getCondition() {
        return (fulfillmentBillDTO -> true);
    }

    @Override
    public Action<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> getAction() {
        return (srcState, tarState, event, fulfillmentBillDTO) -> {
            // 修改履约单状态
            MainFulfillmentBill updateMainBill = new MainFulfillmentBill();
            updateMainBill.setId(fulfillmentBillDTO.getMainFulfillmentBill().getId());
            updateMainBill.setStatus(tarState.getStatus());
            //fulfillmentBillDaoService.updateMainBillById(updateMainBill);
            System.out.println("状态改为完成了");
        };
    }
}

八、准备测试类测试

package com.lx.designPattern;

import com.lx.designPattern.statepattern.statemachine.FulfillmentStatusStateMachine;
import com.lx.designPattern.statepattern.statemachine.business.InsuranceStatusChangeServiceImpl;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.dto.MainFulfillmentBill;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Desc 阿里状态机测试类
 * @author lwp
 * @version 1.0
 * @date 2024-01-13 22:16:22
 */
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "dev")
public class StateMachineTest {

    @Autowired
    private FulfillmentStatusStateMachine fulfillmentStatusStateMachine;

    @Test
    public void handStatusChangeComplete() {
        FulfillmentBillDTO billDTO = new FulfillmentBillDTO();
        MainFulfillmentBill mainFulfillmentBill = new MainFulfillmentBill();
        mainFulfillmentBill.setFulfillmentCode("LY001");
        mainFulfillmentBill.setStatus(1);
        billDTO.setMainFulfillmentBill(mainFulfillmentBill);
        fulfillmentStatusStateMachine.fireEvent(FulfillmentStatusEnum.getByStatus(3),
                FulfillmentStatusEventEnum.COMPLETE_RENT_DELIVER,billDTO);
    }

    
}

 九、测试效果如下图

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

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

相关文章

blender 导入到 Marvelous Designer

1&#xff09; 将模型的所有部分合并为一个单独的mesh 2&#xff09; 先调整计量单位&#xff1a; 3&#xff09;等比缩放&#xff0c;身高调整到180cm左右 4&#xff09;应用当前scale 首先&#xff0c;选中你要修改的物体&#xff0c;然后按下Ctrl-A键&#xff0c;打开应用…

大数据仓库开发规范示例

大数据仓库开发规范示例 一、前提概要二、数仓分层原则及定义2.1 数仓分层原则2.2 数仓分层定义 三、数仓公共开发规范3.1 分层调用规范3.2 数据类型规范3.3 数据冗余规范3.4 NULL字段处理规范3.5 公共字段规范3.6 数据表处理规范3.7 事实表划分规范 四、数仓各层开发规范4.1 分…

vcenter综合利用总结

1.Sphere、vCenter、ESXi简介 ESXi&#xff1a;安装在实体服务器上&#xff0c;其实是个linux内核的操作系统&#xff0c;官方的说法是有自己专利的一个内核&#xff0c;不属于以往任何现有的产品。只有安装了ESXi以后你才能在上面创建虚拟机。你可以理解成在你的台式机上装的v…

重学Java 5 idea详细使用和运算符

慢点跑&#xff0c;前面的路不好走 ——24.1.14 一、IDEA的使用 1.idea的介绍 1.概述&#xff1a;开发工具 2.特点&#xff1a; a、idea是java写的&#xff0c;所以本地上必须有正确的jdk环境 b、idea自动保存 c、不用我们打开dos命令窗口执行javac和java命令 d、idea有强大的…

高级分布式系统-第9讲 实时调度--可调度性分析

调度的目的&#xff1a; 分布式实时系统中&#xff0c;很多任务同时尝试访问共享资源&#xff08;如处理器和网络&#xff09;&#xff0c;调度试图有效地利用这些资源来解决问题&#xff0c;以保证系统是正确的&#xff0c;换句话说是保证系统符合其所有的时间限制。 调度的…

Webpack模块打包工具

目录 Webpack模块打包工具知识点自测01.Webpack 简介以及体验目标讲解小结 02.Webpack 修改入口和出口目标讲解小结 03.案例-用户登录-长度判断目标讲解小结 04.Webpack 自动生成 html 文件目标讲解小结 05.Webpack-打包 css 代码目标讲解小结 06.优化-提取 css 代码目标讲解小…

吐血整理,性能测试重要指标+设计真实负载(详细总结)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、性能测试之重要…

8年老鸟,自动化测试经验,测试数据管理分析总结,一篇打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 问题&#xff1a;…

2024年软件测试行发展趋势,“我“如何成为全栈测试工程师?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试行业的现状…

26.9K Star,漫画阅读 APP 开源了

今天推荐是一款适用于 Android 6.0 及更高版本的免费开源漫画阅读器&#xff0c;基于 Kotlin 开发的。这款 APP 完全免费、好用、无广告&#xff0c;自带上千个全球漫画源&#xff0c;在线阅读和下载都很方便&#xff0c;是漫画爱好者必备&#xff01; 它以插件的形式提供了来自…

服务器出现500、502、503错误的原因以及解决方法

服务器我们经常会遇到访问不了的情况有的时候是因为我们服务器被入侵了所以访问不了&#xff0c;有的时候是因为出现了服务器配置问题&#xff0c;或者软硬件出现问题导致的无法访问的问题&#xff0c;这时候会出现500、502、503等错误代码。基于以上问题我们第一步可以先重启服…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -关于我们页面实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

C#,求最长回文字符串的马拉车(Manacher)算法的源代码

一、回文字符串&#xff08;Palindromic String&#xff09; 回文字符串&#xff08;Palindromic String&#xff09;是指前、后向读起来完全相同的字符串。 回文字符串除了答题似乎没有什么用处 :P 二、求解思路 求解字符串的回文子串的基本思路&#xff1a; 1、遍历每个位…

基于SpringBoot的房屋交易平台的设计与实现

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1 研究背景 互…

深入浅出理解SPP、ASPP、DSPP、MDSPP空间金字塔池化系列结构(综合版)

一、参考资料 目标检测&#xff1a;SPP-net SPP原理及实现 金字塔池化系列的理解SPP、ASPP SPP&#xff0c;PPM、ASPP和FPN结构理解和总结 二、空间金字塔池化(SPP) 原始论文&#xff1a;[1] 1. 引言 传统的卷积神经网络中&#xff0c;池化层通常采用固定的池化层级和固定…

高校站群内容管理系统开发语言各有优势

站群管理系统开发可以选择多种编程语言&#xff0c;具体选择哪种语言最好需要考虑多个因素&#xff0c;包括开发团队的技术栈、项目需求、性能要求、安全性等。下面列举一些常见的编程语言及其适用场景&#xff1a; PHP&#xff1a;PHP是一种广泛使用的服务器端脚本语言&#…

QT通过QPdfWriter类实现pdf文件生成与输出

一.QPdfWriter类介绍 本文代码工程下载地址&#xff1a; https://download.csdn.net/download/xieliru/88736664?spm1001.2014.3001.5503 QPdfWrite是一个用于创建PDF文件的类&#xff0c;它是Qt库的一部分。它提供了一些方法和功能&#xff0c;使您能够创建和写入PDF文件。…

MySQL修炼手册4:分组与聚合:GROUP BY与HAVING的应用

写在开头 MySQL数据库的强大功能为我们提供了丰富的数据处理工具&#xff0c;其中GROUP BY与HAVING的应用使得数据的分组与聚合变得更加灵活和高效。在本篇博客中&#xff0c;我们将深入研究GROUP BY与HAVING的基础知识&#xff0c;并通过实际案例&#xff0c;展示它们在数据分…

select...for update锁详解

select…for update锁详解 select…for update的作用就是&#xff1a;如果A事务中执行了select…for update&#xff0c;那么在其提交或回滚事务之前&#xff0c;B&#xff0c;C&#xff0c;D…事务是无法操作&#xff08;写&#xff09;A事务select…for update所命中的数据的…

游戏找不到emp.dll,无法运行的5种解决方法

游戏在运行过程中提示找不到emp.dll文件&#xff0c;这一现象的原因可能涉及到多个层面。首先&#xff0c;emp.dll是一个动态链接库文件&#xff0c;对于特定的游戏运行至关重要&#xff0c;它可能包含了游戏运行所必需的函数、资源或其他关键信息。当系统在加载游戏时无法找到…