Solon v3.1.2

statefulflow - 两组接口应用演示

</> markdown

下面是一个行政审批的流程配置:

# classpath:flow/f1.chain.yml
id: f1
layout:
  - {id: step1, title: "发起审批", meta: {actor: "刘涛", form: "form1"}}
  - {id: step2, title: "抄送", meta: {cc: "吕方"}, task: "@OaMetaProcessCom"}
  - {id: step3, title: "审批", meta: {actor: "陈鑫", cc: "吕方"}, task: "@OaMetaProcessCom"}
  - {id: step4, title: "审批", type: "parallel", link: [step4_1, step4_2]}
  - {id: step4_1, meta: {actor: "陈宇"}, link: step4_end}
  - {id: step4_2, meta: {actor: "吕方"}, link: step4_end}
  - {id: step4_end, type: "parallel"}
  - {id: step5, title: "抄送", meta: {cc: "吕方"}, task: "@OaMetaProcessCom"}
  - {id: step6, title: "结束", type: "end"}

OaMetaProcessCom 可以帮我们实现邮件抄送之类的活

@Component("OaMetaProcessCom")
public class OaMetaProcessCom implements TaskComponent {
    @Override
    public void run(FlowContext context, Node node) throws Throwable {
        String cc = node.getMeta("cc");
        if (Utils.isNotEmpty(cc)) {
            //发送邮件...
        }
    }
}

1、断点操控场景(就是手动前进、或后退)

每个活动节点,都会被断点操控。一般使用 BlockStateController 比较合适(也可使用 ActorStateController,要注意不同状态控制器的特点)。比如开发 ai-flow 时:用户输入后,有些节点是自动前进,有些节点要停下来再等用户输出。

@Configuration
public class DemoCom {
    @Bean
    public StatefulFlowEngine flowEngine() {
        return StatefulFlowEngine.newInstance(StatefulSimpleFlowDriver.builder()
                .stateController(new BlockStateController() { //改进一下,节点可配置自动前进
                    @Override
                    public boolean isAutoForward(FlowContext context, Node node) {
                        return super.isAutoForward(context, node) || 
                                node.getMetaOrDefault("autoForward", false);
                    }
                })
                .stateRepository(new InMemoryStateRepository())
                .build());
    }

    @Bean
    public void test(StatefulFlowEngine flowEngine) {
        //单步前进(上下文需要配置,实例id)
        StatefulNode statefulNode = flowEngine.stepForward("c1", new FlowContext("instance-1")); //使用实例id
        assert "step1".equals(statefulNode.getNode().getId());

        statefulNode = flowEngine.stepForward("c1", new FlowContext("instance-1")); //使用实例id
        assert "step2".equals(statefulNode.getNode().getId());
    }
}

2、等待介入场景

这个场景就是把前进或后退分为3个步骤:

  • 先获取节点状态
  • 参与者介入
  • 再根据介入情况提交状态

这个场景,有参与者配置的,才会被要求介入(没有人员配置时,会自动前进)。一般使用 ActorStateController 比较合适。

@Configuration
public class DemoCom {
    @Bean
    public StatefulFlowEngine flowEngine() {
        return StatefulFlowEngine.newInstance(StatefulSimpleFlowDriver.builder()
                .stateController(new ActorStateController("actor")) //参与者配置,可多个。比如:userId, roleId...
                .stateRepository(new InMemoryStateRepository())
                .build());
    }

    @Bean
    public void test(StatefulFlowEngine flowEngine) {
        FlowContext context;
        StatefulNode statefulNode;

        context = new FlowContext("instance-1").put("actor", "刘涛"); //使用实例id

        statefulNode = flowEngine.getActivityNode("c1", context);
        assert "step1".equals(statefulNode.getNode().getId());
        assert StateType.WAITING == statefulNode.getState();

        //等待当前用户处理

        flowEngine.postActivityState(context, statefulNode.getNode(), StateType.COMPLETED);

        //-----------


        context = new FlowContext("instance-1").put("actor", "陈鑫"); //使用实例id

        statefulNode = flowEngine.getActivityNode("c1", context);
        assert "step3".equals(statefulNode.getNode().getId());
        assert StateType.WAITING == statefulNode.getState();

        //等待当前用户处理

        flowEngine.postActivityState(context, statefulNode.getNode(), StateType.COMPLETED);
    }
}

3、实现自动流转与阻断结合

重写 StateController 的 isAutoForward 方法,比如实现:有 "autoForward: true" 的元信息配置,则自动前进。

@Configuration
public class DemoCom {
    @Bean
    public StatefulFlowEngine flowEngine() {
        return StatefulFlowEngine.newInstance(StatefulSimpleFlowDriver.builder()
                .stateController(new BlockStateController() {
                    @Override
                    public boolean isAutoForward(FlowContext context, Node node) {
                        return super.isAutoForward(context, node) || 
                                node.getMetaOrDefault("autoForward", false);
                    }
                })
                .stateRepository(new InMemoryStateRepository())
                .build());
    }
}

配置效果(注意 autoForward)

# classpath:flow/f1.chain.yml
id: f1
layout:
  - {id: step1, title: "发起审批", meta: {actor: "刘涛", form: "form1"}}
  - {id: step2, title: "抄送", meta: {cc: "吕方", autoForward: true}, task: "@OaMetaProcessCom"}
  - {id: step3, title: "审批", meta: {actor: "陈鑫", cc: "吕方"}, task: "@OaMetaProcessCom"}
  - {id: step4, title: "审批", type: "parallel", link: [step4_1, step4_2]}
  - {id: step4_1, meta: {actor: "陈宇"}, link: step4_end}
  - {id: step4_2, meta: {actor: "吕方"}, link: step4_end}
  - {id: step4_end, type: "parallel"}
  - {id: step5, title: "抄送", meta: {cc: "吕方"}, task: "@OaMetaProcessCom"}
  - {id: step6, title: "结束", type: "end"}