首页 > 其他分享 >Spring状态机

Spring状态机

时间:2023-12-14 11:12:01浏览次数:30  
标签:return OrderInfo Spring 状态机 OrderStatus WAIT order orderStatus

1.依赖

<!--状态机-->
<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>2.0.1.RELEASE</version>
</dependency>

2.状态枚举类

public enum OrderStatus {
    //
    DELETE(0,"逻辑删除"),
    WAIT_PAYMENT(1,"待支付"),
    WAIT_TAKING(2,"待接单"),
    WAIT_DELIVER(3,"待发货"),
    WAIT_RECEIVE(4,"待收货"),
    FINISH(5,"订单结束"),
    CONSUMER_CANCEL(6,"消费者取消"),
    SHOP_CANCEL(7,"商家取消"),
    REFUND(8,"退款");

    private Integer value;
    private String name;

    OrderStatus(Integer value, String name) {
        this.value = value;
        this.name = name;
    }
    public Integer getValue(){
        return value;
    }

    public String getName(){
        return name;
    }

    /**
     * 根据value获得对应Enum对象
     * @param key
     * @return
     */
    public static OrderStatus getByKey(Integer key) {
        for (OrderStatus e : values()) {
            if (e.getValue().equals(key)) {
                return e;
            }
        }
        throw new RuntimeException("enum not exists.");
    }
}

3.状态事件枚举类

public enum OrderStatusChangeEvent {
    //支付,商家接单,骑手配送,确认收货
    PAYED,TAKING,DELIVERY, RECEIVED,CANCEL,UNTAKING,REFUND;
}

4.状态机配置

/**
 * 订单状态机配置
 */
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> {

    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderStatusChangeEvent> config) throws Exception {
        config.withConfiguration()
                .autoStartup(true)
                .listener(listener());
    }

    @Bean
    public StateMachineListener<OrderStatus, OrderStatusChangeEvent> listener() {
        return new StateMachineListenerAdapter<>() {
            @Override
            public void stateChanged(State<OrderStatus, OrderStatusChangeEvent> from, State<OrderStatus, OrderStatusChangeEvent> to) {
                System.out.println("State change to " + to.getId());
            }
        };
    }

    /**
     * 配置状态
     * @param states
     * @throws Exception
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception {
        states
                .withStates()
                .initial(OrderStatus.WAIT_PAYMENT)
                .states(EnumSet.allOf(OrderStatus.class));
    }

    /**
     * 配置状态转换事件关系
     * @param transitions
     * @throws Exception
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception {
        transitions
                .withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_TAKING)
                .event(OrderStatusChangeEvent.PAYED)
                .and()
                .withExternal().source(OrderStatus.WAIT_TAKING).target(OrderStatus.WAIT_DELIVER)
                .event(OrderStatusChangeEvent.TAKING)
                .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)
                // 消费者取消
                .source(OrderStatus.WAIT_PAYMENT)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                .and().withExternal()
                .source(OrderStatus.WAIT_TAKING)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                .and().withExternal()
                .source(OrderStatus.WAIT_DELIVER)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                .and().withExternal()
                .source(OrderStatus.WAIT_RECEIVE)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                // 商家取消
                .and().withExternal()
                .source(OrderStatus.WAIT_TAKING)
                .target(OrderStatus.SHOP_CANCEL)
                .event(OrderStatusChangeEvent.UNTAKING)
                // 消费者退款
                .and().withExternal()
                .source(OrderStatus.FINISH)
                .target(OrderStatus.REFUND)
                .event(OrderStatusChangeEvent.REFUND);
    }

    /**
     * 持久化配置
     * 在实际使用中,可以配合Redis等进行持久化操作
     * @return
     */
    @Bean
    public DefaultStateMachinePersister persister(){
        return new DefaultStateMachinePersister<>(new StateMachinePersist<Object, Object, OrderInfo>() {

            @Override
            public void write(StateMachineContext<Object, Object> context, OrderInfo order) throws Exception {
                //此处并没有进行持久化操作
            }

            @Override
            public StateMachineContext<Object, Object> read(OrderInfo order) throws Exception {
                //此处直接获取Order中的状态,其实并没有进行持久化读取操作,通过这一步获取状态
                return new DefaultStateMachineContext<>(OrderStatus.getByKey(order.getStatus()), null, null, null);
            }
        });
    }
}

5.状态转变监听类

