Spring状态机
if-else实现状态机
public class BasketballMusicSateMachineUsingIfElse{private boolean isPlayingMusic;public BasketballMusicSateMachineUsingIfElse(){this.isPlayMusic = false;//初始状态为音乐未播放}public void playMusic(){if(!isPlayingMusic){System.out.println("Music starts playing...");ifPlayingMusic = true;}}public void stopMusic(){if(isPlayingMusic){System.out.println("Music stops playing...");isPlayingMusic = false;}} public void performActivity(String activity){if ("basketball".equals(activity)) {System.out.println("Music~");playMusic(); // 打篮球时播放音乐} else if ("sing_rap".equals(activity)) {System.out.println("哎哟你干嘛!");stopMusic(); // 唱跳Rap时停止音乐} else {System.out.println("Invalid activity!");}}public static void main(String[] args) {BasketballMusicStateMachineUsingIfElse stateMachine = new BasketballMusicStateMachineUsingIfElse();// 测试状态机stateMachine.performActivity("basketball"); // 打篮球,音乐开始播放stateMachine.performActivity("sing_rap"); // 唱跳Rap,音乐停止播放stateMachine.performActivity("basketball"); // 再次打篮球,音乐重新开始播放}
}
和状态机的对比
①、引入依赖
spring-statemachine-core
②、定义状态、事件
public enum States {IDLE, // 空闲状态PLAYING_BB, // 打篮球状态SINGING // 唱跳Rap状态
}
public enum Event {START_BB_MUSIC, // 开始播放篮球音乐事件STOP_BB_MUSIC // 停止篮球音乐事件
}
③、配置状态机
@Configuration
@EnableStateMachine
public class BasketballMusicStateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Event> {@Autowiredprivate BasketballMusicStateMachineEventListener eventListener;@Overridepublic void configure(StateMachineConfigurationConfigurer<States, Event> config) throws Exception {config.withConfiguration().autoStartup(true).listener(eventListener); // 设置状态机事件监听器}@Overridepublic void configure(StateMachineStateConfigurer<States, Event> states) throws Exception {states.withStates().initial(States.IDLE).states(EnumSet.allOf(States.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<States, Event> transitions) throws Exception {transitions.withExternal().source(States.IDLE).target(States.PLAYING_BB).event(Event.START_BB_MUSIC).and().withExternal().source(States.PLAYING_BB).target(States.SINGING).event(Event.STOP_BB_MUSIC).and().withExternal().source(States.SINGING).target(States.PLAYING_BB).event(Event.START_BB_MUSIC);}
}
④、监听器
@Component
public class BasketballMusicStateMachineEventListener extends StateMachineListenerAdapter<States, Event> {@Overridepublic void stateChanged(State<States, Event> from, State<States, Event> to) {if (from.getId() == States.IDLE && to.getId() == States.PLAYING_BB) {System.out.println("开始打篮球,music 起");} else if (from.getId() == States.PLAYING_BB && to.getId() == States.SINGING) {System.out.println("唱跳,你干嘛");} else if (from.getId() == States.SINGING && to.getId() == States.PLAYING_BB) {System.out.println("继续打篮球,music 继续");}}
}
⑤、单元测试
@SpringBootTest
class ChatApplicationTests {@Resourceprivate StateMachine<States, Event> stateMachine;@Testvoid contextLoads() {//开始打球,music 起stateMachine.sendEvent(Event.START_BB_MUSIC);//开始唱跳,你干嘛stateMachine.sendEvent(Event.STOP_BB_MUSIC);//继续打球,music 继续stateMachine.sendEvent(Event.START_BB_MUSIC);}
}
==================================================
案例一:
①、依赖
spring-statemachine-core
②、模拟订单类
@Data
public class Order {private Long orderId;private OrderStatusEnum orderStatus;
}
//订单状态转换
public enum OrderStatusEnum {// 待支付WAIT_PAYMENT,// 待发货WAIT_DELIVER,// 待收货WAIT_RECEIVE,// 完成FINISH;
}
//订单状态
public enum OrderStatusChangeEventEnum {//支付PAYED,//发货DELIVERY,//收货RECEIVED;
}
③、构造订单状态机
@Configuration
@EnableStateMachine
public class OrderStatusMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEventEnum> {/*** 配置状态*/@Overridepublic void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum> states) throws Exception {states.withStates().initial(OrderStatusEnum.WAIT_PAYMENT).end(OrderStatusEnum.FINISH).states(EnumSet.allOf(OrderStatusEnum.class));}/*** 配置状态转换事件关系*/@Overridepublic void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum> transitions) throws Exception {transitions.withExternal().source(OrderStatusEnum.WAIT_PAYMENT).target(OrderStatusEnum.WAIT_DELIVER).event(OrderStatusChangeEventEnum.PAYED).and().withExternal().source(OrderStatusEnum.WAIT_DELIVER).target(OrderStatusEnum.WAIT_RECEIVE).event(OrderStatusChangeEventEnum.DELIVERY).and().withExternal().source(OrderStatusEnum.WAIT_RECEIVE).target(OrderStatusEnum.FINISH).event(OrderStatusChangeEventEnum.RECEIVED);}
}
④、状态机监听器
监听状态变更事件,完成状态转换
@Component
@WithStateMachine
@Transactional
public class OrderStatusListener {@OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER")public boolean payTransition(Message message) {Order order = (Order) message.getHeaders().get("order");order.setOrderStatus(OrderStatusEnum.WAIT_DELIVER);System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());return true;}@OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")public boolean deliverTransition(Message message) {Order order = (Order) message.getHeaders().get("order");order.setOrderStatus(OrderStatusEnum.WAIT_RECEIVE);System.out.println("发货,状态机反馈信息:" + message.getHeaders().toString());return true;}@OnTransition(source = "WAIT_RECEIVE", target = "FINISH")public boolean receiveTransition(Message message) {Order order = (Order) message.getHeaders().get("order");order.setOrderStatus(OrderStatusEnum.FINISH);System.out.println("收货,状态机反馈信息:" + message.getHeaders().toString());return true;}}
⑤、编写订单服务类
@Service
public class OrderServiceImpl implements OrderService {@Resourceprivate StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;private long id = 1L;private Map<Long, Order> orders = Maps.newConcurrentMap();@Overridepublic Order create() {Order order = new Order();order.setOrderStatus(OrderStatusEnum.WAIT_PAYMENT);order.setOrderId(id++);orders.put(order.getOrderId(), order);System.out.println("订单创建成功:" + order.toString());return order;}@Overridepublic Order pay(long id) {Order order = orders.get(id);System.out.println("尝试支付,订单号:" + id);Message message = MessageBuilder.withPayload(OrderStatusChangeEventEnum.PAYED).setHeader("order", order).build();if (!sendEvent(message)) {System.out.println(" 支付失败, 状态异常,订单号:" + id);}return orders.get(id);}@Overridepublic Order deliver(long id) {Order order = orders.get(id);System.out.println(" 尝试发货,订单号:" + id);if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.DELIVERY).setHeader("order", order).build())) {System.out.println(" 发货失败,状态异常,订单号:" + id);}return orders.get(id);}@Overridepublic Order receive(long id) {Order order = orders.get(id);System.out.println(" 尝试收货,订单号:" + id);if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.RECEIVED).setHeader("order", order).build())) {System.out.println(" 收货失败,状态异常,订单号:" + id);}return orders.get(id);}@Overridepublic Map<Long, Order> getOrders() {return orders;}/*** 发送状态转换事件* @param message* @return*/private synchronized boolean sendEvent(Message<OrderStatusChangeEventEnum> message) {boolean result = false;try {orderStateMachine.start();result = orderStateMachine.sendEvent(message);} catch (Exception e) {e.printStackTrace();} finally {if (Objects.nonNull(message)) {Order order = (Order) message.getHeaders().get("order");if (Objects.nonNull(order) && Objects.equals(order.getOrderStatus(), OrderStatusEnum.FINISH)) {orderStateMachine.stop();}}}return result;}
}
⑥、测试入口
@RestController
public class OrderController {@Resourceprivate OrderService orderService;@RequestMapping("/testOrderStatusChange")public String testOrderStatusChange(){orderService.create();orderService.create();orderService.pay(1L);orderService.deliver(1L);orderService.receive(1L);orderService.pay(2L);orderService.deliver(2L);orderService.receive(2L);System.out.println("全部订单状态:" + orderService.getOrders());return "success";}}
拓展:
消息队列方式
订单状态的流转可以通过 MQ 发布一个事件,消费者根据业务条件把订单状态进行流转,可以根据不同的事件发送到不同的 Topic。
定时任务驱动
每隔一段时间启动一下 job,根据特定的状态从数据库中拿对应的订单记录,然后判断订单是否有条件到达下一个状态。
规则引擎方式
业务团队可以在规则引擎里编写一系列的状态及其对应的转换规则,由规则引擎根据已经加载的规则对输入数据进行解析,根据解析的结果执行相应的动作,完成状态流转。
===============================================================
案例二
①、引入依赖
spring-statemachine-starter
②、定义状态和事件
public enum OrderStates {NEW, PAID, SHIPPED, COMPLETED, CANCELLED
}public enum OrderEvents {PAY, SHIP, COMPLETE, CANCEL
}
③、配置状态机
@Configuration
@EnableStateMachine
public class StateMachineConfig extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {private static final Logger log = LoggerFactory.getLogger(StateMachineConfig.class);@Overridepublic void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config)throws Exception {config.withConfiguration().autoStartup(true).listener(listener());}@Overridepublic void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)throws Exception {states.withStates().initial(OrderStates.NEW).end(OrderStates.COMPLETED).end(OrderStates.CANCELLED).states(EnumSet.allOf(OrderStates.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {transitions.withExternal().source(OrderStates.NEW).target(OrderStates.PAID).event(OrderEvents.PAY).and().withExternal().source(OrderStates.PAID).target(OrderStates.SHIPPED).event(OrderEvents.SHIP).and().withExternal().source(OrderStates.SHIPPED).target(OrderStates.COMPLETED).event(OrderEvents.COMPLETE).and().withExternal().source(OrderStates.NEW).target(OrderStates.CANCELLED).event(OrderEvents.CANCEL).and().withExternal().source(OrderStates.PAID).target(OrderStates.CANCELLED).event(OrderEvents.CANCEL);}@Beanpublic StateMachineListener<OrderStates, OrderEvents> listener() {return new StateMachineListenerAdapter<>() {@Overridepublic void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {log.info("State change to: {}", to.getId());}@Overridepublic void stateMachineError(StateMachine<OrderStates, OrderEvents> stateMachine, Exception exception) {log.error("Exception caught: {}", exception.getMessage(), exception);}@Overridepublic void eventNotAccepted(Message<OrderEvents> message) {Order order = (Order) message.getHeaders().get("order");log.error("Order state machine can't change state {} --> {}", Objects.requireNonNull(order).getStatus(), message.getPayload());}};}@Beanpublic StateMachinePersist<OrderStates, OrderEvents, String> inMemoryStateMachinePersist() {return new StateMachinePersist<>() {private final Map<String, StateMachineContext<OrderStates, OrderEvents>> contexts = new HashMap<>();@Overridepublic void write(StateMachineContext<OrderStates, OrderEvents> context, String contextObj) {contexts.put(contextObj, context);}@Overridepublic StateMachineContext<OrderStates, OrderEvents> read(String contextObj) {return contexts.get(contextObj);}};}
}
④、配置状态改变后的处理器
使用@WithStateMachine来配置状态机流转后的后续逻辑,比如更新订单状态、发邮件等。
@Service
@WithStateMachine
public class OrderStateChangeHandler {private static final Logger log = LoggerFactory.getLogger(OrderStateChangeHandler.class);@OnTransition(source = "NEW", target = "PAID")public void payTransition(Message<OrderEvents> message) {Order order = (Order) message.getHeaders().get("order");log.info("Handle Pay Order:{}", order);// 其他业务 如保存订单状态Objects.requireNonNull(order).setStatus(OrderStates.PAID);//orderRepository.save(order);}@OnTransition(source = "PAID", target = "SHIPPED")public void shipTransition(Message<OrderEvents> message) {Order order = (Order) message.getHeaders().get("order");log.info("Handle Ship Order:{}", order);// 其他业务 如更新订单Objects.requireNonNull(order).setStatus(OrderStates.SHIPPED);
// orderMapper.updateById(order);}@OnTransition(source = "SHIPPED", target = "COMPLETED")public void completeTransition(Message<OrderEvents> message) {Order order = (Order) message.getHeaders().get("order");log.info("Handle Complete Order:{}", order);// 其他业务 如更新订单Objects.requireNonNull(order).setStatus(OrderStates.COMPLETED);
// orderMapper.updateById(order);}}
⑤、使用状态机控制订单状态流转
@Service
public class OrderService {private static final Logger log = LoggerFactory.getLogger(OrderService.class);private final StateMachine<OrderStates, OrderEvents> stateMachine;public OrderService(StateMachine<OrderStates, OrderEvents> stateMachine) {this.stateMachine = stateMachine;}public void payOrder(Integer id) {log.info("Pay Order: {}", id);Order order = new Order("12345", "Sample Order", OrderStates.NEW, new BigDecimal("99.99"));// 模拟支付
// payService.payOrder(1);Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.PAY).setHeader("order", order).build();stateMachine.sendEvent(Mono.just(message)).subscribe();}public void shipOrder(Integer id) {log.info("Ship Order: {}", id);Order order = new Order("12345", "Sample Order", OrderStates.PAID, new BigDecimal("99.99"));// 模拟发货
// tradeService.shipOrder(1);Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.SHIP).setHeader("order", order).build();stateMachine.sendEvent(Mono.just(message)).subscribe();}public void completeOrder(Integer id) {log.info("Complete Order: {}", id);Order order = new Order("12345", "Sample Order", OrderStates.SHIPPED, new BigDecimal("99.99"));Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.COMPLETE).setHeader("order", order).build();stateMachine.sendEvent(Mono.just(message)).subscribe();}}
⑥、控制订单流转
@GetMapping("/order/pay/{id}")
public String payOrder(@PathVariable("id") Integer id) {orderService.payOrder(id);return "Order paid ";
}@GetMapping("/order/ship/{id}")
public String shipOrder(@PathVariable("id") Integer id) {orderService.shipOrder(id);return "Order shipped ";
}@GetMapping("/order/complete/{id}")public String completeOrder(@PathVariable("id") Integer id) {orderService.completeOrder(id);return "Order completed ";
}
测试:
1.NEW --> SHIPPED
因为我们配置的订单流转规则中,NEW只能转换到PAID或CANCELLED,所以我们期望的是订单不能流转成功。
在浏览器中访问:http://localhost:8082/order/ship/1
控制台中打印如下错误信息,并且处理器中业务未执行,和我们的预期一致。
-
NEW --> COMPLETE
同上面一样,期望是会出现错误,不能转换成功。访问:http://localhost:8082/order/complete/1 -
NEW --> PAID
由于在状态机的配置,NEW是可以转换成PAID的。所以,期望能转换成功。访问:http://localhost:8082/order/pay/1
我们从控制台中可以看到, 订单状态流转成功,并且进入到handler中进行订单流转后的业务处理。这时该订单的状态已经变成PAID。
如果我们在来支付一次,结果会怎么样?
执行一次结果是报错,因为上一次请求,该订单的状态已经流转为了PAID,所以再次流转NEW --> PAY就会报错。
- PAID --> SHIPPED
属于配置允许的状态流转,所以期望能够转换成功。访问:http://localhost:8082/order/ship/1
从控制台中可以看到能够成功流转,因为符合我们配置的状态机流转规则。
同样如果我们再调用一次会怎么样?
和上一步的测试结果一样,因为该订单的状态已经扭转为了SHIPPED,所以它不能再次转换为SHIPPED。
- SHIPPED --> COMPLETED
我们之间访问:http://localhost:8082/order/complete/1
该订单当前状态为SHIPPED,根据配置的规则可以转换为COMPLETED
====================================================================
案例:
①、导入sql,订单表的创建
CREATE TABLE `tb_order` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`order_code` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '订单编码',`status` smallint(3) DEFAULT NULL COMMENT '订单状态',`name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '订单名称',`price` decimal(12,2) DEFAULT NULL COMMENT '价格',`delete_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '删除标记,0未删除 1已删除',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '更新时间',`create_user_code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',`update_user_code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '更新人',`version` int(11) NOT NULL DEFAULT '0' COMMENT '版本号',`remark` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单表';/*Data for the table `tb_order` */insert into `tb_order`(`id`,`order_code`,`status`,`name`,`price`,`delete_flag`,`create_time`,`update_time`,`create_user_code`,`update_user_code`,`version`,`remark`) values (2,'A111',1,'A','22.00',0,'2022-10-15 16:14:11','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),(3,'A111',1,'订单A','22.00',0,'2022-10-02 21:53:13','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),(4,'A111',1,'订单A','22.00',0,'2022-10-02 21:53:13','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),(5,'A111',1,'订单A','22.00',0,'2022-10-03 09:08:30','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL);
②、引入依赖
<!-- redis持久化状态机项目中:yml配置文件中进行Redis连接信息的配置-->
<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-redis</artifactId><version>1.2.9.RELEASE</version>
</dependency>
<!--状态机-->
<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-starter</artifactId><version>2.0.1.RELEASE</version>
</dependency>
③、定义状态机状态和事件
public enum OrderStatus {// 待支付,待发货,待收货,已完成WAIT_PAYMENT(1, "待支付"),WAIT_DELIVER(2, "待发货"),WAIT_RECEIVE(3, "待收货"),FINISH(4, "已完成");private Integer key;private String desc;OrderStatus(Integer key, String desc) {this.key = key;this.desc = desc;}public Integer getKey() {return key;}public String getDesc() {return desc;}public static OrderStatus getByKey(Integer key) {for (OrderStatus e : values()) {if (e.getKey().equals(key)) {return e;}}throw new RuntimeException("enum not exists.");}
}
public enum OrderStatusChangeEvent {// 支付,发货,确认收货PAYED, DELIVERY, RECEIVED;
}
③、定义状态机规则和配置状态机
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> {/*** 配置状态** @param states* @throws Exception*/public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception {states.withStates().initial(OrderStatus.WAIT_PAYMENT).states(EnumSet.allOf(OrderStatus.class));}/*** 配置状态转换事件关系** @param transitions* @throws Exception*/public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception {transitions//支付事件:待支付-》待发货.withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED).and()//发货事件:待发货-》待收货.withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY).and()//收货事件:待收货-》已完成.withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderStatusChangeEvent.RECEIVED);}
}
④、配置持久化
@Configuration
@Slf4j
public class Persist<E, S> {/*** 持久化到内存map中** @return*/@Bean(name = "stateMachineMemPersister")public static StateMachinePersister getPersister() {return new DefaultStateMachinePersister(new StateMachinePersist() {@Overridepublic void write(StateMachineContext context, Object contextObj) throws Exception {log.info("持久化状态机,context:{},contextObj:{}", JSON.toJSONString(context), JSON.toJSONString(contextObj));map.put(contextObj, context);}@Overridepublic StateMachineContext read(Object contextObj) throws Exception {log.info("获取状态机,contextObj:{}", JSON.toJSONString(contextObj));StateMachineContext stateMachineContext = (StateMachineContext) map.get(contextObj);log.info("获取状态机结果,stateMachineContext:{}", JSON.toJSONString(stateMachineContext));return stateMachineContext;}private Map map = new HashMap();});}@Resourceprivate RedisConnectionFactory redisConnectionFactory;/*** 持久化到redis中,在分布式系统中使用** @return*/@Bean(name = "stateMachineRedisPersister")public RedisStateMachinePersister<E, S> getRedisPersister() {RedisStateMachineContextRepository<E, S> repository = new RedisStateMachineContextRepository<>(redisConnectionFactory);RepositoryStateMachinePersist p = new RepositoryStateMachinePersist<>(repository);return new RedisStateMachinePersister<>(p);}
}
监听状态的变化:
@Component("orderStateListener")
@WithStateMachine(name = "orderStateMachine")
@Slf4j
public class OrderStateListenerImpl {@Resourceprivate OrderMapper orderMapper;@OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER")public void payTransition(Message<OrderStatusChangeEvent> message) {Order order = (Order) message.getHeaders().get("order");log.info("支付,状态机反馈信息:{}", message.getHeaders().toString());//更新订单order.setStatus(OrderStatus.WAIT_DELIVER.getKey());orderMapper.updateById(order);//TODO 其他业务}@OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")public void deliverTransition(Message<OrderStatusChangeEvent> message) {Order order = (Order) message.getHeaders().get("order");log.info("发货,状态机反馈信息:{}", message.getHeaders().toString());//更新订单order.setStatus(OrderStatus.WAIT_RECEIVE.getKey());orderMapper.updateById(order);//TODO 其他业务}@OnTransition(source = "WAIT_RECEIVE", target = "FINISH")public void receiveTransition(Message<OrderStatusChangeEvent> message) {Order order = (Order) message.getHeaders().get("order");log.info("确认收货,状态机反馈信息:{}", message.getHeaders().toString());//更新订单order.setStatus(OrderStatus.FINISH.getKey());orderMapper.updateById(order);//TODO 其他业务}
}
⑤、业务系统
@Controller
@RequestMapping
public class OrderController{@Resourceprivate OrderService.orderService;//根据id查询订单@RequestMapping("/getById")public Order getById(@RequestParam("id") Long id){Order order = orderServiceService.getById(id);return order;}//创建订单public String create(@RequestBody Order order){orderService.create(order);return "success";}//对订单进行支付@RequestMapping("/pay")public String pay(@RequestParam("id") Long id){orderService.pay(id);return "success";}//对订单进行发货@RequestMapping("/deliver")public String deliver(@RequestParam("id") Long id){orderService.deliver(id);return "success";}//对订单进行确认收货@RequestMapping("receive")public String receive(@RequestParam("id") Long id){orderService.receive(id);return "success";}
}
@Service
@Slf4j
public class OrerServiceImpl extends ServiceImpl<OrderMapper,Order> implements OrderService {@Resourceprivate StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine;@Resourceprivate StateMachinePersister<OrderStatus, OrderStatusChangeEvent, String> stateMachineMemPersister;@Resourceprivate OrderMapper orderMapper;public Order create(Order order) {order.setStatus(OrderStatus.WAIT_PAYMENT.getKey());orderMapper.insert(order);return order;}public Order pay(Long id) {Order order = orderMapper.selectById(id);log.info("线程名称:{},尝试支付,订单号:{}" ,Thread.currentThread().getName() , id);if (!sendEvent(OrderStatusChangeEvent.PAYED, order)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), order);throw new RuntimeException("支付失败, 订单状态异常");}return order;}public Order deliver(Long id) {Order order = orderMapper.selectById(id);log.info("线程名称:{},尝试发货,订单号:{}" ,Thread.currentThread().getName() , id);if (!sendEvent(OrderStatusChangeEvent.DELIVERY, order)) {log.error("线程名称:{},发货失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), order);throw new RuntimeException("发货失败, 订单状态异常");}return order;}public Order receive(Long id) {Order order = orderMapper.selectById(id);log.info("线程名称:{},尝试收货,订单号:{}" ,Thread.currentThread().getName() , id);if (!sendEvent(OrderStatusChangeEvent.RECEIVED, order)) {log.error("线程名称:{},收货失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), order);throw new RuntimeException("收货失败, 订单状态异常");}return order;}private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) {boolean result = false;try {//启动状态机orderStateMachine.start();//尝试恢复状态机状态stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId()));Message message = MessageBuilder.withPayload(changeEvent).setHeader("order", order).build();result = orderStateMachine.sendEvent(message);//持久化状态机状态stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId()));} catch (Exception e) {log.error("订单操作失败:{}", e);} finally {orderStateMachine.stop();}return result;}
}
测试:
1)验证业务
新增一个订单
http://localhost:8084/order/create
对订单进行支付
http://localhost:8084/order/pay?id=2
对订单进行发货
http://localhost:8084/order/deliver?id=2
对订单进行确认收货
http://localhost:8084/order/receive?id=2
正常流程结束。如果对一个订单进行支付了,再次进行支付,则会报错:http://localhost:8084/order/pay?id=2