状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。目前网上已经有很多实现方案,可以根据自己需要采用。
spring状态机框架:Spring StateMachine
在网上看了下关于spring状态机的文章,很多都很相似,好像都来自“程序员DD”的《使用Spring StateMachine框架实现状态机》 一文。
但是文中只是简单举了正常的例子,对于异常逻辑没有详细写出。狗尾续貂一下,补充下异常流程的demo。
package online.javaadu.statemachinedemo.model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.statemachine.annotation.OnEventNotAccepted;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;
@WithStateMachine
public class EventConfig {
private Logger logger = LoggerFactory.getLogger(getClass());
@OnTransition(target = "UNPAID")
public void create() {
logger.info("订单创建,待支付");
}
@OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
public void pay() {
logger.info("用户完成支付,待收货");
}
/**
* 状态不支持支付
*/
@OnEventNotAccepted(event = "PAY")
public void unpay() {
logger.info("当前状态不支持-完成支付");
}
@OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
public void receive() {
logger.info("用户已收货,订单完成");
}
/**
* 状态不支持收货
*/
@OnEventNotAccepted(event = "RECEIVE")
public void unreceive() {
logger.info("当前状态不支持-收货");
}
}
自建状态机
package machine.base;
import lombok.Getter;
/**
* 有限状态机的动作枚举 1-暂存 2-提交 3-审核 4-撤回 5-驳回 6-反审核 7-作废 8-删除
*/
@Getter
public enum EnumFsmEvent {
TEMP_STORAGE(1, "暂存"),
SUBMIT(2, "提交"),
AUDITED(3, "审核"),
WITHDRAW(4, "撤回"),
REJECT(5, "驳回"),
UNAUDITED(6, "反审核"),
CANCEL(7, "作废"),
DELETE(8, "删除")
;
private Integer code;
private String desc;
EnumFsmEvent(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public static EnumFsmEvent findEnumFsmEvent(Integer code) {
for (EnumFsmEvent event : EnumFsmEvent.values()) {
if (event.getCode().equals(code)) {
return event;
}
}
return null;
}
}
package machine.base;
import lombok.Getter;
/**
* @ClassName: EnumFsmStatus
* @Description: 1:暂存,2,审核中,3,已审核,4,已驳回,5,已反审,6,已作废;
* @Author: Yu RuiXin
* @Date: 2020/5/24 18:46
*/
@Getter
public enum EnumFsmStatus {
HAVE_BEAN_TEMP_STORAGE(1, "暂存"),
IS_AUDITED(2, "审核中"),
HAVE_BEAN_AUDITED(3, "已审核"),
HAVA_BEAN_REJECT(4, "已驳回"),
HAVE_BEAN_UNAUDITED(5, "已反审"),
HAVE_BEAN_CANCEL(6, "已作废")
;
private Integer code;
private String info;
EnumFsmStatus(Integer code, String info) {
this.code = code;
this.info = info;
}
public static EnumFsmStatus findEnumStatus(Integer code) {
for (EnumFsmStatus status : EnumFsmStatus.values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
}
package machine.base;
/**
* @ClassName: FsmMachine
* @Description: 状态机
* @Author: Yu RuiXin
* @Date: 2020/5/24 18:46
*/
public interface FsmMachine {
/**
* 初始化状态机
* 需要将状态与状态实体对应
*/
void initMachine() ;
/**
* 根据实际状态,获取状态实体
* @param status 单据状态
* @return
*/
FsmState getState(String status) ;
/**
* 执行状态扭转方法 实现类中可以
* @param event 操作事件
* @param status 单据状态
* @return
*/
FsmRetBody doEvent(String event, String status) ;
}
package machine.base;
/**
* @ClassName: FsmRetBody
* @Description: 状态机返回格式
* @Author: Yu RuiXin
* @Date: 2020/5/24 18:46
*/
public class FsmRetBody {
private int code;
private String msg;
private T data;
public FsmRetBody() {}
public FsmRetBody(int code, String msg) {
this.code = code;
this.msg = msg;
}
public FsmRetBody(FsmRetCode retCode) {
this.code = retCode.getCode();
this.msg = retCode.getDesc();
}
public static FsmRetBody success() {
return new FsmRetBody(FsmRetCode.SUCCESS);
}
public static FsmRetBody error() {
return new FsmRetBody(FsmRetCode.ERROR);
}
public static FsmRetBody createRetByCode(FsmRetCode retCode) {
return new FsmRetBody(retCode);
}
public static FsmRetBody noEvent() {
return new FsmRetBody(FsmRetCode.NO_EVENT);
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
package machine.base;
import lombok.Getter;
/**
* @ClassName: FsmRetCode
* @Description: 状态码
* @Author: Yu RuiXin
* @Date: 2020/5/24 18:45
*/
@Getter
public enum FsmRetCode {
SUCCESS(200, "执行成功"),
ERROR(500, "系统错误"),
NO_EVENT(401, "没有此事件"),
NON_EXECUTABLE_TEMP_STORAGE(60000, "当前状态,不可暂存"),
NON_EXECUTABLE_SUBMIT(60001, "当前状态,不可提交"),
NON_EXECUTABLE_AUDITED(60002, "当前状态,不可审核"),
NON_EXECUTABLE_WITHDRAW(60003, "当前状态,不可撤回"),
NON_EXECUTABLE_REJECT(60004, "当前状态,不可驳回"),
NON_EXECUTABLE_UNAUDITED(60005, "当前状态,不可反审核"),
NON_EXECUTABLE_CANCEL(60006, "当前状态,不可作废"),
NON_EXECUTABLE_DELETE(60007, "当前状态,不可删除"),
UNAUDITED_ERROR_HAS_RETURN_NOTE(60011,"存在退货单,不可反关单")
;
FsmRetCode(int code, String desc) {
this.code = code;
this.desc = desc;
}
private int code;
private String desc;
}
package machine.base;
import org.springframework.core.NamedThreadLocal;
/**
* @ClassName: FsmState
* @Description: 初始状态父类
* @Author: Yu RuiXin
* @Date: 2020/5/24 18:46
*/
public class FsmState {
/**
* 作为实体属性,可根据实际业务需要实例化,比如订单实体等,方便操作事件的方法使用
*/
private ThreadLocal tl = new NamedThreadLocal("SmpFsmThreadLocal");;
/**
* 暂存
*/
public FsmRetBody doTempStorage() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_TEMP_STORAGE);
}
/**
* 提交
*/
public FsmRetBody doSubmit() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_SUBMIT);
}
/**
* 审核
*/
public FsmRetBody doAudited() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_AUDITED);
}
/**
* 撤回
*/
public FsmRetBody doWithdraw() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_WITHDRAW);
}
/**
* 驳回
*/
public FsmRetBody doReject() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_REJECT);
}
/**
* 反审核
*/
public FsmRetBody doUnaudited() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_UNAUDITED);
}
/**
* 作废
*/
public FsmRetBody doCancel() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_CANCEL);
}
/**
* 删除
*/
public FsmRetBody doDelete() {
return FsmRetBody.createRetByCode(FsmRetCode.NON_EXECUTABLE_DELETE);
}
/**
* 操作事件
* 此方法是唯一需要判断执行的逻辑,根据操作事件决定执行具体的方法,只在父类中风状态,实现类中不需要处理
* @param event 需要执行的事件
*/
public FsmRetBody doEvent(EnumFsmEvent event) {
switch (event) {
case TEMP_STORAGE:
return this.doTempStorage();
case SUBMIT:
return this.doSubmit();
case AUDITED:
return this.doAudited();
case WITHDRAW:
return this.doWithdraw();
case REJECT:
return this.doReject();
case UNAUDITED:
return this.doUnaudited();
case CANCEL:
return this.doCancel();
case DELETE:
return this.doDelete();
default:
return FsmRetBody.noEvent();
}
}
public T getT() {
T t = this.tl.get();
tl.remove();
return t;
}
public void setT(T t) {
this.tl.set(t);
}
}
package machine.state;
import machine.FsmOperService;
import machine.base.FsmRetBody;
import machine.base.FsmState;
/**
* @ClassName: FsmStateAudited
* @Description: 已审核状态体-支持操作:反审核
* @Author: RuiXin Yu
* @Date: 2018/12/23 17:49
*/
public class FsmStateAudited extends FsmState {
FsmOperService fsmOperService;
public FsmStateAudited(FsmOperService fsmOperService) {
this.fsmOperService = fsmOperService;
}
@Override
public FsmRetBody doUnaudited() {
fsmOperService.doUnaudited(this.getT());
return FsmRetBody.success();
}
}
package machine.state;
import machine.base.FsmState;
/**
* @ClassName: FsmStateCancel
* @Description: 已作废状态体-支持动作:无
* @Author: RuiXin Yu
* @Date: 2018/12/23 17:50
*/
public class FsmStateCancel extends FsmState {
public FsmStateCancel() {}
}
package machine.state;
import machine.FsmOperService;
import machine.base.FsmRetBody;
import machine.base.FsmState;
/**
* @ClassName: FsmStateIsAudited
* @Description: 审核中状态体-支持操作:撤回、审核、驳回
* @Author: RuiXin Yu
* @Date: 2018/12/23 17:50
*/
public class FsmStateIsAudited extends FsmState {
FsmOperService fsmOperService;
public FsmStateIsAudited(FsmOperService fsmOperService) {
this.fsmOperService = fsmOperService;
}
@Override
public FsmRetBody doWithdraw() {
fsmOperService.doWithdraw(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doAudited() {
fsmOperService.doAudited(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doReject() {
fsmOperService.doReject(this.getT());
return FsmRetBody.success();
}
}
package machine.state;
import machine.FsmOperService;
import machine.base.FsmRetBody;
import machine.base.FsmState;
/**
* @ClassName: FsmStateReject
* @Description: 已驳回状态体-支持时间:提交、审核、作废
* @Author: RuiXin Yu
* @Date: 2018/12/23 17:50
*/
public class FsmStateReject extends FsmState {
FsmOperService fsmOperService;
public FsmStateReject(FsmOperService fsmOperService) {
this.fsmOperService = fsmOperService;
}
@Override
public FsmRetBody doSubmit() {
fsmOperService.doSubmit(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doAudited() {
fsmOperService.doAudited(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doCancel() {
fsmOperService.doCancel(this.getT());
return FsmRetBody.success();
}
}
package machine.state;
import machine.FsmOperService;
import machine.base.FsmRetBody;
import machine.base.FsmState;
/**
* @ClassName: FsmStateTempStorage
* @Description: 暂存状态体-支持动作:暂存、提交、审核、删除
* @Author: RuiXin Yu
* @Date: 2018/12/23 17:50
*/
public class FsmStateTempStorage extends FsmState {
FsmOperService fsmOperService;
public FsmStateTempStorage(FsmOperService fsmOperService) {
this.fsmOperService = fsmOperService;
}
@Override
public FsmRetBody doTempStorage() {
fsmOperService.doTempStorage(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doSubmit() {
fsmOperService.doSubmit(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doAudited() {
fsmOperService.doAudited(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doDelete() {
fsmOperService.doDelete(this.getT());
return FsmRetBody.success();
}
}
package machine.state;
import machine.FsmOperService;
import machine.base.FsmRetBody;
import machine.base.FsmState;
/**
* @ClassName: FsmStateUnaudited
* @Description: 已反审状态体-支持动作:提交、审核、作废
* @Author: RuiXin Yu
* @Date: 2018/12/23 17:50
*/
public class FsmStateUnaudited extends FsmState {
FsmOperService fsmOperService;
public FsmStateUnaudited(FsmOperService fsmOperService) {
this.fsmOperService = fsmOperService;
}
@Override
public FsmRetBody doSubmit() {
fsmOperService.doSubmit(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doAudited() {
fsmOperService.doAudited(this.getT());
return FsmRetBody.success();
}
@Override
public FsmRetBody doCancel() {
fsmOperService.doCancel(this.getT());
return FsmRetBody.success();
}
}
package machine;
import machine.base.*;
import machine.state.*;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: FsmMachineService
* @Description: 状态机实现业务类
* @Author: RuiXin Yu
* @Date: 2018/12/23 17:49
*/
public class FsmMachineService implements FsmMachine {
private static final Map stateMap = new HashMap();
private FsmStateTempStorage fsmStateTempStorage;
private FsmStateIsAudited fsmStateIsAudited;
private FsmStateAudited fsmStateAudited;
private FsmStateReject fsmStateReject;
private FsmStateUnaudited fsmStateUnaudited;
private FsmStateCancel fsmStateCancel;
public FsmMachineService(FsmStateTempStorage fsmStateTempStorage, FsmStateIsAudited fsmStateIsAudited,
FsmStateAudited fsmStateAudited, FsmStateReject fsmStateReject,
FsmStateUnaudited fsmStateUnaudited, FsmStateCancel fsmStateCancel) {
this.fsmStateTempStorage = fsmStateTempStorage;
this.fsmStateIsAudited = fsmStateIsAudited;
this.fsmStateAudited = fsmStateAudited;
this.fsmStateReject = fsmStateReject;
this.fsmStateUnaudited = fsmStateUnaudited;
this.fsmStateCancel = fsmStateCancel;
}
@Override
@PostConstruct
public void initMachine() {
stateMap.put(EnumFsmStatus.HAVE_BEAN_TEMP_STORAGE, fsmStateTempStorage);
stateMap.put(EnumFsmStatus.IS_AUDITED, fsmStateIsAudited);
stateMap.put(EnumFsmStatus.HAVE_BEAN_AUDITED, fsmStateAudited);
stateMap.put(EnumFsmStatus.HAVA_BEAN_REJECT, fsmStateReject);
stateMap.put(EnumFsmStatus.HAVE_BEAN_UNAUDITED, fsmStateUnaudited);
stateMap.put(EnumFsmStatus.HAVE_BEAN_CANCEL, fsmStateCancel);
}
@Override
public FsmState getState(String statusCode) {
EnumFsmStatus status = EnumFsmStatus.findEnumStatus(Integer.valueOf(statusCode));
return stateMap.get(status);
}
/**
* 执行状态扭转方法
* @param eventCode 操作事件
* @param status 单据状态
* @return
*/
@Override
public FsmRetBody doEvent(String eventCode, String status) {
EnumFsmEvent event = EnumFsmEvent.findEnumFsmEvent(Integer.valueOf(eventCode));
FsmState state = this.getState(status);
return state.doEvent(event);
}
/**
* 执行状态扭转方法
* 由于退货业务有需要依赖退货单数据实体的地方,在上面的方法doEvent的基础上私有化定制,所以增加了设置实体T
* @param event
* @param status
* @param t 实体,可以根据业务需要设置类型
* @return
*/
public FsmRetBody doEvent(EnumFsmEvent event, EnumFsmStatus status, T t) {
FsmState state = this.getState(status.getCode().toString());
state.setT(t);
return state.doEvent(event);
}
}
package machine;
/**
* @ClassName: FsmOperService
* @Description:
* @Author: RuiXin Yu
* @Date: 2018/12/29 13:33
*/
public interface FsmOperService {
/**
* 暂存
* @param t
*/
void doTempStorage(T t);
/**
* 提交
* @param t
*/
void doSubmit(T t);
/**
* 审核
* @param t
*/
void doAudited(T t);
/**
* 撤回
* @param t
*/
void doWithdraw(T t);
/**
* 驳回
* @param t
*/
void doReject(T t);
/**
* 反审核
* @param t
*/
void doUnaudited(T t);
/**
* 作废
* @param t
*/
void doCancel(T t);
/**
* 删除
* @param t
*/
void doDelete(T t);
}