@Component("orderStateListener")
@WithStateMachine(name = "orderStateMachine")
@Slf4j
public class OrderStateListenerImpl{
    /**
     * 订单基本信息数据库操作
     */
    @Autowired
    private OrderInfoMapper orderInfoMapper;

    /**
     * 订单状态数据库操作
     */
    @Autowired
    private OrderStatusMapper orderStatusMapper;

    /**
     * 支付
     * @param message
     * @return
     */
    @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_TAKING")
    public boolean payTransition(Message<OrderStatusChangeEvent> message) {
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.WAIT_TAKING.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.WAIT_TAKING.getValue());
            orderStatus.setName("消费者支付");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 商家接单
     * @param message
     * @return
     */
    @OnTransition(source = "WAIT_TAKING", target = "WAIT_DELIVER")
    public boolean takingTransition(Message<OrderStatusChangeEvent> message) {
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 分配给附近骑手
            order.setRiderId("1");
            // 修改状态
            order.setStatus(OrderStatus.WAIT_DELIVER.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.WAIT_DELIVER.getValue());
            orderStatus.setName("商家接单");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")
    public boolean deliverTransition(Message<OrderStatusChangeEvent> message) {
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态

            order.setStatus(OrderStatus.WAIT_RECEIVE.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.WAIT_RECEIVE.getValue());
            orderStatus.setName("骑手配送");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "WAIT_RECEIVE", target = "FINISH")
    public boolean receiveTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.FINISH.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.FINISH.getValue());
            orderStatus.setName("消费者收货");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "WAIT_TAKING", target = "SHOP_CANCEL")
    public boolean untakingTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.SHOP_CANCEL.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.SHOP_CANCEL.getValue());
            orderStatus.setName("商家拒绝接单");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = {"WAIT_PAYMENT","WAIT_TAKING","WAIT_DELIVER","WAIT_RECEIVE"},target = "CONSUMER_CANCEL")
    public boolean cancelTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.CONSUMER_CANCEL.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.CONSUMER_CANCEL.getValue());
            orderStatus.setName("消费者取消订单");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "FINISH",target = "REFUND")
    public boolean refundTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.REFUND.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.REFUND.getValue());
            orderStatus.setName("消费者退款");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

6.service类

public interface OrderStateService {

    //发起支付
    Boolean pay(OrderInfo orderInfo);

    Boolean taking(OrderInfo orderInfo) throws Exception;

    //订单发货
    Boolean deliver(OrderInfo orderInfo);

    //订单收货
    Boolean receive(OrderInfo orderInfo);
    Boolean orderUntaking(OrderInfo orderInfo);
    Boolean orderCancel(OrderInfo orderInfo);
    Boolean orderRefund(OrderInfo orderInfo);
    
}

7.serviceImpl类

@Service
public class OrderStateServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderStateService {

    @Resource
    private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine;

    @Autowired
    private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, OrderInfo> persister;

