Java搭建订单状态机模型

本文介绍了如何使用Spring State Machine构建一个订单状态机,详细展示了从订单创建到完成的各个状态流转,包括状态枚举、事件定义、状态机配置、持久化处理、业务类和服务类的实现。状态机监听器处理状态转换逻辑,确保订单状态按照预设路径正确流转。此外,还提供了测试用例来验证状态机的功能。

订单状态机

前言

在电商平台中,订单的状态是十分复杂的,并且订单状态的流转也是极其复杂并且十分严格的。
因此,我们需要定义订单状态的流转模型,并定义订单状态机模型。
我们只需对订单进行相应的状态设置即可,订单状态机内部去触发订单状态流转事件,从而进行相关的状态设置。
如果订单状态不符合(例:待付款->已发货),那么订单状态机内部判断订单前置状态不符合,不能触发相关的流转事件,从而抛出异常,设置订单状态失败。
下边是一个订单状态机的模型,此订单状态稍微有点复杂,不过也涵盖了所有的问题情况。

1 订单状态流程的构建

在这里插入图片描述

2 订单状态机源码

2.1 引入相关依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>5.3.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>2.0.1.RELEASE</version>
</dependency>=

2.2 定义状态机枚举类

package com.wazk.statusmachine.constant;

/**
 * @class: OrderStatusEnum
 * @description: TODO
 * @author: wazk
 * @version: 1.0
 * @date: 2022/4/5 5:03 下午
 */
public enum OrderStatusEnum {
   
   
    // 待支付	pay_wait 0
    // 部分支付	pay_part 5
    // 已支付	pay_over 10
    // 待发货待授权	send_wait 15
    // 部分发货		send_part 20
    // 已发货全部发货	send_over 25
    // 已完成(全部收到货)finished 30 25
    // 已发起售后申请 aftermarket_apply 35
    // 部分退款	refund_part 40 15
    // 已关闭	closed 100

    PAY_WAIT(0, "PAY_WAIT"),
    PAY_PART(5, "PAY_PART"),
    PAY_OVER(10, "PAY_OVER"),
    SEND_WAIT(15, "SEND_WAIT"),
    SEND_PART(20, "SEND_PART"),
    SEND_OVER(25, "SEND_OVER"),
    FINISHED(30, "FINISHED"),
    AFTERMARKET_APPLY(35, "AFTERMARKET_APPLY"),
    REFUND_PART(40, "REFUND_PART"),
    CLOSED(100, "CLOSED"),
    ;


    private Integer code;
    private String type;

    public Integer getCode(){
   
   
        return this.code;
    }
    public String getType(){
   
   
        return this.type;
    }

    OrderStatusEnum(Integer code, String type) {
   
   
        this.code = code;
        this.type = type;
    }

    public static OrderStatusEnum getByCode(Integer code){
   
   
        for (OrderStatusEnum saleOrderStatusEnum : values()) {
   
   
            if (saleOrderStatusEnum.getCode().equals(code)) {
   
   
                return saleOrderStatusEnum;
            }
        }
        return null;
    }

}

2.3 定义状态机流转事件

package com.wazk.statusmachine.machine;

/**
 * @class: OrderStatusChangeEvent
 * @description: TODO
 * @author: wazk
 * @version: 1.0
 * @date: 2022/4/5 5:07 下午
 */
public enum OrderStatusChangeEvent {
   
   

//    待付款 -> 部分支付 部分支付事件
    PAY_WAIT_TO_PAY_PART_EVENT,
//    待付款 -> 已支付(待成团) 全部支付,待成团
    PAY_WAIT_TO_PAY_OVER_EVENT,
//    待付款 -> 待发货(待授权) 实体全部付款待发货,虚拟全部付款待授权
    PAY_WAIT_TO_SEND_WAIT_EVENT,
//    待付款 -> 已完成(全部收货) 不需要发货
    PAY_WAIT_TO_FINISHED_EVENT,
//    待付款 -> 已关闭 订单取消
    PAY_WAIT_TO_CLOSED_EVENT,

//    部分支付 -> 已支付(待成团) 拼团订单支付剩下的一部分
    PAY_PART_TO_PAY_OVER_EVENT,
//    部分支付 -> 待发货(待授权) 订单支付剩下的一部分
    PAY_PART_TO_SEND_WAIT_EVENT,
//    部分支付 -> 已完成(全部收货) 不需要发货订单支付剩下的一部分
    PAY_PART_TO_FINISHED_EVENT,

//    已支付(待成团) -> 待发货(待授权) 拼团订单拼团成功
    PAY_OVER_TO_SEND_WAIT_EVENT,
//    已支付(待成团) -> 已完成(全部收货) 不需要发货的订单拼团成功
    PAY_OVER_TO_FINISHED_EVENT,
//    已支付(待成团) -> 发起售后申请 拼团订单未拼成功发起售后申请
    PAY_OVER_TO_AFTERMARKET_APPLY_EVENT,

//    待发货(待授权) -> 部分发货
    SEND_WAIT_TO_SEND_PART_EVENT,
//    待发货(待授权) -> 已发货(全部发货)
    SEND_WAIT_TO_SEND_OVER_EVENT,
//    待发货(待授权) -> 发起售后申请
    SEND_WAIT_TO_AFTERMARKET_APPLY_EVENT,

//    部分发货 -> 已发货(全部发货)
    SEND_PART_TO_SEND_OVER_EVENT,
//    部分发货 -> 发起售后申请
    SEND_PART_TO_AFTERMARKET_APPLY_EVENT,

//    已发货(全部发货) -> 已完成(全部收货)
    SEND_OVER_TO_FINISHED_EVENT,
//    已发货(全部发货) -> 发起售后申请
    SEND_OVER_TO_AFTERMARKET_APPLY_EVENT,

//    已完成(全部收货) -> 发起售后申请
    FINISHED_TO_AFTERMARKET_APPLY_EVENT,

//    发起售后申请 -> 部分退款
    AFTERMARKET_APPLY_TO_REFUND_PART_EVENT,
//    发起售后申请 -> 已关闭
    AFTERMARKET_APPLY_TO_CLOSED_EVENT,

//    部分退款 -> 已关闭
    REFUND_PART_TO_CLOSED_EVENT,
//    部分退款 -> 发起售后申请 再次发起售后申请
    REFUND_PART_TO_AFTERMARKET_APPLY_EVENT,

