最近好多业务都是流程状态的传递,借此机会写词文章,记录一下,什么样的场景设计需要我们的状态机:

目前市场流行的状态机:
 1.Spring Statemachine

2.阿里COLA4.4

状态机框架

  • Spring Statemachine (重量级选手)1.2k+ star.
  • squirrel-foundation(松鼠)1.8k+ star.
  • cola-statemachine (可乐)6.6k+ star.

springboot合cola-statemachine 4.4.0

cola-statemachine(阿里出品)

相比Spring statemachine状态机等的复杂,功能多;我们实际业务员需要常用的功能,简单使用,所以这类就显得不简洁;再看cola-statemachine相比就是小巧、无状态、简单、轻量、性能极高的状态机DSL实现,解决业务中的状态流转问题。
github:
https://github.com/alibaba/COLA/tree/master/cola-components/cola-component-statemachine

学习这玩意什么用:

状态机优势

1、状态机建立的控制中心是跟外界低耦合的,通过event通信;
2、控制中心所有的状态都是预设好的,不会超预料;
3、状态的跳转都是有设定控制条件的,会按照预设的转移路径运动;
4、状态机还非常容易的扩展和变更,支持因业务的发展而变更或扩展复杂业务流程。

Spring Boot StateMachine实现

<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>1.2.0.RELEASE</version></dependency>

Spring Boot cola实现

         <dependency><groupId>com.alibaba.cola</groupId><artifactId>cola-component-statemachine</artifactId><version>4.4.0-SNAPSHOT</version></dependency>

状态机实现步骤:

第一步生成一个状态机

第二步:设置一个外部状态转移类型的builder 
        第三步:设置状态机的id和ready
        第四步:触发状态机

概念:
State:状态

Event:事件,状态由事件触发,引起变化

Transition:流转,表示从一个状态到另一个状态

External Transition:外部流转,两个不同状态之间的流转

Internal Transition:内部流转,同一个状态之间的流转

Condition:条件,表示是否允许到达某个状态

Action:动作,到达某个状态之后,可以做什么

StateMachine:状态机

完成状态机配置:状态机的初始状态和所有状态机的转移规则

整个状态的调度逻辑主要依靠配置方式的定义,而所有的业务逻辑操作都被定义在了状态监听器中,其实状态监听器可以实现的功能远不止上面我们所述的内容,它还有更多的事件捕获

都是技术人员介绍那么多都是废话,直接上代码它不香

好多代码都是demo根本没有实际试用起来。今天给大家上点干活。

无脑选择spring自带的状态机:

场景一:电商的订单,和发货,退货的状态

企业无商城,你玩什么。因此我们的实际场景就是我们经常看到的订单状态的流转

状态机定义三件事:

1.定义枚举状态

2.定义枚举事件

3.定义事件流转的触发条件

有人就说了,为什么定义枚举呢?

答:你想定义啥,定义啥,你有本事,可以直接定义字典,定义接口,定义静态字段。

1.先给我们的业务订单定义状态

public enum OrderState implements IEnum<String> {CREATED(0, ""),//新创建订单PENDING(10, "Pending"),//支付待确认WAIT_SHIP(20, "Preparing"),//待发货REFUND_CHOICE(30, ""),//订单退款逻辑选择器,伪状态,数据库中不存在DELIVERING(40, "Shipped"),//已发货[运输中],所有的子单都发货,订单变更为已发货状态DELIVERED(50, "Shipped"),//已妥投[运输中],所有的子单都妥投,订单变更为妥投状态RECEIVED(60, "Received"),//已签收,所有的子单都签收(刨除逆向订单),订单变更为已签收COMPLETED(70, "Completed"),//完成,所有的子单都完成(刨除逆向订单),订单变更为已完成CANCELED(80, "Canceled"),//已取消,未支付订单、取消订单REFUND_AUDIT(90, "Reviewing"),//退货审核,所有子单都处于该状态REFUND_AUDIT_CHOICE(95, ""),//订单退款审核逻辑选择器,伪状态,数据库中不存在REFUNDING(100, "Refunding"),//退款中,所有子单都处于该状态REFUNDED(110, "Refunded");//已退款,所有子单都处于该状态/*** 此值为了解决父订单的状态取值而设,越大说明业务流程越深,时间离现在越近,订单的状态取此值最小的子单的状态*/@Getterprivate final int logicDepth;@Getter@Setterprivate String customerDesc;OrderState(int depth, String desc) {this.logicDepth = depth;this.customerDesc = desc;}@Overridepublic String getValue() {return name();}
}

2.定义事件