    /**
     * 发送订单支付事件
     */
    @Override
    public Boolean pay(OrderInfo orderInfo) {
        // 获得订单信息
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试支付,订单号:" + orderInfo.getId());
        // 发送支付事件
        Boolean result = sendEvent(OrderStatusChangeEvent.PAYED, orderInfo);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + orderInfo.getId());
        }
        return result;
    }

    /**
     * 商家接单
     * @param order
     * @return
     */
    @Override
    public Boolean taking(OrderInfo order) throws Exception {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试商家接单,订单号:" + order.getId());
        // 发送接单事件
        Boolean result = sendEvent(OrderStatusChangeEvent.TAKING, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    /**
     * 骑手配送
     * @param order
     * @return
     */
    @Override
    public Boolean deliver(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试发货,订单号:" + order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.DELIVERY, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean receive(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.RECEIVED, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean orderUntaking(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.UNTAKING, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean orderCancel(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.CANCEL, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean orderRefund(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.REFUND, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    /**
     * 发送订单状态转换事件
     *
     * @param event
     * @param order
     * @return
     */
    private synchronized boolean sendEvent(OrderStatusChangeEvent event, OrderInfo order) {
        boolean result = false;
        Message<OrderStatusChangeEvent>  message = MessageBuilder.withPayload(event).
                setHeader("order", order).build();
        try {
            orderStateMachine.start();
//            //尝试恢复状态机状态
            persister.restore(orderStateMachine, order);
            //添加延迟用于线程安全测试
//            Thread.sleep(1000);
            result = orderStateMachine.sendEvent(message);
            //持久化状态机状态
            persister.persist(orderStateMachine, order);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            orderStateMachine.stop();
        }
        return result;
    }
}

标签:return,OrderInfo,Spring,状态机,OrderStatus,WAIT,order,orderStatus
From: https://www.cnblogs.com/lwx11111/p/17900765.html

相关文章

  • SpringBoot接收日期参数异常
    一、关于接收前端传递的日期参数的问题:前提:Date类型的属性上添加了以下注解:@JsonFormat(timezone="GMT+8",pattern="yyyy-MM-dd")@DateTimeFormat(pattern="yyyy-MM-dd")@JSONField(format="yyyy-MM-dd")1、java.sql.date:空字符串解析报错,正常日期格式字符串没问......
  • SpringBoot中@Transactional失效场景
    一、背景:1、需求  定时器需要定时到“消息通知表”中获取“消息反馈表”中不存在的数据,遍历这些数据,并对每一条数据发起流程,不管发起成功与否都需要往消息反馈表中插入一条该数据的发起结果,若发起成功还需要往“核查案件表”中插入一条该案件的主表数据2、问题:  发现在发......
  • 国产化软件新浪潮: spring 改造替代...
    中午看了篇《国产化软件新浪潮:jdkredismysqltomcatnginx改造替代品及信创名录》想给它补充个spring改造替代:)七、Spring替代品-Solon生态1、Java新的生态级框架从零开始构建,有自己的标准规范与开放生态(历时五年,具备全球第二级别的生态规模)。与其他框架相比,解决了两......
  • springboot虚拟线程(jdk21,springboot3.2.0)
    1.什么是虚拟线程虚拟线程是JDK21版本正式发布的一个新特性。虚拟线程和平台线程主要区别在于,虚拟线程在运行周期内不依赖操作系统线程:它们与硬件脱钩,因此被称为“虚拟”。这种解耦是由JVM提供的抽象层赋予的。虚拟线程的运行成本远低于平台线程。它们消耗的内存要少得多。这就......
  • 【SpringBootWeb入门-12】MySQL-DDL-图形化工具
    1、章节前言上一篇文章我们讲解了MySQL的安装与配置,以及相关sql命令的执行操作,在演示这些sql语句的时候,我们都是在命令行当中进行操作的,在命令行当中敲写语句很不方便,主要原因有以下几点:无提示:命令行当中输入任何sql语句没有任何提示,全凭记忆,而且很容易敲错代码;操作繁琐:全部的......
  • SpringSecurity
    SpringSecurity1简介SpringSecurity是Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。一般来说中大型的项目都是使用SpringSecurity来做安全框架。小项目有Shiro的比较多,因为相比与SpringSecurity,Shiro的上手更......
  • springboot004旅游路线规划系统(Java毕业设计,附数据库和源码)
    第一章绪论1.1选题背景与研究意义随着社会的不断进步,在居民生活水平提高的同时,人们当前在生活的方方面面也越来越注重服务所带来的体验,随着近几年国家政策大力发展旅游业,旅游景点的建设越来也完善,旅游业的发展速度得到了显著的提升。各大旅行社、旅游景点都不断的推出新的活动计......
  • SpringCloud Seata 启动闪退
    SpringCloudSeata启动闪退查看报错--->虚拟机启动失败原因定位【JDK14丢弃了cms垃圾回收器,修改相应的GC参数即可】果报jvm启动失败,是因为启动参数的垃圾回收参数不对,应该是在jdk14之后,已经丢弃了cms垃圾回收器,所以修改相应的垃圾回收器参数即可。%JAVACMD%%JAVA_OP......
  • springboot下文件上传。
    1.本地上传到E盘下的image目录@Slf4j@RestControllerpublicclassUploadController{@PostMapping("/upload")publicResultupload(MultipartFileimage)throwsIOException{log.info("文件上传:{}",image);StringoriginalFilenam......
  • Spring Boot应用启动 java -jar
    1.系统参数的标准格式为:-Dargname=argvalue,多个参数之间用空格隔开,如果参数值中间有空格,则用引号括起来#1.基本java-jarrun.jar#2.指定java路径nohup/opt/mdw/jdk1.8.0_241/bin/java-jarrun.jar#3.如果中文乱码,指定jar包的运行环境的编码java-Dfile.encoding=utf-8-......