Java 编程语言中,状态机主要有这几个 spring statemachine
、squirrel-foundation
、COLA-component-statemachine
调研后发现前两个都是有状态的,需要持久化,考虑到目前项目的复杂性选择了阿里开源的无状态状态机组件,下面是cola-component-statemachine 实战。
状态机主要解决问题是:
maven 参考:
<dependency> <groupId>com.alibaba.cola</groupId> <artifactId>cola-component-statemachine</artifactId> <version>4.3.2</version> </dependency>
使用状态机管理一个简单的审批流程状态。
首先定义了一个状态机基础抽象,用于后续规范其他状态机
/** * 通用基础设定及方法 * @param <S> 状态枚举/类 * @param <E> 事件枚举/类 * @param <C> 上下文数据对象 */ public interface BaseMachine<S,E,C> { /** * 获取状态机id */ String getMachineId(); /** * 激活某个事件 * * @param status 状态枚举 * @param event 事件 * @param context 上下文参数 */ default S fire(S status, E event, C context) { String machineId = getMachineId(); StateMachine<S, E, C> objectObjectObjectStateMachine = StateMachineFactory.get(machineId); return objectObjectObjectStateMachine.fireEvent(status, event, context); } }
然后定义审批的状态和事件
需要注意的是状态不等于事件,但是名称又往往相似
状态:
@Getter public enum ComStates { PENDING_SUBMIT(0,"待提审"), AUDITING(2,"审核中(单/多人)"), SUCCESS(3,"已通过"), REJECT(4,"已驳回"), CANCEL(5,"已取消"), ; private final Integer value; private final String name; ComStates(Integer value,String name){ this.value = value; this.name = name; } public static ComStates getByValue(Integer value){ return new ArrayList<>(Arrays.asList(ComStates.values())).stream().filter(o-> Objects.equals(o.value,value)).findFirst().orElse(null); } }
事件:
@Getter public enum ComEvents { SUBMIT(1,"提交审核"), CANCEL(2,"撤销审核"), PASS_AUDIT(4,"通过审核"), REJECT_AUDIT(5,"驳回审核") ; private final Integer value; private final String name; ComEvents(Integer value,String name){ this.value = value; this.name = name; } }
审批事件流程参考
一共五个事件,五个简易流程
演示项目结构参考:
测试接口:
@GetMapping("/com/get") public ComContext get(String dataId){ return dbExample.get(dataId); } @GetMapping("/com/submit") public Object submit(String dataId){ ComContext context = dbExample.get(dataId); ComContext ctx=new ComContext(); BeanUtils.copyProperties(context,ctx); return comAuditMachine.fire(ComStates.getByValue(context.getCurrentState()), ComEvents.SUBMIT, ctx); } @GetMapping("/com/cancel") public Object cancel(String dataId){ ComContext context = dbExample.get(dataId); ComContext ctx=new ComContext(); BeanUtils.copyProperties(context,ctx); return comAuditMachine.fire(ComStates.getByValue(context.getCurrentState()), ComEvents.CANCEL, ctx); } @GetMapping("/com/audit") public Object audit(String dataId,Long suid,Integer state,String msg){ ComContext context = dbExample.get(dataId); ComContext ctx=new ComContext(); BeanUtils.copyProperties(context,ctx); ctx.setSessionUserId(suid); ctx.setCurrentNodeAuditState(state); ctx.setCurrentNodeReason(msg); ComEvents comEvents; if (Objects.equals(1,state)){ comEvents = ComEvents.PASS_AUDIT; }else{ comEvents = ComEvents.REJECT_AUDIT; } return comAuditMachine.fire(ComStates.getByValue(context.getCurrentState()),comEvents,ctx); }
主要包含,提交审批/取消审批/审批。另外一个get获取当前审核数据信息
下面模拟流程: 提交审批->取消审批
上面操作,一切都按预计执行。
下面执行以下流程:提交审批->1号审核人员通过->2号人员驳回
按预计执行完毕。
其他流程这里就不展开描述了,感兴趣的可以下载demo源码尝试
demo-boot-statemachine.zip (访问密码: 9987)
相关操作接口:
查看审核信息 http://localhost:8080/com/get?dataId=1 提交审核 http://localhost:8080/com/submit?dataId=1 取消审核 http://localhost:8080/com/cancel?dataId=1 首次审核不通过 http://localhost:8080/com/audit?dataId=1&suid=1&state=2&msg=notfond 1号人审核通过 http://localhost:8080/com/audit?dataId=1&suid=1&state=1 2号不通过 http://localhost:8080/com/audit?dataId=1&suid=2&state=2&msg=2notfond 2号通过 http://localhost:8080/com/audit?dataId=1&suid=2&state=1
需要注意的是引用状态机模式,并不能减少业务代码的编写,只是优化的整个编码的细节,如COLA的下图一样形象的讲解了这个
更多参考连接:
http://blog.xqlee.com/article/2403281832589381.html