public enum OrderEvent implements IEnum<String> {COD_CHECKOUT,//创建订单后选择COD支付COD_CONFIRM,//支付确认COD_CANCEL,//支付取消COD_TIMEOUT,//支付确认超时PAY_SUCCESS,//PPD支付成功PAY_TIMEOUT,//支付超时PAY_CANCEL,//取消支付USER_CANCEL,//支付后/支付确认后用户取消PLATFORM_CANCEL,//支付后平台取消TIMEOUT_CANCEL,//订单匹配超时取消DO_SHIP,//发货ORDER_ARRIVE,//妥投CONFIRM_RECEIVE,//用户签收ORDER_REVIEW,//订单评价REJECT_ORDER,//用户拒签APPLY_RETURN,//申请退货退款RETURN_AGGREE,//退货退款审核通过RETURN_REJECT,//退货退款审核拒绝GOODS_RETURNED,//平台收到退回货物DO_REFUND,//收到货后,平台操作发起退款PPD_REFUND_SUCCESS,;//退款成功回调COD_REFUND_SUCCESS,//退款成功回调@Overridepublic String getValue() {return name();}
}

3.定义状态机配置

@Configuration
public class OrderStateMachineConfig {final static String MACHINEID = "orderItemStateMachine";@Beanpublic StateMachinePersister<OrderState, OrderEvent, OrderStateAware> orderItemPersister(StateMachinePersist<OrderState, OrderEvent, OrderStateAware> orderItemStateMachinePersist) {return new DefaultStateMachinePersister<>(orderItemStateMachinePersist);}@Beanpublic StateMachine<OrderState, OrderEvent> orderItemStateMachine() throws Exception {// @formatter:offStateMachineBuilder.Builder<OrderState, OrderEvent> builder = StateMachineBuilder.builder();builder.configureConfiguration().withConfiguration().machineId(MACHINEID).beanFactory(beanFactory);builder.configureStates().withStates().initial(OrderState.CREATED).choice(OrderState.REFUND_CHOICE).choice(OrderState.REFUND_AUDIT_CHOICE).end(OrderState.COMPLETED).end(OrderState.CANCELED).end(OrderState.REFUNDED).states(EnumSet.allOf(OrderState.class));builder.configureTransitions()//CREATED 状态流转.withExternal().source(OrderState.CREATED).target(OrderState.WAIT_SHIP).event(OrderEvent.PAY_SUCCESS).and().withExternal().source(OrderState.CREATED).target(OrderState.CANCELED).event(OrderEvent.PAY_CANCEL).and().withExternal().source(OrderState.CREATED).target(OrderState.CANCELED).event(OrderEvent.PAY_TIMEOUT).and().withExternal().source(OrderState.CREATED).target(OrderState.PENDING).event(OrderEvent.COD_CHECKOUT)//PENDING 状态流转.and().withExternal().source(OrderState.PENDING).target(OrderState.WAIT_SHIP).event(OrderEvent.COD_CONFIRM).and().withExternal().source(OrderState.PENDING).target(OrderState.CANCELED).event(OrderEvent.COD_CANCEL).and().withExternal().source(OrderState.PENDING).target(OrderState.CANCELED).event(OrderEvent.COD_TIMEOUT)//WAIT_SHIP 状态流转.and().withExternal().source(OrderState.WAIT_SHIP).target(OrderState.DELIVERING).event(OrderEvent.DO_SHIP).and().withExternal().source(OrderState.WAIT_SHIP).target(OrderState.REFUND_CHOICE).event(OrderEvent.USER_CANCEL).and().withExternal().source(OrderState.WAIT_SHIP).target(OrderState.REFUND_CHOICE).event(OrderEvent.PLATFORM_CANCEL).and().withExternal().source(OrderState.WAIT_SHIP).target(OrderState.REFUND_CHOICE).event(OrderEvent.TIMEOUT_CANCEL)//退货退款/仅退款/cancel choice流转.and().withChoice().source(OrderState.REFUND_CHOICE)//如果为COD支付[wait_ship,delivered],状态变为Canceled,事物提交后返还库存、退还限购,发送异步消息通知A端//COD received状态 不允许退款.first(OrderState.CANCELED, codRefundChoiceGuard,codRefundChoiceAction)//否则 !cod & wait_ship & 实付=0,状态变为Refunded,事物提交后返还库存、退还限购,退还cash,发送异步消息通知A端.then(OrderState.REFUNDED,cashRefundChoiceGuard,cashRefundChoiceAction)//否则 !cod & wait_ship & 实付>0, 状态变为Refunding,事物提交后返还库存、退还限购,退还cash,调用三方支付退款api,发送异步消息通知A端.then(OrderState.REFUNDING, ppdRefundOnlyChoiceGuard,ppdRefundOnlyChoiceAction)//否则 (!cod & received)(可能包含cash支付,此时也需要审核).then(OrderState.REFUND_AUDIT, ppdRefundChoiceGuard,ppdRefundChoiceAction)//DELIVERING 状态流转.and().withExternal().source(OrderState.DELIVERING).target(OrderState.DELIVERED).event(OrderEvent.ORDER_ARRIVE)//DELEVERED 状态流转.and().withExternal().source(OrderState.DELIVERED).target(OrderState.RECEIVED).event(OrderEvent.CONFIRM_RECEIVE).and().withExternal().source(OrderState.DELIVERED).target(OrderState.REFUND_CHOICE).event(OrderEvent.REJECT_ORDER)//RECEIVED 状态流转.and().withExternal().source(OrderState.RECEIVED).target(OrderState.COMPLETED).event(OrderEvent.ORDER_REVIEW).and().withExternal().source(OrderState.RECEIVED).target(OrderState.REFUND_CHOICE).event(OrderEvent.APPLY_RETURN)//RETURN_AUDIT 状态流转.and().withExternal().source(OrderState.REFUND_AUDIT).target(OrderState.COMPLETED).event(OrderEvent.RETURN_REJECT).and().withExternal().source(OrderState.REFUND_AUDIT).target(OrderState.REFUND_AUDIT_CHOICE).event(OrderEvent.RETURN_AGGREE)//审核通过后.and().withChoice().source(OrderState.REFUND_AUDIT_CHOICE)//实付=0.first(OrderState.REFUNDED,refundAuditChoiceGuard)//实付>0.last(OrderState.REFUNDING)//REFUNDING 状态流转.and().withExternal().source(OrderState.REFUNDING).target(OrderState.REFUNDED).event(OrderEvent.PPD_REFUND_SUCCESS)
//                .and().withExternal()
//                .source(OrderState.REFUNDING).target(OrderState.REFUNDED).event(OrderEvent.COD_REFUND_SUCCESS);// @formatter:onreturn builder.build();}@Beanpublic StateMachinePersist<OrderState, OrderEvent, OrderStateAware> orderItemStateMachinePersist() {return new StateMachinePersist<OrderState, OrderEvent, OrderStateAware>() {@Overridepublic void write(StateMachineContext<OrderState, OrderEvent> context, OrderStateAware contextObj) {}@Overridepublic StateMachineContext<OrderState, OrderEvent> read(OrderStateAware contextObj) {return new DefaultStateMachineContext<>(contextObj.getState(),null, null, null, null, MACHINEID);}};}
}

4.定义状态机

public interface OrderEventFirer extends OrderStateAware {default void fireEvent(StateMachineRestorer restorer, OrderEvent event) {StateMachine<OrderState, OrderEvent> stateMachine = restorer.restore(this);stateMachine.sendEvent(event);OrderState newState = stateMachine.getState().getId();changeState(newState,event);}default void fireEvent(StateMachineRestorer restorer, OrderEvent event, Map<String,Object> headers) {StateMachine<OrderState, OrderEvent> stateMachine = restorer.restore(this);MessageBuilder<OrderEvent> builder = MessageBuilder.withPayload(event);for (Map.Entry<String, Object> entry : headers.entrySet()) {builder.setHeader(entry.getKey(), entry.getValue());}Message<OrderEvent> message = builder.build();stateMachine.sendEvent(message);OrderState newState = stateMachine.getState().getId();changeState(newState,event);}default void changeState(OrderState newState, OrderEvent event){OrderState currentState = this.getState();Assert.state(currentState != newState,"Undefined state transition.state=" + currentState + ",event=" + event);this.setBackState(currentState);this.setState(newState);this.setLatestAction(event);}void setState(OrderState state);void setBackState(OrderState state);void setLatestAction(OrderEvent event);
}

5.业务代码使用