    ;

}

2.4 定义状态机配置类

package com.wazk.statusmachine.machine;

import com.wazk.statusmachine.constant.OrderStatusEnum;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;

import java.util.EnumSet;

/**
 * @class: OrderStatusMachineConfig
 * @description: TODO
 * @author: wazk
 * @version: 1.0
 * @date: 2022/4/5 5:09 下午
 */
@Configuration
@EnableStateMachine(name = "orderStatusMachine")
public class OrderStatusMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEvent> {
   
   

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


    /**
     * 配置状态转换事件关系
     * @param orderStatusMachineConfig:
     * @throws Exception:
     */
    public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusChangeEvent> orderStatusMachineConfig) throws Exception {
   
   
        orderStatusMachineConfig
//            待付款 -> 部分支付 部分支付事件
                .withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.PAY_PART).event(OrderStatusChangeEvent.PAY_WAIT_TO_PAY_PART_EVENT)
                .and()
//            待付款 -> 已支付(待成团) 全部支付,待成团
                .withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.PAY_OVER).event(OrderStatusChangeEvent.PAY_WAIT_TO_PAY_OVER_EVENT)
                .and()
//            待付款 -> 待发货(待授权) 实体全部付款待发货,虚拟全部付款待授权
                .withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.SEND_WAIT).event(OrderStatusChangeEvent.PAY_WAIT_TO_SEND_WAIT_EVENT)
                .and()
//            待付款 -> 已完成(全部收货) 不需要发货
                .withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.FINISHED).event(OrderStatusChangeEvent.PAY_WAIT_TO_FINISHED_EVENT)
                .and()
//            待付款 -> 已关闭 订单取消
                .withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.CLOSED).event(OrderStatusChangeEvent.PAY_WAIT_TO_CLOSED_EVENT)
                .and()

//            部分支付 -> 已支付(待成团) 拼团订单支付剩下的一部分
                .withExternal().source(OrderStatusEnum.PAY_PART).target(OrderStatusEnum.PAY_OVER).event(OrderStatusChangeEvent.PAY_PART_TO_PAY_OVER_EVENT)
                .and()
//            部分支付 -> 待发货(待授权) 订单支付剩下的一部分
                .withExternal().source(OrderStatusEnum.PAY_PART).target(OrderStatusEnum.SEND_WAIT).event(OrderStatusChangeEvent.PAY_PART_TO_SEND_WAIT_EVENT)
                .and()
//            部分支付 -> 已完成(全部收货) 不需要发货订单支付剩下的一部分
                .withExternal().source(OrderStatusEnum.PAY_PART).target(OrderStatusEnum.FINISHED).event(OrderStatusChangeEvent.PAY_PART_TO_FINISHED_EVENT)
                .and()

//            已支付(待成团) -> 待发货(待授权) 拼团订单拼团成功
                .withExternal().source(OrderStatusEnum.PAY_OVER).target(OrderStatusEnum.SEND_WAIT).event(OrderStatusChangeEvent.PAY_OVER_TO_SEND_WAIT_EVENT)
                .and()
//            已支付(待成团) -> 已完成(全部收货) 不需要发货的订单拼团成功
                .withExternal().source(OrderStatusEnum.PAY_OVER).target(OrderStatusEnum.FINISHED).event(OrderStatusChangeEvent.PAY_OVER_TO_FINISHED_EVENT)
                .and()
//            已支付(待成团) -> 发起售后申请 拼团订单未拼成功发起售后申请
                .withExternal().source(OrderStatusEnum.PAY_OVER).target(OrderStatusEnum.AFTERMARKET_APPLY).event(OrderStatusChangeEvent.PAY_OVER_TO_AFTERMARKET_APPLY_EVENT)
                .and()

//            待发货(待授权) -> 部分发货
                .withExternal()
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

难过的风景

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值