├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── lyxiang │ │ ├── SquirrelApplication.java │ │ ├── common │ │ ├── OrderCondition.java │ │ ├── OrderContext.java │ │ ├── OrderEvent.java │ │ └── OrderState.java │ │ ├── controller │ │ └── OrderController.java │ │ ├── dao │ │ └── OrderDTOMapper.java │ │ ├── declarative │ │ ├── DeclarativeOrderMachine.java │ │ ├── Main.java │ │ ├── OrderEventConverter.java │ │ └── OrderStateConverter.java │ │ ├── fluent │ │ ├── Main.java │ │ └── OrderStateMachine.java │ │ ├── pojo │ │ └── OrderDTO.java │ │ ├── service │ │ └── OrderService.java │ │ └── spring │ │ ├── AbstractOrderStatusMachineEngine.java │ │ ├── AbstractUntypedStateMachine.java │ │ ├── BaseOrderStateMachine.java │ │ ├── OrderStateMachineEngineFactory.java │ │ ├── SubmitOrderStateMachine.java │ │ └── SubmitOrderStateMachineEngine.java └── resources │ ├── application.properties │ └── mapper │ └── OrderDTOMapper.xml └── sql └── order.sql /README.md: -------------------------------------------------------------------------------- 1 | # squirrel-foundation-demo 2 | squirrel-foundation状态机的demo版本 3 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.2.RELEASE 9 | 10 | 11 | com.lyxiang 12 | squirrel-foundation-demo 13 | 0.0.1-SNAPSHOT 14 | squirrel 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | 40 | org.squirrelframework 41 | squirrel-foundation 42 | 0.3.8 43 | 44 | 45 | 46 | org.mybatis.spring.boot 47 | mybatis-spring-boot-starter 48 | 1.3.2 49 | 50 | 51 | 52 | com.alibaba 53 | druid-spring-boot-starter 54 | 1.1.1 55 | 56 | 57 | 58 | mysql 59 | mysql-connector-java 60 | runtime 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/SquirrelApplication.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.ComponentScan; 7 | 8 | @SpringBootApplication 9 | @ComponentScan(basePackages = {"com.lyxiang"}) 10 | @MapperScan(basePackages = "com.lyxiang.dao") 11 | public class SquirrelApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(SquirrelApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/common/OrderCondition.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.common; 2 | 3 | 4 | import org.squirrelframework.foundation.fsm.Condition; 5 | 6 | /** 7 | * @author: liyuxiang 8 | * @create: 2019-01-23 9 | */ 10 | public class OrderCondition implements Condition { 11 | 12 | @Override 13 | public boolean isSatisfied(Object context) { 14 | return true; 15 | } 16 | 17 | @Override 18 | public String name() { 19 | return "hahah"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/common/OrderContext.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.common; 2 | 3 | import com.lyxiang.pojo.OrderDTO; 4 | 5 | /** 6 | * @author: liyuxiang 7 | * @create: 2019-01-23 8 | */ 9 | public class OrderContext { 10 | 11 | public OrderContext(OrderDTO orderDTO) { 12 | this.orderDTO = orderDTO; 13 | } 14 | 15 | public OrderContext() { 16 | } 17 | 18 | public OrderDTO orderDTO; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/common/OrderEvent.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.common; 2 | 3 | /** 4 | * @author: liyuxiang 5 | * @create: 2019-01-23 6 | */ 7 | public enum OrderEvent { 8 | 9 | SUBMIT_ORDER, 10 | PAY, 11 | PART_SEND, 12 | SEND, 13 | COMPLETE 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/common/OrderState.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.common; 2 | 3 | /** 4 | * @author: liyuxiang 5 | * @create: 2019-01-23 6 | */ 7 | public enum OrderState { 8 | 9 | INIT, 10 | 11 | WAIT_PAY, 12 | 13 | WAIT_SEND, 14 | 15 | PART_SEND, 16 | 17 | WAIT_RECEIVE, 18 | 19 | COMPLETE, 20 | 21 | CANCELED; 22 | 23 | public static OrderState getState(String state) { 24 | for (OrderState orderState : OrderState.values()) { 25 | if (orderState.name().equalsIgnoreCase(state)) { 26 | return orderState; 27 | } 28 | } 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.controller; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import com.lyxiang.service.OrderService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * @author: liyuxiang 13 | * @create: 2019-01-29 14 | */ 15 | @RestController 16 | @RequestMapping(value = "/order/") 17 | public class OrderController { 18 | 19 | @Autowired 20 | OrderService orderService; 21 | 22 | @RequestMapping(value = "submitOrder") 23 | public Map submitOrder() { 24 | int orderId = orderService.submitOrder(); 25 | return ImmutableMap.of("orderId", orderId); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/dao/OrderDTOMapper.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.dao; 2 | 3 | import com.lyxiang.pojo.OrderDTO; 4 | 5 | public interface OrderDTOMapper { 6 | 7 | int insert(OrderDTO orderDTO); 8 | 9 | int updateByPrimaryKeySelective(OrderDTO orderDTO); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/declarative/DeclarativeOrderMachine.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.declarative; 2 | 3 | import com.lyxiang.common.OrderContext; 4 | import com.lyxiang.common.OrderEvent; 5 | import com.lyxiang.common.OrderState; 6 | import org.squirrelframework.foundation.fsm.annotation.State; 7 | import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters; 8 | import org.squirrelframework.foundation.fsm.annotation.States; 9 | import org.squirrelframework.foundation.fsm.annotation.Transit; 10 | import org.squirrelframework.foundation.fsm.annotation.Transitions; 11 | import org.squirrelframework.foundation.fsm.impl.AbstractUntypedStateMachine; 12 | 13 | /** 14 | * @author: liyuxiang 15 | * @create: 2019-01-23 16 | */ 17 | @States({ 18 | @State(name = "INIT", entryCallMethod = "entryStateInit", exitCallMethod = "exitStateInit", initialState = true), 19 | @State(name = "WAIT_PAY", entryCallMethod = "entryStateWaitPay", exitCallMethod = "exitStateWaitPay"), 20 | @State(name = "WAIT_SEND", entryCallMethod = "entryStateWaitSend", exitCallMethod = "exitStateWaitSend"), 21 | @State(name = "PART_SEND", entryCallMethod = "entryStatePartSend", exitCallMethod = "exitStatePartSend"), 22 | @State(name = "WAIT_RECEIVE", entryCallMethod = "entryStateWaitReceive", exitCallMethod = "exitStateWaitReceive"), 23 | @State(name = "COMPLETE", entryCallMethod = "entryStateComplete", exitCallMethod = "exitStateComplete") 24 | }) 25 | @Transitions({ 26 | @Transit(from = "INIT", to = "WAIT_PAY", on = "SUBMIT_ORDER", callMethod = "submitOrder"), 27 | @Transit(from = "WAIT_PAY", to = "WAIT_SEND", on = "PAY", callMethod = "pay"), 28 | @Transit(from = "WAIT_SEND", to = "PART_SEND", on = "PART_SEND", callMethod = "partSend"), 29 | @Transit(from = "PART_SEND", to = "WAIT_RECEIVE", on = "SEND", callMethod = "send"), 30 | @Transit(from = "WAIT_RECEIVE", to = "COMPLETE", on = "COMPLETE", callMethod = "complete") 31 | }) 32 | @StateMachineParameters(stateType = OrderState.class, eventType = OrderEvent.class, contextType = OrderContext.class) 33 | public class DeclarativeOrderMachine extends AbstractUntypedStateMachine { 34 | 35 | public void submitOrder(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 36 | System.out.println("submitOrder"); 37 | } 38 | 39 | public void pay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 40 | System.out.println("pay"); 41 | } 42 | 43 | public void partSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 44 | System.out.println("partSend"); 45 | } 46 | 47 | public void send(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 48 | System.out.println("send"); 49 | } 50 | 51 | public void complete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 52 | System.out.println("complete"); 53 | } 54 | 55 | public void entryStateInit(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 56 | System.out.println("entryStateInit"); 57 | } 58 | 59 | public void exitStateInit(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 60 | System.out.println("exitStateInit"); 61 | } 62 | 63 | public void entryStateWaitPay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 64 | System.out.println("entryStateWaitPay"); 65 | } 66 | 67 | public void exitStateWaitPay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 68 | System.out.println("exitStateWaitPay"); 69 | } 70 | 71 | public void entryStateWaitSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 72 | System.out.println("entryStateWaitSend"); 73 | } 74 | 75 | public void exitStateWaitSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 76 | System.out.println("exitStateWaitSend"); 77 | } 78 | 79 | public void entryStatePartSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 80 | System.out.println("entryStatePartSend"); 81 | } 82 | 83 | public void exitStatePartSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 84 | System.out.println("exitStatePartSend"); 85 | } 86 | 87 | public void entryStateWaitReceive(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 88 | System.out.println("entryStateWaitReceive"); 89 | } 90 | 91 | public void exitStateWaitReceive(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 92 | System.out.println("exitStateWaitReceive"); 93 | } 94 | 95 | public void entryStateComplete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 96 | System.out.println("entryStateComplete"); 97 | } 98 | 99 | public void exitStateComplete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 100 | System.out.println("exitStateComplete"); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/declarative/Main.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.declarative; 2 | 3 | import com.lyxiang.common.OrderEvent; 4 | import com.lyxiang.common.OrderState; 5 | import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory; 6 | import org.squirrelframework.foundation.fsm.UntypedStateMachine; 7 | import org.squirrelframework.foundation.fsm.UntypedStateMachineBuilder; 8 | 9 | /** 10 | * @author: liyuxiang 11 | * @create: 2019-01-24 12 | */ 13 | public class Main { 14 | 15 | public static void main(String[] args) { 16 | 17 | UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(DeclarativeOrderMachine.class); 18 | 19 | UntypedStateMachine fsm = builder.newAnyStateMachine(OrderState.INIT); 20 | 21 | fsm.start(); 22 | 23 | fsm.fire(OrderEvent.SUBMIT_ORDER); 24 | fsm.fire(OrderEvent.PAY); 25 | fsm.fire(OrderEvent.PART_SEND); 26 | fsm.fire(OrderEvent.SEND); 27 | fsm.fire(OrderEvent.COMPLETE); 28 | 29 | fsm.terminate(); 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/declarative/OrderEventConverter.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.declarative; 2 | 3 | import com.lyxiang.common.OrderEvent; 4 | import org.squirrelframework.foundation.fsm.Converter; 5 | 6 | /** 7 | * @author: liyuxiang 8 | * @create: 2019-01-24 9 | */ 10 | public class OrderEventConverter implements Converter { 11 | 12 | 13 | @Override 14 | public String convertToString(OrderEvent orderEvent) { 15 | return orderEvent.name(); 16 | } 17 | 18 | @Override 19 | public OrderEvent convertFromString(String name) { 20 | return OrderEvent.valueOf(name); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/declarative/OrderStateConverter.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.declarative; 2 | 3 | import com.lyxiang.common.OrderState; 4 | import org.squirrelframework.foundation.fsm.Converter; 5 | 6 | /** 7 | * @author: liyuxiang 8 | * @create: 2019-01-24 9 | */ 10 | public class OrderStateConverter implements Converter { 11 | 12 | @Override 13 | public String convertToString(OrderState orderState) { 14 | return orderState.name(); 15 | } 16 | 17 | @Override 18 | public OrderState convertFromString(String name) { 19 | return OrderState.valueOf(name); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/fluent/Main.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.fluent; 2 | 3 | import com.lyxiang.common.OrderContext; 4 | import com.lyxiang.common.OrderEvent; 5 | import com.lyxiang.common.OrderState; 6 | import com.lyxiang.common.OrderCondition; 7 | import org.squirrelframework.foundation.component.SquirrelProvider; 8 | import org.squirrelframework.foundation.fsm.DotVisitor; 9 | import org.squirrelframework.foundation.fsm.StateMachineBuilder; 10 | import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory; 11 | 12 | /** 13 | * @author: liyuxiang 14 | * @create: 2019-01-23 15 | */ 16 | public class Main { 17 | 18 | public static void main(String[] args) { 19 | 20 | OrderContext orderContext = new OrderContext(); 21 | 22 | StateMachineBuilder builder = StateMachineBuilderFactory.create(OrderStateMachine.class, OrderState.class, OrderEvent.class, OrderContext.class); 23 | 24 | builder.onEntry(OrderState.INIT).callMethod("entryStateInit"); 25 | builder.onExit(OrderState.INIT).callMethod("exitStateInit"); 26 | 27 | builder.onEntry(OrderState.WAIT_PAY).callMethod("entryStateWaitPay"); 28 | builder.onExit(OrderState.WAIT_PAY).callMethod("exitStateWaitPay"); 29 | 30 | builder.onEntry(OrderState.WAIT_SEND).callMethod("entryStateWaitSend"); 31 | builder.onExit(OrderState.WAIT_SEND).callMethod("exitStateWaitSend"); 32 | 33 | builder.onEntry(OrderState.PART_SEND).callMethod("entryStatePartSend"); 34 | builder.onExit(OrderState.PART_SEND).callMethod("exitStatePartSend"); 35 | 36 | builder.onEntry(OrderState.WAIT_RECEIVE).callMethod("entryStateWaitReceive"); 37 | builder.onExit(OrderState.WAIT_RECEIVE).callMethod("exitStateWaitReceive"); 38 | 39 | builder.onEntry(OrderState.COMPLETE).callMethod("entryStateCompleteByAdmin"); 40 | builder.onExit(OrderState.COMPLETE).callMethod("entryStateCompleteByAdmin"); 41 | 42 | builder.externalTransition().from(OrderState.INIT).to(OrderState.WAIT_PAY).on(OrderEvent.SUBMIT_ORDER).callMethod("stateInitToWaitPay"); 43 | builder.externalTransition().from(OrderState.WAIT_PAY).to(OrderState.WAIT_SEND).on(OrderEvent.PAY).callMethod("stateWaitPayToWaitSend"); 44 | builder.externalTransition().from(OrderState.WAIT_SEND).to(OrderState.PART_SEND).on(OrderEvent.PART_SEND).when(new OrderCondition()).callMethod("stateWaitSendToPartSend"); 45 | builder.externalTransition().from(OrderState.PART_SEND).to(OrderState.WAIT_RECEIVE).on(OrderEvent.SEND).callMethod("statePartSendToWaitReceive"); 46 | builder.externalTransition().from(OrderState.WAIT_RECEIVE).to(OrderState.COMPLETE).on(OrderEvent.COMPLETE).callMethod("stateWaitReceiveToComplete"); 47 | 48 | OrderStateMachine fsm = builder.newStateMachine(OrderState.INIT); 49 | fsm.start(); 50 | fsm.fire(OrderEvent.SUBMIT_ORDER, orderContext); 51 | fsm.fire(OrderEvent.PAY, orderContext); 52 | fsm.fire(OrderEvent.PART_SEND, orderContext); 53 | fsm.fire(OrderEvent.SEND, orderContext); 54 | fsm.fire(OrderEvent.COMPLETE, orderContext); 55 | 56 | //生成状态图 57 | DotVisitor visitor = SquirrelProvider.getInstance().newInstance(DotVisitor.class); 58 | fsm.accept(visitor); 59 | visitor.convertDotFile("MyStateMachine"); 60 | 61 | fsm.terminate(); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/fluent/OrderStateMachine.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.fluent; 2 | 3 | import com.lyxiang.common.OrderContext; 4 | import com.lyxiang.common.OrderEvent; 5 | import com.lyxiang.common.OrderState; 6 | import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine; 7 | 8 | /** 9 | * @author: liyuxiang 10 | * @create: 2019-01-23 11 | */ 12 | public class OrderStateMachine extends AbstractStateMachine { 13 | 14 | public void entryStateInit(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 15 | System.out.println(fromState + "->" + toState); 16 | } 17 | 18 | public void stateInitToWaitPay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 19 | System.out.println(fromState + "->" + toState); 20 | } 21 | 22 | public void stateWaitPayToWaitSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 23 | System.out.println(fromState + "->" + toState); 24 | } 25 | 26 | public void stateWaitSendToPartSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 27 | System.out.println(fromState + "->" + toState); 28 | } 29 | 30 | public void statePartSendToWaitReceive(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 31 | System.out.println(fromState + "->" + toState); 32 | } 33 | 34 | public void stateWaitReceiveToComplete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 35 | System.out.println(fromState + "->" + toState); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/pojo/OrderDTO.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.pojo; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author: liyuxiang 7 | * @create: 2019-01-21 8 | */ 9 | public class OrderDTO { 10 | 11 | private Integer id; 12 | 13 | private String state; 14 | 15 | private Date createTime; 16 | 17 | private Date updateTime; 18 | 19 | public Integer getId() { 20 | return id; 21 | } 22 | 23 | public void setId(Integer id) { 24 | this.id = id; 25 | } 26 | 27 | public String getState() { 28 | return state; 29 | } 30 | 31 | public void setState(String state) { 32 | this.state = state; 33 | } 34 | 35 | public Date getCreateTime() { 36 | return createTime; 37 | } 38 | 39 | public void setCreateTime(Date createTime) { 40 | this.createTime = createTime; 41 | } 42 | 43 | public Date getUpdateTime() { 44 | return updateTime; 45 | } 46 | 47 | public void setUpdateTime(Date updateTime) { 48 | this.updateTime = updateTime; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "OrderDTO{" + 54 | "id=" + id + 55 | ", state='" + state + '\'' + 56 | ", createTime=" + createTime + 57 | ", updateTime=" + updateTime + 58 | '}'; 59 | } 60 | 61 | public OrderDTO(String state) { 62 | this.state = state; 63 | } 64 | 65 | public OrderDTO() { 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.service; 2 | 3 | import com.lyxiang.common.OrderContext; 4 | import com.lyxiang.common.OrderEvent; 5 | import com.lyxiang.common.OrderState; 6 | import com.lyxiang.pojo.OrderDTO; 7 | import com.lyxiang.spring.OrderStateMachineEngineFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | 11 | /** 12 | * @author: liyuxiang 13 | * @create: 2019-01-29 14 | */ 15 | @Service 16 | public class OrderService { 17 | 18 | @Autowired 19 | OrderStateMachineEngineFactory orderStateMachineEngineFactory; 20 | 21 | public int submitOrder() { 22 | OrderDTO orderDTO = new OrderDTO(OrderState.INIT.name()); 23 | OrderContext orderContext = new OrderContext(orderDTO); 24 | orderStateMachineEngineFactory.fire(orderContext, OrderEvent.SUBMIT_ORDER); 25 | return orderContext.orderDTO.getId(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/spring/AbstractOrderStatusMachineEngine.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.spring; 2 | 3 | import com.lyxiang.common.OrderContext; 4 | import com.lyxiang.common.OrderEvent; 5 | import com.lyxiang.common.OrderState; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.context.ApplicationContextAware; 11 | import org.springframework.core.GenericTypeResolver; 12 | import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory; 13 | import org.squirrelframework.foundation.fsm.StateMachineConfiguration; 14 | import org.squirrelframework.foundation.fsm.UntypedStateMachine; 15 | import org.squirrelframework.foundation.fsm.UntypedStateMachineBuilder; 16 | 17 | /** 18 | * @author: liyuxiang 19 | * @create: 2019-01-21 20 | */ 21 | public abstract class AbstractOrderStatusMachineEngine implements ApplicationContextAware { 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(AbstractOrderStatusMachineEngine.class); 24 | 25 | private ApplicationContext applicationContext; 26 | 27 | protected UntypedStateMachineBuilder builder; 28 | 29 | public AbstractOrderStatusMachineEngine() { 30 | Class genericType = (Class) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractOrderStatusMachineEngine.class); 31 | builder = StateMachineBuilderFactory.create(genericType, ApplicationContext.class); 32 | } 33 | 34 | @Override 35 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 36 | this.applicationContext = applicationContext; 37 | } 38 | 39 | public void fire(OrderEvent orderEvent, OrderContext orderContext) { 40 | T stateMachine = builder.newUntypedStateMachine(OrderState.getState(orderContext.orderDTO.getState()), 41 | StateMachineConfiguration.create().enableDebugMode(true).enableAutoStart(true), 42 | applicationContext); 43 | try { 44 | stateMachine.fire(orderEvent, orderContext); 45 | } catch (Exception e) { 46 | logger.error("stateMachine.fire error"); 47 | } 48 | } 49 | 50 | 51 | protected abstract boolean accept(OrderState orderState); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/spring/AbstractUntypedStateMachine.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.spring; 2 | 3 | import org.squirrelframework.foundation.fsm.UntypedStateMachine; 4 | import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine; 5 | 6 | /** 7 | * @author: liyuxiang 8 | * @create: 2019-01-22 9 | */ 10 | public abstract class AbstractUntypedStateMachine extends AbstractStateMachine implements UntypedStateMachine { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/spring/BaseOrderStateMachine.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.spring; 2 | 3 | import com.lyxiang.dao.OrderDTOMapper; 4 | import org.springframework.context.ApplicationContext; 5 | 6 | /** 7 | * @author: liyuxiang 8 | * @create: 2019-01-30 9 | */ 10 | public abstract class BaseOrderStateMachine extends AbstractUntypedStateMachine { 11 | 12 | protected OrderDTOMapper orderDTOMapper; 13 | 14 | public BaseOrderStateMachine(ApplicationContext applicationContext) { 15 | this.orderDTOMapper = applicationContext.getBean(OrderDTOMapper.class); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/spring/OrderStateMachineEngineFactory.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.spring; 2 | 3 | import com.lyxiang.common.OrderContext; 4 | import com.lyxiang.common.OrderEvent; 5 | import com.lyxiang.common.OrderState; 6 | import org.springframework.beans.BeansException; 7 | import org.springframework.context.ApplicationContext; 8 | import org.springframework.context.ApplicationContextAware; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * @author: liyuxiang 15 | * @create: 2019-01-21 16 | */ 17 | @Service 18 | public class OrderStateMachineEngineFactory implements ApplicationContextAware { 19 | 20 | private ApplicationContext applicationContext; 21 | 22 | @Override 23 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 24 | this.applicationContext = applicationContext; 25 | } 26 | 27 | public void fire(OrderContext orderContext, OrderEvent orderEvent) { 28 | Map orderStatusMachineEngineMap = applicationContext.getBeansOfType(AbstractOrderStatusMachineEngine.class); 29 | boolean accept = false; 30 | for (AbstractOrderStatusMachineEngine orderStatusMachineEngine : orderStatusMachineEngineMap.values()) { 31 | if (orderStatusMachineEngine.accept(OrderState.getState(orderContext.orderDTO.getState()))) { 32 | accept = true; 33 | orderStatusMachineEngine.fire(orderEvent, orderContext); 34 | } 35 | } 36 | if (!accept) { 37 | throw new RuntimeException("执行失败"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/spring/SubmitOrderStateMachine.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.spring; 2 | 3 | import com.lyxiang.common.OrderContext; 4 | import com.lyxiang.pojo.OrderDTO; 5 | import com.lyxiang.common.OrderEvent; 6 | import com.lyxiang.common.OrderState; 7 | import org.springframework.context.ApplicationContext; 8 | import org.squirrelframework.foundation.fsm.annotation.State; 9 | import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters; 10 | import org.squirrelframework.foundation.fsm.annotation.States; 11 | import org.squirrelframework.foundation.fsm.annotation.Transit; 12 | import org.squirrelframework.foundation.fsm.annotation.Transitions; 13 | 14 | /** 15 | * @author: liyuxiang 16 | * @create: 2019-01-22 17 | */ 18 | @States({ 19 | @State(name = "INIT", entryCallMethod = "entryStateInit", exitCallMethod = "exitStateInit", initialState = true), 20 | @State(name = "WAIT_PAY", entryCallMethod = "entryStateWaitPay", exitCallMethod = "exitStateWaitPay"), 21 | @State(name = "WAIT_SEND", entryCallMethod = "entryStateWaitSend", exitCallMethod = "exitStateWaitSend"), 22 | @State(name = "PART_SEND", entryCallMethod = "entryStatePartSend", exitCallMethod = "exitStatePartSend"), 23 | @State(name = "WAIT_RECEIVE", entryCallMethod = "entryStateWaitReceive", exitCallMethod = "exitStateWaitReceive"), 24 | @State(name = "COMPLETE", entryCallMethod = "entryStateComplete", exitCallMethod = "exitStateComplete") 25 | }) 26 | @Transitions({ 27 | @Transit(from = "INIT", to = "WAIT_PAY", on = "SUBMIT_ORDER", callMethod = "submitOrder"), 28 | @Transit(from = "WAIT_PAY", to = "WAIT_SEND", on = "PAY", callMethod = "pay"), 29 | @Transit(from = "WAIT_SEND", to = "PART_SEND", on = "PART_SEND", callMethod = "partSend"), 30 | @Transit(from = "PART_SEND", to = "WAIT_RECEIVE", on = "SEND", callMethod = "send"), 31 | @Transit(from = "WAIT_RECEIVE", to = "COMPLETE", on = "COMPLETE", callMethod = "complete") 32 | }) 33 | @StateMachineParameters(stateType = OrderState.class, eventType = OrderEvent.class, contextType = OrderContext.class) 34 | public class SubmitOrderStateMachine extends BaseOrderStateMachine { 35 | 36 | public SubmitOrderStateMachine(ApplicationContext applicationContext) { 37 | super(applicationContext); 38 | } 39 | 40 | @Override 41 | protected void afterTransitionCompleted(Object fromState, Object toState, Object event, Object context) { 42 | if (fromState instanceof OrderState && toState instanceof OrderState) { 43 | OrderContext orderContext = (OrderContext) context; 44 | OrderDTO orderDTO = orderContext.orderDTO; 45 | orderDTO.setState(((OrderState) toState).name()); 46 | orderDTOMapper.insert(orderDTO); 47 | } 48 | } 49 | 50 | public void submitOrder(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 51 | System.out.println("pay"); 52 | } 53 | 54 | public void pay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 55 | System.out.println("pay"); 56 | } 57 | 58 | public void partSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 59 | System.out.println("partSend"); 60 | } 61 | 62 | public void send(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 63 | System.out.println("send"); 64 | } 65 | 66 | public void complete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 67 | System.out.println("complete"); 68 | } 69 | 70 | public void entryStateInit(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 71 | System.out.println("entryStateInit"); 72 | } 73 | 74 | public void exitStateInit(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 75 | System.out.println("exitStateInit"); 76 | } 77 | 78 | public void entryStateWaitPay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 79 | System.out.println("entryStateWaitPay"); 80 | } 81 | 82 | public void exitStateWaitPay(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 83 | System.out.println("exitStateWaitPay"); 84 | } 85 | 86 | public void entryStateWaitSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 87 | System.out.println("entryStateWaitSend"); 88 | } 89 | 90 | public void exitStateWaitSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 91 | System.out.println("exitStateWaitSend"); 92 | } 93 | 94 | public void entryStatePartSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 95 | System.out.println("entryStatePartSend"); 96 | } 97 | 98 | public void exitStatePartSend(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 99 | System.out.println("exitStatePartSend"); 100 | } 101 | 102 | public void entryStateWaitReceive(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 103 | System.out.println("entryStateWaitReceive"); 104 | } 105 | 106 | public void exitStateWaitReceive(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 107 | System.out.println("exitStateWaitReceive"); 108 | } 109 | 110 | public void entryStateComplete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 111 | System.out.println("entryStateComplete"); 112 | } 113 | 114 | public void exitStateComplete(OrderState fromState, OrderState toState, OrderEvent orderEvent, OrderContext orderContext) { 115 | System.out.println("exitStateComplete"); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/lyxiang/spring/SubmitOrderStateMachineEngine.java: -------------------------------------------------------------------------------- 1 | package com.lyxiang.spring; 2 | 3 | import com.lyxiang.common.OrderState; 4 | import org.springframework.stereotype.Service; 5 | 6 | /** 7 | * @author: liyuxiang 8 | * @create: 2019-01-22 9 | */ 10 | @Service 11 | public class SubmitOrderStateMachineEngine extends AbstractOrderStatusMachineEngine { 12 | 13 | @Override 14 | protected boolean accept(OrderState orderState) { 15 | return OrderState.INIT == orderState; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8090 2 | 3 | spring.datasource.username=root 4 | spring.datasource.password=root 5 | spring.datasource.driver-class-name= com.mysql.jdbc.Driver 6 | spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8 7 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 8 | 9 | spring.datasource.initialSize=5 10 | spring.datasource.minIdle=5 11 | spring.datasource.maxActive=20 12 | # 配置获取连接等待超时的时间 13 | spring.datasource.maxWait=60000 14 | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 15 | spring.datasource.timeBetweenEvictionRunsMillis=60000 16 | # 配置一个连接在池中最小生存的时间,单位是毫秒 17 | spring.datasource.minEvictableIdleTimeMillis=300000 18 | spring.datasource.validationQuery=SELECT 1 FROM DUAL 19 | spring.datasource.testWhileIdle=true 20 | spring.datasource.testOnBorrow=false 21 | spring.datasource.testOnReturn=false 22 | # 打开PSCache,并且指定每个连接上PSCache的大小 23 | spring.datasource.poolPreparedStatements=true 24 | spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 25 | 26 | #配置mybatis 27 | mybatis.type-aliases-package=com.base 28 | mybatis.mapper-locations=classpath:mapper/*.xml 29 | logging.level.com.ddl.mapper=debug -------------------------------------------------------------------------------- /src/main/resources/mapper/OrderDTOMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | id, state 12 | 13 | 14 | insert into sals_order(id, state) 15 | values(#{id, jdbcType=INTEGER}, #{state, jdbcType=VARCHAR}) 16 | 17 | 18 | update sals_order 19 | 20 | 21 | state = #{state} 22 | 23 | 24 | where id = #{id} 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/sql/order.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `sals_order` ( 2 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 | `state` varchar(50) DEFAULT NULL, 4 | `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 5 | `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 | PRIMARY KEY (`id`) 7 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4; --------------------------------------------------------------------------------