 @Overridepublic void doDelivered(String orderItemUuid, TrackDetailsDto tracking) {OrderItem orderItem = baseMapper.findByUuid(orderItemUuid);orderItem.setDeliverAt(tracking.getDeliverDate());orderItem.fireEvent(stateMachineRestorer, OrderEvent.ORDER_ARRIVE);if(null == orderItem.getPaymentAt()) {orderItem.setPaymentAt(orderItem.getDeliverAt());}baseMapper.updateById(orderItem);Order order = orderDao.findByUuid(orderItem.getOrderUuid());if (null == order.getDeliveredCount()) {order.setDeliveredCount(0);}order.setDeliveredCount(order.getDeliveredCount() + 1 );List<OrderState> subStates = baseMapper.findByOrderUuid(order.getUuid()).stream().map(OrderItem::getState).collect(Collectors.toList());if (order.stateModified(subStates)) {smsSender.sendSms(SmsBizType.ORDER_SINGED,order.getLanguage(),order.getShippingAddressMobile());}orderDao.updateById(order);}

写完收工:

好多网友看了,欲哭无泪,看了这么久不能运行。白扯半天。

springboot+状态机相关推荐

  1. springboot状态机模式

    链接: 状态机和工作流的区别. 链接: 状态机引擎选型. 链接: 彻底搞懂Spring状态机原理,实现订单与物流解耦. 链接: spring statemachine收录. 链接: spring st ...

