手写Spring状态机
前言
Github:https://github.com/HealerJean
什么是状态机?为什么要用?
State Machine
,不是指一台实际机器,而是指一个数学模型,一般就是指一张状态转换图,主要作用是用来管理复杂的状态流转。
2、状态机4大概念
说明 | |
---|---|
State |
状态,一个状态机至少要包含两个状态。 |
Event |
事件,事件就是执行某个操作的触发条件或者口令。对于自动门,“按开门按钮”就是一个事件 |
Action |
动作,事件发生以后要执行动作。例如事件是“按开门按钮”,动作是“开门”。编程的时候,一个 Action 一般就对应一个函数,动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。 |
Transition |
变换,也就是从一个状态变化为另一个状态。例如“开门过程”就是一个变换。 |
3、UML
图
4、时序图
一、状态
1、接口:IState
/**
* State 状态
*
* @author zhangyujin
* @date 2023-06-28 09:06:33
*/
public interface IState<S extends Enum<S>> {
S getState();
}
2、业务状态枚举: OrderStatusEnum
package com.healerjean.proj.statemechine.statue;
/**
* OrderStatusEnum
*
* @author zhangyujin
* @date 2023/6/28$ 10:58$
*/
public enum OrderStatusEnum implements IState<OrderStatusEnum> {
INIT("init", "初始"),
WAIT_PAYMENT("waitPayment", "待支付"),
WAIT_DELIVER("waitDeliver", "待发货"),
WAIT_RECEIVE("waitReceive", "待收货"),
FINISH("finish", "完结"),
;
private final String code;
private final String desc;
OrderStatusEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
@Override
public OrderStatusEnum getState() {
return this;
}
}
3、获取状态工厂: IStateFactory
/**
* StateFactory
*
* @author zhangyujin
* @date 2023-06-28 11:06:09
*/
public interface IStateFactory<S extends Enum<S>, T extends IState<S>> {
/**
* 获取状态
*
* @param enumState enumState
* @return T
*/
T buildState(S enumState);
}
二、事件
1、接口:IEvent
package com.healerjean.proj.statemechine.enent;
/**
* Event 动作
*
* @author zhangyujin
* @date 2023-06-28 09:06:45
*/
public interface IEvent<E extends Enum<E>> {
/**
* getEvent
* @return E
*/
E getEvent();
}
2、业务事件枚举: OrderEventEnum
package com.healerjean.proj.statemechine.enent;
/**
* OrderEventEnum
*
* @author zhangyujin
* @date 2023/6/28$ 11:02$
*/
public enum OrderEventEnum implements IEvent<OrderEventEnum> {
CREATE("Create", "订单创建"),
PAYED("payed", "支付"),
DELIVERY("delivery", "发货"),
RECEIVED("received", "收货"),
;
private final String code;
private final String desc;
OrderEventEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
@Override
public OrderEventEnum getEvent() {
return this;
}
}
三、执行结果
1、枚举:EventExecuteResultEnum
package com.healerjean.proj.statemechine.enums;
import java.util.Arrays;
import java.util.Objects;
/**
* EventExecuteResultEnum
* @author zhangyujin
* @date 2023/6/28$ 09:50$
*/
public enum EventExecuteResultEnum {
SUCCESS("success", "成功", true),
SUCCESS_REPEAT("successRepeat", "成功-重复", true),
FAIL_TRY_LOCK_ERROR("failTryLock", "失败-获取状态机同步锁失败", false),
FAIL_CONFIG_EMPTY("failConfigEmpty", "失败-获取不到流转配置", false),
FAIL_EXECUTE_ERROR("failError", "失败-错误", false),
;
private final String code;
private final String msg;
private final Boolean result;
/**
* EventExecuteResultEnum
*
* @param code code
* @param msg msg
* @param result success
* @return {@link }
*/
EventExecuteResultEnum(String code, String msg, boolean result) {
this.code = code;
this.msg = msg;
this.result = result;
}
/**
* toEventExecuteResultEnum
*
* @param code code
* @return {@link EventExecuteResultEnum}
*/
public static EventExecuteResultEnum toEventExecuteResultEnum(String code) {
return Arrays.stream(EventExecuteResultEnum.values()).filter(item -> item.getCode().equals(code)).findFirst().orElse(null);
}
/**
* getResult
*
* @param code code
* @return {@link Boolean}
*/
public static Boolean getResult(String code) {
EventExecuteResultEnum eventExecuteResultEnum = toEventExecuteResultEnum(code);
if (Objects.nonNull(eventExecuteResultEnum)) {
return eventExecuteResultEnum.getResult();
}
return null;
}
public String getCode() {
return code;
}
public String getMsg() {
return msg;
}
public Boolean getResult() {
return result;
}
}
2、业务异常:OrderStateMarchException
package com.healerjean.proj.statemechine.exception;
import com.healerjean.proj.statemechine.context.StateContext;
/**
* OrderStateMarchException
*
* @author zhangyujin
* @date 2023/6/28$ 11:49$
*/
public class OrderStateMarchException extends RuntimeException {
private String code;
private String message;
private StateContext context;
public OrderStateMarchException(StateContext context) {
this.context = context;
}
public OrderStateMarchException(String message, StateContext context) {
super(message);
this.message = message;
this.context = context;
}
public OrderStateMarchException(String code, String message) {
super(message);
this.code = code;
this.message = message;
}
public OrderStateMarchException(String code, String message, StateContext context) {
super(message);
this.code = code;
this.message = message;
this.context = context;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public StateContext getContext() {
return context;
}
public void setContext(StateContext context) {
this.context = context;
}
}
四、状态机上下文
1、抽象类: StateContext
package com.healerjean.proj.statemechine.context;
import com.healerjean.proj.statemechine.statue.IState;
/**
* StateContext
*
* @author zhangyujin
* @date 2023-06-28 10:06:06
*/
public abstract class StateContext<T extends IState> {
private T source;
private T target;
public StateContext() {
}
/**
* 获取当前状态机上下文
*
* @return 当前状态机上下文
*/
public abstract Object fetchContext();
public T getSource() {
return this.source;
}
public void setSource(final T source) {
this.source = source;
}
public T getTarget() {
return this.target;
}
public void setTarget(final T target) {
this.target = target;
}
}
2、 实现类:OrderStateEventContext
package com.healerjean.proj.statemechine.context;
import com.healerjean.proj.statemechine.enent.OrderEventEnum;
import com.healerjean.proj.statemechine.statue.OrderStatusEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* OrderStateEventContext
*
* @author zhangyujin
* @date 2023/6/28$ 11:29$
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class OrderStateEventContext extends StateEventContext<OrderStatusEnum, OrderEventEnum> {
/**
* 订单号
*/
private String orderId;
/**
* 用户Id
*/
private String userId;
/**
* 订单事件
*/
private OrderEventEnum orderEventEnum;
@Override
public Object fetchContext() {
return this;
}
@Override
protected OrderEventEnum fetchEvent() {
return this.orderEventEnum;
}
}
3、业务上下文:OrderStateEventContext
package com.healerjean.proj.statemechine.context;
import com.healerjean.proj.statemechine.enent.OrderEventEnum;
import com.healerjean.proj.statemechine.statue.OrderStatusEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* OrderStateEventContext
*
* @author zhangyujin
* @date 2023/6/28$ 11:29$
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class OrderStateEventContext extends StateEventContext<OrderStatusEnum, OrderEventEnum> {
/**
* 订单号
*/
private String orderId;
/**
* 用户Id
*/
private String userId;
/**
* 订单事件
*/
private OrderEventEnum orderEventEnum;
@Override
public Object fetchContext() {
return this;
}
@Override
protected OrderEventEnum fetchEvent() {
return this.orderEventEnum;
}
}
五、流转规则
1、Transitions
package com.healerjean.proj.statemechine.transition;
import com.healerjean.proj.statemechine.IStateMachine;
import org.apache.commons.compress.utils.Lists;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
/**
* Transitions
*
* @author zhangyujin
* @date 2023/6/28$ 09:43$
*/
public class Transitions<S extends Enum<S>, E extends Enum<E>> {
/**
* 所有转换
*/
private List<Transition> transitions = Lists.newArrayList();
/**
* stateMachine
*/
private IStateMachine stateMachine;
public Transitions() {
}
public S accept(S source, E event) {
Optional<Transition> transition = this.transitions.stream().filter(t -> t.accept(source, event)).findFirst();
return transition.map(Transition::getTarget).orElse(null);
}
public Transitions setStateMachine(IStateMachine stateMachine) {
this.stateMachine = stateMachine;
return this;
}
public Transition withTransition() {
return this.add(new Transition(this.stateMachine));
}
private Transition add(Transition transition) {
this.transitions.add(transition);
return transition;
}
public List<Transition> getTransitions() {
return this.transitions;
}
public class Transition {
private EnumSet<S> source;
private S target;
private E event;
private IStateMachine stateMachine;
public Transition(IStateMachine stateMachine) {
this.stateMachine = stateMachine;
}
public Transition source(S state) {
this.source = EnumSet.of(state);
return this;
}
public Transition source(EnumSet<S> states) {
this.source = states;
return this;
}
public Transition target(S state) {
this.target = state;
return this;
}
public Transition event(E event) {
this.event = event;
return this;
}
public Transitions and() {
return this.stateMachine.getTransitions();
}
/**
* 状态机核心校验逻辑
*
* @param source 当前状态
* @param event 当前具体状态机事件
* @return 是否接收该状态机事件
*/
boolean accept(S source, E event) {
return this.source.contains(source) && this.event.equals(event);
}
public EnumSet<S> getSource() {
return this.source;
}
public S getTarget() {
return this.target;
}
public E getEvent() {
return this.event;
}
public IStateMachine getStateMachine() {
return this.stateMachine;
}
}
}
2、CurrentTransition
package com.healerjean.proj.statemechine.transition;
import com.healerjean.proj.statemechine.IStateMachine;
import com.healerjean.proj.statemechine.enent.IEvent;
import com.healerjean.proj.statemechine.statue.IState;
import com.healerjean.proj.statemechine.statue.IStateFactory;
/**
* Transition
*
* @author zhangyujin
* @date 2023-06-28 11:06:25
*/
public class CurrentTransition<S extends IState, E extends IEvent> {
private final S source;
private final E event;
private final IStateMachine<S, E> stateMachine;
public CurrentTransition(final S source, final E event, final IStateMachine<S, E> stateMachine) {
this.source = source;
this.event = event;
this.stateMachine = stateMachine;
}
public S transit() {
IStateFactory stateFactory = this.stateMachine.getStateFactory();
return (S) stateFactory.buildState(this.stateMachine.getTransitions()
.accept(this.source.getState(), this.event.getEvent()));
}
public S getSource() {
return this.source;
}
public E getEvent() {
return this.event;
}
}
3、规则配置:
1)接口:IStateMachineConfig
package com.healerjean.proj.statemechine.config;
import com.healerjean.proj.statemechine.transition.Transitions;
/**
* @author zhangyujin
* @date 2023/6/28$ 09:36$
*/
public interface IStateMachineConfig<State extends Enum<State>, Event extends Enum<Event>> {
/**
* configure
*
* @param transitions transitions
*/
void configure(Transitions<State, Event> transitions) throws Exception;
}
2)业务规则实现:OrderStateMachineConfig
package com.healerjean.proj.statemechine.config.impl;
import com.healerjean.proj.statemechine.config.EnableStateMachine;
import com.healerjean.proj.statemechine.config.IStateMachineConfig;
import com.healerjean.proj.statemechine.enent.OrderEventEnum;
import com.healerjean.proj.statemechine.statue.OrderStatusEnum;
import com.healerjean.proj.statemechine.transition.Transitions;
import org.springframework.context.annotation.Configuration;
import java.util.EnumSet;
/**
* 订单状态机
*
* @author zhangyujin
* @date 2023/6/28$ 09:37$
*/
@EnableStateMachine("orderStateMachine")
@Configuration
public class OrderStateMachineConfig implements IStateMachineConfig<OrderStatusEnum, OrderEventEnum> {
/**
* configure
*
* @param transitions transitions
*/
@Override
public void configure(Transitions<OrderStatusEnum, OrderEventEnum> transitions) {
// 订单状态:初始化 动作:创建订单 -> 订单状态:待支付
transitions.withTransition()
.source(EnumSet.of(OrderStatusEnum.INIT))
.event(OrderEventEnum.CREATE)
.target(OrderStatusEnum.WAIT_PAYMENT);
// 订单状态:待支付 动作:支付 -> 订单状态:等待发货
transitions.withTransition()
.source(EnumSet.of(OrderStatusEnum.WAIT_PAYMENT))
.event(OrderEventEnum.PAYED)
.target(OrderStatusEnum.WAIT_DELIVER);
}
}
3)状态机和规则初始化:StateMachineBeanConfiguration
package com.healerjean.proj.statemechine.config;
import java.lang.annotation.*;
/**
* EnableStateMachine
*
* @author zhangyujin
* @date 2023-06-28 11:06:15
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface EnableStateMachine {
String value() default "statemachine";
}
package com.healerjean.proj.statemechine.config;
import com.healerjean.proj.statemechine.IStateMachine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
/**
* StateMachineBeanConfiguration
*
* @author zhangyujin
* @date 2023-06-28 11:06:37
*/
@Slf4j
@Configuration
public class StateMachineBeanConfiguration implements ApplicationContextAware {
/**
* StateMachineBeanConfiguration
*/
public StateMachineBeanConfiguration() {
}
/**
* 状态机配置
*
* @param applicationContext applicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, Object> stateMachineConfigBeans = applicationContext.getBeansWithAnnotation(EnableStateMachine.class);
Map<String, IStateMachine> stateMachineBeans = applicationContext.getBeansOfType(IStateMachine.class);
for (Map.Entry<String, Object> entry : stateMachineConfigBeans.entrySet()) {
String configName = entry.getKey();
Object configBean = entry.getValue();
EnableStateMachine enableStateMachine = applicationContext.findAnnotationOnBean(configName, EnableStateMachine.class);
assert enableStateMachine != null;
String enableStateMachineName = enableStateMachine.value();
for (Map.Entry<String, IStateMachine> e : stateMachineBeans.entrySet()) {
String stateMachineName = e.getKey();
IStateMachine stateMachineBean = e.getValue();
if (enableStateMachineName.equalsIgnoreCase(stateMachineName)) {
try {
((IStateMachineConfig) configBean).configure(stateMachineBean.getTransitions().setStateMachine(stateMachineBean));
} catch (Exception var5) {
log.error("StateMachineBeanConfiguration|Config {} failed.", stateMachineName);
}
log.info("StateMachineBeanConfiguration|Config {} success.", stateMachineName);
}
}
}
}
}
六、状态机
1、接口:IStateMachine
package com.healerjean.proj.statemechine;
import com.healerjean.proj.statemechine.context.StateContext;
import com.healerjean.proj.statemechine.enent.IEvent;
import com.healerjean.proj.statemechine.enums.EventExecuteResultEnum;
import com.healerjean.proj.statemechine.exception.OrderStateMarchException;
import com.healerjean.proj.statemechine.statue.IState;
import com.healerjean.proj.statemechine.statue.IStateFactory;
import com.healerjean.proj.statemechine.transition.CurrentTransition;
import com.healerjean.proj.statemechine.transition.Transitions;
/**
* IStateMachine
*
* @author zhangyujin
* @date 2023-06-28 11:06:27
*/
public interface IStateMachine<S extends IState, E extends IEvent> {
/**
* sendEvent
*
* @param event 执行时间
* @param context 状态机上下文
* @return 是否执行成功
*/
default EventExecuteResultEnum sendEvent(E event, StateContext<S> context) {
S source = this.getState(context);
CurrentTransition<S, E> currentTransition = new CurrentTransition(source, event, this);
S target = currentTransition.transit();
boolean accepted = target != null && target.getState() != null;
context.setSource(source);
context.setTarget(target);
EventExecuteResultEnum executeResultEnum;
if (accepted) {
try {
executeResultEnum = this.handleStateChange(context, event);
} catch (OrderStateMarchException e) {
executeResultEnum = this.handleStateChangeError(e);
}
} else {
executeResultEnum = this.handleStateChangeUnaccepted(context, event);
}
return executeResultEnum;
}
S getState(StateContext<S> context);
<T extends Enum<T>, K extends IState<T>> IStateFactory<T, K> getStateFactory();
Transitions getTransitions();
EventExecuteResultEnum handleStateChange(StateContext<S> context, E event);
EventExecuteResultEnum handleStateChangeUnaccepted(StateContext<S> context, E event);
EventExecuteResultEnum handleStateChangeError(OrderStateMarchException exception);
}
2、抽象类:AbstractStateMachine
package com.healerjean.proj.statemechine.impl;
import com.healerjean.proj.statemechine.IStateMachine;
import com.healerjean.proj.statemechine.context.StateContext;
import com.healerjean.proj.statemechine.enent.IEvent;
import com.healerjean.proj.statemechine.enums.EventExecuteResultEnum;
import com.healerjean.proj.statemechine.statue.IState;
import com.healerjean.proj.statemechine.statue.IStateFactory;
import com.healerjean.proj.statemechine.transition.Transitions;
/**
* AbstractStateMachine
*
* @author zhangyujin
* @date 2023/6/28$ 11:40$
*/
public abstract class AbstractStateMachine<S extends IState, E extends IEvent, Context extends StateContext<S>> implements IStateMachine<S, E> {
/**
* transitions
*/
private Transitions transitions = new Transitions();
@Override
public Transitions getTransitions() {
return transitions;
}
@Override
public <T extends Enum<T>, K extends IState<T>> IStateFactory<T, K> getStateFactory() {
return s -> (K) s;
}
/**
* 正常流转-结果处理
*
* @param context context
* @param event event
* @return EventExecuteResultEnum
*/
@Override
public EventExecuteResultEnum handleStateChange(StateContext<S> context, E event) {
return invokeHandleStateChange((Context) context);
}
/**
* 正常流转-结果处理
*
* @param context context
* @return EventExecuteResultEnum
*/
protected abstract EventExecuteResultEnum invokeHandleStateChange(Context context);
/**
* 失败流转-结果处理
*
* @param context context
* @param event event
* @return EventExecuteResultEnum
*/
@Override
public EventExecuteResultEnum handleStateChangeUnaccepted(StateContext<S> context, E event) {
return invokeHandleStateChangeUnaccepted((Context) context);
}
/**
* 错误流转-结果处理
*
* @param context context
* @return EventExecuteResultEnum
*/
protected abstract EventExecuteResultEnum invokeHandleStateChangeUnaccepted(Context context);
}
3、业务状态机:OrderStateMachine
package com.healerjean.proj.statemechine.impl;
import com.healerjean.proj.statemechine.context.OrderStateEventContext;
import com.healerjean.proj.statemechine.context.StateContext;
import com.healerjean.proj.statemechine.enent.OrderEventEnum;
import com.healerjean.proj.statemechine.enums.EventExecuteResultEnum;
import com.healerjean.proj.statemechine.exception.OrderStateMarchException;
import com.healerjean.proj.statemechine.statue.OrderStatusEnum;
import com.healerjean.proj.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* OrderStateMarchine
*
* @author zhangyujin
* @date 2023/6/28$ 11:40$
*/
@Slf4j
@Component
public class OrderStateMachine extends AbstractStateMachine<OrderStatusEnum, OrderEventEnum,
OrderStateEventContext> {
/**
* 执行状态机
*
* @param context context
* @return EventExecuteResultEnum
*/
public EventExecuteResultEnum invokeSendEvent(OrderStateEventContext context) {
OrderEventEnum orderEventEnum = context.getOrderEventEnum();
EventExecuteResultEnum executeResultEnum;
try {
executeResultEnum = sendEvent(orderEventEnum, context);
} catch (Exception e) {
log.error("[OrderStateMachine#invokeSendEvent] error, context:{}",
JsonUtils.toString(context), e);
return EventExecuteResultEnum.FAIL_EXECUTE_ERROR;
}
log.info("[OrderStateMachine#invokeSendEvent] context:{}, executeResultEnum:{}",
JsonUtils.toString(context), executeResultEnum);
return executeResultEnum;
}
/**
* getState
*
* @param context context
* @return OrderStatusEnum
*/
@Override
public OrderStatusEnum getState(StateContext<OrderStatusEnum> context) {
// todo 获取源状态
return OrderStatusEnum.INIT;
}
/**
* 成功-结果处理
*
* @param context context
* @return EventExecuteResultEnum
*/
@Override
protected EventExecuteResultEnum invokeHandleStateChange(OrderStateEventContext context) {
// 模拟异常
// throw new OrderStateMarchException("9999", "测试异常", context);
// todo 业务处理
return EventExecuteResultEnum.SUCCESS;
}
/**
* 失败-结果处理
*
* @param context context
* @return EventExecuteResultEnum
*/
@Override
protected EventExecuteResultEnum invokeHandleStateChangeUnaccepted(OrderStateEventContext context) {
// todo 业务处理
return EventExecuteResultEnum.FAIL_CONFIG_EMPTY;
}
/**
* 异常-结果处理
*
* @param exception context
* @return EventExecuteResultEnum
*/
@Override
public EventExecuteResultEnum handleStateChangeError(OrderStateMarchException exception) {
// todo 业务处理
return EventExecuteResultEnum.FAIL_EXECUTE_ERROR;
}
}
七、业务处理
1、接口:OrderService
package com.healerjean.proj.service;
import com.healerjean.proj.data.bo.OrderBO;
/**
* @author zhangyujin
* @date 2023/6/28$ 12:49$
*/
public interface OrderService {
/**
* 状态刘庄
* @param order
* @return
*/
boolean sendEvent(OrderBO order);
}
1)实现类:OrderServiceImpl
package com.healerjean.proj.service.impl;
import com.healerjean.proj.common.anno.LogIndex;
import com.healerjean.proj.data.bo.OrderBO;
import com.healerjean.proj.service.OrderService;
import com.healerjean.proj.statemechine.context.OrderStateEventContext;
import com.healerjean.proj.statemechine.enums.EventExecuteResultEnum;
import com.healerjean.proj.statemechine.impl.OrderStateMachine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* OrderService
* @author zhangyujin
* @date 2023/6/28$ 12:51$
*/
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
/**
* orderStateMachine
*/
@Resource
private OrderStateMachine orderStateMachine;
/**
* OrderService
* @param order order
* @return boolean
*/
@LogIndex
@Override
public boolean sendEvent(OrderBO order) {
OrderStateEventContext orderStateEventContext = new OrderStateEventContext();
orderStateEventContext.setOrderId(order.getOrderId());
orderStateEventContext.setUserId(order.getUserId());
orderStateEventContext.setOrderEventEnum(order.getEventEnum());
EventExecuteResultEnum eventExecuteResultEnum = orderStateMachine.invokeSendEvent(orderStateEventContext);
return eventExecuteResultEnum.getResult();
}
}
2、单元测试:OrderServiceImplTest
1)流转成功:sendEventSuccess
package com.healerjean.proj.service.impl;
import com.alibaba.fastjson.JSON;
import com.healerjean.proj.base.BaseJunit5SpringTest;
import com.healerjean.proj.data.bo.OrderBO;
import com.healerjean.proj.service.OrderService;
import com.healerjean.proj.statemechine.enent.OrderEventEnum;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import javax.annotation.Resource;
/**
* @author zhangyujin
* @date 2023/6/28$ 12:54$
*/
@Slf4j
public class OrderServiceImplTest extends BaseJunit5SpringTest {
/**
* orderService
*/
@Resource
private OrderService orderService;
@Test
void sendEventSuccess() {
OrderBO order = new OrderBO();
order.setOrderId(""+System.currentTimeMillis());
order.setUserId("8888");
order.setEventEnum(OrderEventEnum.CREATE);
boolean result = orderService.sendEvent(order);
log.info("[OrderServiceImplTest#sendEventSuccess] result:{}", JSON.toJSONString(result));
}
}
// context:
{
"source": "INIT",
"target": "WAIT_PAYMENT",
"orderId": "1687930465881",
"userId": "8888",
"orderEventEnum": "CREATE"
}
//executeResultEnum:"SUCCESS
2)流转失败:sendEventFail
package com.healerjean.proj.service.impl;
import com.alibaba.fastjson.JSON;
import com.healerjean.proj.base.BaseJunit5SpringTest;
import com.healerjean.proj.data.bo.OrderBO;
import com.healerjean.proj.service.OrderService;
import com.healerjean.proj.statemechine.enent.OrderEventEnum;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import javax.annotation.Resource;
/**
* @author zhangyujin
* @date 2023/6/28$ 12:54$
*/
@Slf4j
public class OrderServiceImplTest extends BaseJunit5SpringTest {
@Test
void sendEventFail() {
OrderBO order = new OrderBO();
order.setOrderId(""+System.currentTimeMillis());
order.setUserId("8888");
order.setEventEnum(OrderEventEnum.RECEIVED);
boolean result = orderService.sendEvent(order);
log.info("[OrderServiceImplTest#sendEventFail] result:{}", JSON.toJSONString(result));
}
}
// context:
{
"source": "INIT",
"orderId": "1687930466025",
"userId": "8888",
"orderEventEnum": "RECEIVED"
}
//executeResultEnum:"FAIL_CONFIG_EMPTY