在企業開發中,資料在不同的業務間傳輸是最常見的工作,是以雖然我們的主架構是用的狀态機,也就是從流程狀态的角度來看待這個項目,但在具體業務中,每個狀态的轉變中會牽涉到各類業務,這些業務有些需要收到狀态機變化的通知,需要把狀态值傳遞給業務類和業務方法,同樣的,在處理狀态變化是,也需要擷取業務資料,友善不同的業務在同一個狀态變化環節做各自的業務,下面我們就講下這個資料在spring statemachine裡面的傳遞。
這次我們的順序變一下,由外部傳入一個訂單号到controller開始:
@RequestMapping("/testOrderState")
public void testOrderState(String orderId) throws Exception {
StateMachine<OrderStates, OrderEvents> stateMachine = orderStateMachineBuilder.build(beanFactory);
System.out.println(stateMachine.getId());
// 建立流程
stateMachine.start();
// 觸發PAY事件
stateMachine.sendEvent(OrderEvents.PAY);
// 觸發RECEIVE事件
Order order = new Order(orderId, "547568678", "廣東省深圳市", "13435465465", "RECEIVE");
Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.RECEIVE).setHeader("order", order).build();
stateMachine.sendEvent(message);
// 擷取最終狀态
System.out.println("最終狀态:" + stateMachine.getState().getId());
}
controller收到request請求的參數,orderId,然後狀态機依次觸發事件,到觸發RECEIVE事件的時候,我們建立了一個Order,并把orderId塞進去了,其實更多的情況應該是我們拿到orderId,然後查詢資料庫,得到order資料對象,這裡為了簡化代碼,就建立一個啦。
然後就是真正的主角登場了,Message。它其實不是spirng statemachine專屬的,它是spring裡面通用的一種消息工具,看它的源代碼:
package org.springframework.messaging;
public interface Message<T> {
/**
* Return the message payload.
*/
T getPayload();
/**
* Return message headers for the message (never {@code null} but may be empty).
*/
MessageHeaders getHeaders();
}
它由兩個部分組成,看圖就知道了,和代碼裡面是一緻的
在spring statemachine裡面,我們把狀态塞到message的payload裡面,然後把需要傳遞的業務資料(例子裡面就是order對象)塞到header裡面。建立message用的是messagebuilder,看它的名字就知道是專門建立message的。
Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.RECEIVE).setHeader("order", order).build();
stateMachine.sendEvent(message);
建立了message後,狀态機sendEvent就可以不隻是傳一個event,可以組合event(OrderEvents.RECEIVE)和資料内容(order)一起發送給狀态機變化的處理類eventconfig了。讓我們看eventConfig的處理:
/**
* WAITING_FOR_RECEIVE->DONE 執行的動作
*/
@OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
public void receive(Message<OrderEvents> message) {
System.out.println("傳遞的參數:" + message.getHeaders().get("order"));
logger.info("---使用者已收貨,訂單完成---");
}
首先,receive方法的參數由之前的為空:
public void receive() {
logger.info("---使用者已收貨,訂單完成---");
}
改成了Message<OrderEvents> message,這樣就能從message的getHeaders裡面取到傳遞過來的資料對象了。
另外如果我們需要傳遞多個資料對象怎麼辦呢,比如我們在實際業務中,除了傳訂單資料,可能還需要把商品資料,或者支付結果資料也傳過來,那麼也容易,我們還是從controller裡面開始:
Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.RECEIVE).setHeader("order", order).setHeader("otherobj", "otherobjvalue").build();
在後面繼續setHeader就好了,然後到eventConfig裡面:
System.out.println("傳遞的參數:" + message.getHeaders().get("order"));
System.out.println("傳遞的參數:" + message.getHeaders().get("otherObj"));
運作後看日志:
傳遞的參數:Order [id=null, userId=547568678, address=廣東省深圳市, phoneNum=13435465465, state=RECEIVE]
傳遞的參數:otherObjValue
可知兩個的資料都傳遞到了eventConfig裡面了,這個就實作了多個資料對象的同時傳遞。
到這裡為止,狀态機通過message對象就和其他的業務代碼做到了資料連接配接。其實這個很關鍵,隻有做到和其他業務的資料傳遞,才能算的上真正的可用。
下一章我們繼續講狀态機的持久化問題和怎麼在非起始狀态開始建立狀态機
碼雲配套代碼位址