  2. SpringBoot状态机

    状态机优势 1.状态机建立的控制中心是跟外界低耦合的,通过event通信: 2.控制中心所有的状态都是预设好的,不会超预料: 3.状态的跳转都是有设定控制条件的,会按照预设的转移路径运动: 4.状态机 ...

  3. Springboot整合squirrel-foundation状态机

    目录 一. 快速入门 1 . maven 2 . 快速开始 3 . Fluent Api 4 . 状态机四要素 5 . 状态机构建器 6 . 状态机转换操作(代码配置方式) 7 . 状态机转换操作(注 ...

  4. Spring-boot state-machine 状态机 papyrus 详细操作步骤

    之所以写这篇文章是我们公司需要用到,然后百度和其他搜索引擎都没有相关过多详细的介绍和操作步骤,所以我写一篇有关eclipse的状态机开发 前提要求:  需要安装eclipse的papyrus插件 插件 ...

  5. Springboot + redis + 注解 + 拦截器来实现接口幂等性校验

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:wangzaiplus www.jianshu.com/p/ ...

  6. springboot + redis + 注解 + 拦截器 实现接口幂等性校验

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 来源:https://www.jianshu.com/p/6189275403ed 一.概念 ...

  7. springboot token_Springboot接口幂等性基于token实现方案

    什么是接口幂等 幂等(idempotent.idempotence)是一个数学与计算机学概念,常见于抽象代数中,即f(f(x)) = f(x).简单的来说就是一个操作多次执行产生的结果与一次执行产生的 ...

  8. c# 基于layui的通用后台管理系统_【SpringBoot】三十三、SpringBoot+LayUI后台管理系统开发脚手架...

    点击蓝色字免费订阅,每天收到这样的好信息 前言:最近有不少粉丝关注本公众号.并且我已经成功开通了流量主同时会赚一点点广告费,我打算每个月把这部分钱拿出来给大家买点书刊,算是给大家一点福利吧.大家想买什 ...

  9. redis 判断存在性_实战 | springboot+redis+拦截器 实现接口幂等性校验

    来源:https://www.jianshu.com/p/6189275403ed 一.概念 幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次 比如: 订单接口, 不能 ...

最新文章

  1. loadlibrary 失败_职称评审失败的原因有哪些?
  2. VS2017一次性运行多个项目的方法
  3. 你不知道的JavaScript运算符
  4. 使用SearchView报错java.lang.UnsupportedOperationException: Failed to resolve ...
  5. 前端学习(1354):集合关联
  6. Linux常用压缩和解压命令
  7. jq之slideup()
  8. 关于 java.lang.OutOfMemoryError: Java heap space
  9. React 错误Each child in an array or iterator should have a unique “key” prop
  10. 20190823 尚硅谷MySQL核心技术
  11. LINUX 下安装 jdk 问题(please use alien to install rpm packages on Debian )
  12. Python+Selenium ----unittest单元测试框架
  13. 可调稳压电源lm317实验报告_LM317可调稳压电源实训实验.doc
  14. 18-HTML标签的居中
  15. FlinkSql系列5之 Regular Join
  16. python按什么键停止运行_python如何停止运行
  17. Trinity(3)
  18. HYDU_create_process (./utils/launch/launch.c:75): execvp error on file *
  19. Python到底能做什么
  20. Python项目实战 1.1:项目准备.需求分析

热门文章

  1. Linux与Windows下Shebang的执行
  2. 如何解决html字体发虚,CSS3动画过程中文字模糊如何解决?
  3. 打开wps,提示: 运行时错误 429 activeX部件不能创建对象
  4. EOS智能合约开发(二十三)nodeos调用mongo_db_plugin源码分析
  5. 【实战】PHP如何使用 ElasticSearch 做搜索
  6. Matplotlib雷达图、三维饼状图
  7. AI医生来啦,ChatGPT在医疗领域的未来可期
  8. 显卡驱动导致的屏保运行假死
  9. 2020 各企业PHP高级面试题汇集
  10. python自动化控制arduino_LattePandaAI-Python控制Arduino LED灯