1. 程式人生 > >Spring StateMachine(2) UML狀態圖支援

Spring StateMachine(2) UML狀態圖支援

還是剛才的以二級審批請假流程為例。

繪製流程

首先建立 Papyrus 專案,選擇 StateMachine 模板,繪製流程圖如下:

然後建立 6 個 signal event 和與之繫結的 signal :

注意,在 Papyrus 圖中,除了 State (狀態) 和 Transition(遷移)之外,還有 Signal 和 Signal Event 的概念,它們對應於 StateMachine 中的 Event(事件)。其中 Signal 就是事件的名字(字串常量)。

將 Tansition 和 Signal Event 繫結(設定 trigger)。

載入 uml 狀態圖

將 Papyrus 生成的 uml 檔案放到 idea 的 resource 目錄。
因為 State、Event 和 Transition 都定義在 UML 中了,所以 States 列舉和 Events 列舉不再需要,狀態機的配置也簡化了,直接從 UML 檔案來載入:

@Override
    public void configure(StateMachineModelConfigurer<String, String> model) throws Exception {
        model
                .withModel()
                .factory(modelFactory());
    }

    @Bean
    public StateMachineModelFactory<String, String> modelFactory() {
        // 測試二級審批請假流程
        UmlStateMachineModelFactory factory = new UmlStateMachineModelFactory(
                "classpath:model.uml");
        factory.setStateMachineComponentResolver(stateMachineComponentResolver());
        return factory;
    }

注意,這裡 States 和 Events 的型別都變成了 String,畢竟在 UML 中不太好定義型別。
如果要註冊 Action 或者 Guard,可以通過 Resolver 進行:

    @Bean
    public StateMachineComponentResolver<String, String> stateMachineComponentResolver() {
        DefaultStateMachineComponentResolver<String, String> resolver = new DefaultStateMachineComponentResolver<>();
        resolver.registerAction("myAction", myAction());
        resolver.registerGuard("myGuard", myGuard());
        return resolver;
    }

    public Action<String, String> myAction() {
        return new Action<String, String>() {

            @Override
            public void execute(StateContext<String, String> context) {
            }
        };
    }

    public Guard<String, String> myGuard() {
        return new Guard<String, String>() {

            @Override
            public boolean evaluate(StateContext<String, String> context) {
                return false;
            }
        };
    }

傳送事件

跟之前一樣,傳送事件使用狀態機的 sendEvent。只不過 Event 的型別統統是字串,而且必須在 UML 中定義為 Signal。

 private BaseResponse sendEvent(String event,String leaveId){
        BaseResponse result = new BaseResponse();

        if(leaveId == null || leaveId.length()==0){
            result.success = false;
            result.message = "leaveId 不能為空";
            return result;
        }

        try {
            // 根據業務 id 獲取狀態
            persister.restore(stateMachine,leaveId);

            result.success = stateMachine.sendEvent(event);
            // 持久化狀態機
            if (result.success) {
                persister.persist(stateMachine, leaveId);
            }
            JSONObject data = new JSONObject();

            result.message = result.success ? "執行成功":"執行失敗";
            result.message = result.message + ",當前狀態為:"+stateMachine.getState().getId();
            data.put("leaveId",leaveId);
            data.put("event",event);
            data.put("state",stateMachine.getState().getId());
            result.data = data;
        } catch (Exception e) {
            e.printStackTrace();
            result.message = e.getMessage();
        }finally {
            stateMachine.stop();
            return result;
        }
    }

結論

可以看到,通過 UML 方式繪製狀態機,減少了在程式碼中定義 Event、State 和 Transition 的過程,但 UML 中必須通過額外的元素(Signal和 Signal Event)來定義事件,在目前來說 Spring StateMachine 只支援 Papyrus 繪製的 UML 圖。