前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

什么是状态机?为什么要用?

State Machine ,不是指一台实际机器,而是指一个数学模型,一般就是指一张状态转换图,主要作用是用来管理复杂的状态流转。

image-20230720091827698

2、状态机4大概念

  说明
State 状态,一个状态机至少要包含两个状态。
Event 事件,事件就是执行某个操作的触发条件或者口令。对于自动门,“按开门按钮”就是一个事件
Action 动作,事件发生以后要执行动作。例如事件是“按开门按钮”,动作是“开门”。编程的时候,一个 Action一般就对应一个函数,动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
Transition 变换,也就是从一个状态变化为另一个状态。例如“开门过程”就是一个变换。

3、UML

image-20230720092352278

4、时序图

image-20230720091716574

一、状态

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

ContactAuthor