国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

基于 Spring 狀態機實現電商訂單狀態流轉管理

開發 前端
傳統的if-else分支判斷在狀態較多、轉移邏輯復雜時會變得難以維護,而Spring狀態機結合狀態模式可以很好地解決這個問題,讓狀態轉移邏輯更加清晰、可擴展。

引言

在電商系統中,訂單狀態的流轉是核心業務流程之一。從用戶下單、支付、商家發貨到用戶收貨、售后等環節,每個環節對應不同的訂單狀態,且狀態之間的轉移需要滿足嚴格的業務規則。

傳統的if-else分支判斷在狀態較多、轉移邏輯復雜時會變得難以維護,而Spring狀態機結合狀態模式可以很好地解決這個問題,讓狀態轉移邏輯更加清晰、可擴展。

實現

圖片圖片


圖片圖片

案例代碼

訂單狀態枚舉

定義訂單的所有狀態,每個狀態對應業務中的一個環節:

@WithStateMachine
public enum OrderStatus {
    WAIT_PAY("待支付"),
    WAIT_DELIVER("待發貨"),
    WAIT_RECEIVE("待收貨"),
    COMPLETED("已完成"),
    CLOSED("已關閉"),
    AFTER_SALE("售后中");

    @Getter
    private final String desc;

    OrderStatus(String desc) {
        this.desc = desc;
    }
}

訂單事件枚舉

事件是觸發狀態轉移的動作,每個事件對應一次狀態變更的觸發條件:

public enum OrderEvent {
    PAY_SUCCESS("支付成功"),
    DELIVER("倉庫發貨"),
    RECEIVE("確認收貨"),
    CANCEL("用戶取消/超時"),
    APPLY_REFUND("審核退款"),
    APPLY_AFTER_SALE("申請售后");

    @Getter
    private final String desc;

    OrderEvent(String desc) {
        this.desc = desc;
    }
}

狀態機配置

配置狀態機的狀態、事件、轉移邏輯及監聽器:

@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderEvent> {

    /**
     * 配置狀態機的“狀態集合”和“初始狀態”
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvent> states) throws Exception {
        states.withStates()
                .initial(OrderStatus.WAIT_PAY) // 初始狀態為“待支付”
                .states(EnumSet.allOf(OrderStatus.class)); // 注冊所有狀態
    }

    /**
     * 配置狀態機的“轉移規則”(事件觸發狀態變更)
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) throws Exception {
        transitions
                // 待支付 → 待發貨:支付成功
                .withExternal()
                .source(OrderStatus.WAIT_PAY).target(OrderStatus.WAIT_DELIVER)
                .event(OrderEvent.PAY_SUCCESS)
                .and()
                // 待支付 → 已關閉:用戶取消/超時
                .withExternal()
                .source(OrderStatus.WAIT_PAY).target(OrderStatus.CLOSED)
                .event(OrderEvent.CANCEL)
                .and()
                // 待發貨 → 待收貨:倉庫發貨
                .withExternal()
                .source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE)
                .event(OrderEvent.DELIVER)
                .and()
                // 待發貨 → 已關閉:審核退款
                .withExternal()
                .source(OrderStatus.WAIT_DELIVER).target(OrderStatus.CLOSED)
                .event(OrderEvent.APPLY_REFUND)
                .and()
                // 待收貨 → 已完成:確認收貨
                .withExternal()
                .source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.COMPLETED)
                .event(OrderEvent.RECEIVE)
                .and()
                // 已完成 → 售后中:申請售后
                .withExternal()
                .source(OrderStatus.COMPLETED).target(OrderStatus.AFTER_SALE)
                .event(OrderEvent.APPLY_AFTER_SALE);
    }

    /**
     * 配置狀態機的“全局配置”(如監聽器)
     */
    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderEvent> config) throws Exception {
        config.withConfiguration()
                .listener(new OrderStateMachineListener()); // 注冊狀態變更監聽器
    }
}
@Slf4j
@Component
public class OrderStateMachineListener extends StateMachineListenerAdapter<OrderStatus, OrderEvent> {

    @Override
    public void stateChanged(State<OrderStatus, OrderEvent> from, State<OrderStatus, OrderEvent> to) {
        if (from != null) {
            log.info("訂單狀態從: " + from.getId().getDesc() + " 變更為: " + to.getId().getDesc());
        } else {
            log.info("訂單初始狀態: " + to.getId().getDesc());
        }
    }
}

業務邏輯層實現

封裝狀態機觸發邏輯與數據庫操作,保證事務一致性:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private StateMachine<OrderStatus, OrderEvent> stateMachine;

    @Autowired
    private StateMachinePersister<OrderStatus, OrderEvent, Order> stateMachineMemPersister;

    /**
     * 創建訂單(初始狀態為待支付)
     */
    @Transactional
    public Order createOrder(Order order) {
        order.setStatus(OrderStatus.WAIT_PAY);
        orderMapper.insert(order);
        return order;
    }

    /**
     * 觸發狀態事件,更新訂單狀態
     */
    @Transactional
    public boolean triggerEvent(Long orderId, OrderEvent event) {
        // 查詢訂單
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new RuntimeException("訂單不存在:" + orderId);
        }
        boolean result = false;
        try {
            // 從訂單中恢復狀態機當前狀態
            stateMachineMemPersister.restore(stateMachine, order);
            // 發送事件觸發狀態變更
            Message<OrderEvent> message = MessageBuilder.withPayload(event)
                    .setHeader("orderId", orderId)
                    .build();
            result = stateMachine.sendEvent(message);
            // 狀態轉移成功,更新數據庫中的訂單狀態
            if (result) {
                // 持久化狀態機最新狀態
                stateMachineMemPersister.persist(stateMachine, order);
                // 更新訂單實體狀態
                order.setStatus(stateMachine.getState().getId());
                orderMapper.updateById(order);
            }
        } catch (Exception e) {
            throw new RuntimeException("狀態變更失敗:" + e.getMessage(), e);
        }
        return result;
    }

    /**
     * 查詢訂單(用于測試)
     */
    public Order getOrder(Long orderId) {
        return orderMapper.selectById(orderId);
    }

}
接口層實現

對外暴露HTTP接口,用于創建訂單和觸發狀態事件:

@CrossOrigin
@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private OrderService orderService;

    /**
     * 創建訂單
     */
    @PostMapping("/create")
    public Order createOrder(
            @RequestParam String userId,
            @RequestParam String productId,
            @RequestParam BigDecimal amount) {
        Order order = new Order();
        order.setId(userId);
        order.setProductName(productId);
        order.setAmount(amount);
        order.setStatus(OrderStatus.WAIT_PAY);
        return orderService.createOrder(order);
    }

    /**
     * 觸發訂單狀態事件
     */
    @PostMapping("/event/{orderId}/{event}")
    public boolean triggerEvent(
            @PathVariable Long orderId,
            @PathVariable String event) {
        OrderEvent orderEvent = OrderEvent.valueOf(event);
        return orderService.triggerEvent(orderId, orderEvent);
    }

    @GetMapping("/{orderId}")
    public Order getOrder(@PathVariable Long orderId) {
        Order order = orderService.getOrder(orderId);
        if (order == null) {
            throw new RuntimeException("訂單不存在");
        }
        return order;
    }
}

持久化(可選)

@Slf4j
@Configuration
public class StateMachinePersistConfig {

    /**
     * 內存持久化(基于HashMap)
     * 適合單體應用,服務重啟后狀態會丟失
     */
    @Bean(name = "stateMachineMemPersister")
    public StateMachinePersister<OrderStatus, OrderEvent, Order> stateMachineMemPersister() {
        // 實現StateMachinePersist接口,定義狀態讀寫邏輯
        StateMachinePersist<OrderStatus, OrderEvent, Order> persist = new StateMachinePersist<OrderStatus, OrderEvent, Order>() {
            // 用HashMap存儲訂單ID與狀態機上下文的映射
            private final Map<String, StateMachineContext<OrderStatus, OrderEvent>> stateMap = new HashMap<>();

            @Override
            public void write(StateMachineContext<OrderStatus, OrderEvent> context, Order order) throws Exception {
                log.info("內存持久化狀態機 - 寫入,訂單ID: {}, 狀態上下文: {}", order.getId(), JSON.toJSONString(context));
                stateMap.put(order.getId(), context);
            }

            @Override
            public StateMachineContext<OrderStatus, OrderEvent> read(Order order) throws Exception {
                StateMachineContext<OrderStatus, OrderEvent> context = stateMap.get(order.getId());
                log.info("內存持久化狀態機 - 讀取,訂單ID: {}, 狀態上下文: {}", order.getId(), JSON.toJSONString(context));
                return context;
            }
        };

        // 使用Spring提供的DefaultStateMachinePersister包裝
        return new DefaultStateMachinePersister<>(persist);
    }
}

Redis持久化配置案例:

@Configuration
public class StateMachinePersistConfig {

    /**
     * Redis持久化(分布式系統適用)
     * 狀態機上下文存儲在Redis中,支持多實例共享狀態
     */
    @Bean(name = "stateMachineRedisPersister")
    public StateMachinePersister<OrderStatus, OrderEvent, Long> stateMachineRedisPersister(
            RedisConnectionFactory redisConnectionFactory) {
        // 創建Redis狀態機上下文倉庫
        RedisStateMachineContextRepository<OrderStatus, OrderEvent> repository = 
                new RedisStateMachineContextRepository<>(redisConnectionFactory);
        
        // 基于倉庫實現持久化邏輯
        RepositoryStateMachinePersist<OrderStatus, OrderEvent, Long> persist = 
                new RepositoryStateMachinePersist<>(repository);
        
        // 包裝為RedisStateMachinePersister
        return new RedisStateMachinePersister<>(persist);
    }
}
注意事項
  • 狀態機上下文結構:Spring State MachineStateMachineContext包含當前狀態、歷史狀態、擴展變量等信息,持久化時會完整存儲這些內容,確保狀態恢復的準確性。
  • Redis鍵設計:Redis持久化默認鍵格式為STATE_MACHINE_CONTEXT:{orderId},可通過自定義RedisStateMachineContextRepository修改鍵前綴,避免與其他業務鍵沖突。
  • 過期策略:對于Redis持久化,可設置鍵過期時間(如訂單完成后24小時),避免無效數據占用內存。
  • 分布式鎖:在Redis持久化的分布式場景中,建議為triggerEvent方法添加分布式鎖(如 Redisson),防止并發狀態修改導致的數據不一致。
責任編輯:武曉燕 來源: 一安未來
相關推薦

2025-04-14 09:30:11

Spring狀態機訂單

2023-03-06 07:35:30

狀態機工具訂單狀態

2025-07-29 09:36:13

2024-10-10 17:46:06

2011-06-24 16:09:24

Qt 動畫 狀態機

2021-04-29 09:31:05

前端開發技術

2010-06-18 12:38:38

UML狀態機視圖

2024-04-16 09:21:59

Spring流轉狀態數據狀態處理

2020-12-02 13:33:58

函數指針編程語言

2020-10-15 10:38:35

C語言狀態模型

2013-09-03 09:57:43

JavaScript有限狀態機

2010-06-18 13:25:44

UML狀態機視圖

2021-07-08 09:15:20

單片機編程狀態機編程語言

2020-03-27 10:50:29

DSL 狀態機工具

2025-09-26 04:11:00

Spring狀態機業務流程

2024-01-08 09:46:47

2010-07-08 13:03:31

UML狀態機圖

2011-06-29 18:36:59

Qt 動畫 狀態機

2023-08-07 18:45:30

電商訂單訂單類型批量發貨

2010-07-12 15:00:56

UML狀態機視圖
點贊
收藏

51CTO技術棧公眾號

亚洲欧美电影一区二区| 亚洲欧美日韩精品久久奇米色影视 | 成人免费在线电影| 国产一区视频导航| 成人免费xxxxx在线观看| 成人涩涩视频| 欧美性色aⅴ视频一区日韩精品| 久久久久久久激情| 老鸭窝一区二区久久精品| 亚洲一区二区在线| 欧美jizz19性欧美| 亚洲欧美日韩国产中文专区| 国产三级视频在线播放线观看| 91天堂素人约啪| 日韩中文一区| 一区二区蜜桃| 日本欧美中文字幕| 日韩美女在线| 日韩av在线网址| 婷婷免费在线视频| 疯狂欧美牲乱大交777| 亚洲激情在线观看视频| 狠狠色丁香婷婷综合| 国产亚洲福利社区| 色综合久久一区二区三区| 欧美激情乱人伦一区| 写真福利精品福利在线观看| 日韩免费成人网| 粗大黑人巨茎大战欧美成人| 欧美日韩免费一区二区三区视频 | 亚洲人成电影在线| 污视频在线免费观看网站| 欧洲精品一区二区三区在线观看| www.男人的天堂.com| 国产日韩精品一区二区浪潮av| 亚洲熟妇无码av在线播放| 激情久久五月天| 免费观看中文字幕| 国产一级精品在线| 狠狠精品干练久久久无码中文字幕| 视频一区二区三区中文字幕| 免费国产一区二区| 亚洲欧洲另类| 区一区二区三区中文字幕| 日韩在线一区二区| 精品一区二区三区毛片| 国产成人8x视频一区二区| 日韩 欧美 视频| 久久嫩草精品久久久久| 激情视频免费网站| 亚洲免费在线播放| 人成在线免费视频| 欧美日韩国产免费| 99在线视频影院| www.xxxx精品| 红杏视频成人| 国产精自产拍久久久久久| 欧美一区网站| 日韩区国产区| 99精品久久只有精品| 成人性做爰aaa片免费看不忠| 国产精品免费丝袜| 尤物免费看在线视频| 在线成人av网站| 国模套图日韩精品一区二区| 欧美麻豆久久久久久中文 | 黄色日韩网站| 欧美日韩成人在线观看| 国产99精品一区| 国产在线精品二区| 国产毛片精品视频| 一区二区三区韩国| 欧美中文字幕不卡| 欧美三区四区| 日本高清不卡的在线| 欧美日韩国产综合网| 人人妻人人澡人人爽精品欧美一区| 国产成人综合在线观看| 亚洲四虎av| 欧美日韩国产一级| 欧美艳星kaydenkross| 68精品久久久久久欧美| 亚洲天堂久久| 欧洲黄色一级视频| 色综合天天性综合| 久久久人成影片一区二区三区在哪下载| 91sa在线看| 麻豆9191精品国产| 99热手机在线| 欧美日韩午夜影院| 视频成人永久免费视频| 成人综合色站| 久久精品日产第一区二区三区高清版 | 韩国理伦片一区二区三区在线播放| 丁香啪啪综合成人亚洲| 欧美亚洲高清一区| 久久国产精品美女| 久久久久久高清| 97久久超碰国产精品电影| 同心难改在线观看| 日韩中文字幕精品| 欧美国产精品| 熟女少妇精品一区二区| 日韩视频在线永久播放| 欧美人妖在线观看| 在线观看亚洲视频啊啊啊啊| 亚洲一区免费观看| 日韩精品一页| 欧美一级日本a级v片| 亚洲女厕所小便bbb| 超碰高清在线| 999视频在线免费观看| 久久精品视频在线看| 黄色羞羞视频在线观看| 国产精品久久久久av| 91在线视频18| 懂色av一区| 成人做爰66片免费看网站| 国产精品污污网站在线观看| 国产区美女在线| 国产精品xxx在线观看www| 最近中文字幕一区二区三区| 免费污视频在线一区| 精品日韩欧美| 午夜精品一区二区三区免费视频| 91在线亚洲| 日韩中文字幕一区| 欧美性20hd另类| 欧美极品中文字幕| 日本中文字幕高清| 伊人亚洲福利一区二区三区| 日韩影院精彩在线| 在线视频91p| 99国产精品久久久久老师| 亚洲色欲色欲www在线观看| 激情久久99| 成人区一区二区| 日韩电影免费观看中文字幕| 久久午夜精品| 国产在线观看av| 国产欧美日韩一区二区三区| 色婷婷av一区二区三区软件| 日韩一区二区在线免费| 国产网红在线| 欧美专区第一页| 亚洲视频中文字幕| 国产乱人伦丫前精品视频| 欧美a在线视频| 日韩在线观看免费av| 成人va在线观看| 中文另类视频| 我的公把我弄高潮了视频| 亚洲片国产一区一级在线观看| 秋霞成人午夜伦在线观看| 欧美野外wwwxxx| 午夜视频久久久| 日韩精品欧美国产精品忘忧草| 蜜桃一区二区三区在线| 福利在线导航136| 国产卡一卡二在线| 夜夜躁日日躁狠狠久久88av| 成人黄色av网站在线| 亚洲伦理网站| 97在线免费公开视频| 久久99热精品| 亚洲摸摸操操av| 五月激情综合| av资源网站在线观看| 久久精品中文字幕一区二区三区| 欧美中文字幕一区二区三区| 亚洲一区不卡| 高潮在线视频| 成人黄色片视频| 国产z一区二区三区| 激情av一区二区| 一本一道久久综合狠狠老精东影业| 日韩成人影视| 一区二区三区四区国产| 在线播放日韩av| 中文字幕精品—区二区四季| 欧美日韩有码| 免费a级在线播放| 手机看片日韩国产| 欧美另类极品videosbest最新版本| 亚洲视频一区二区免费在线观看| 亚洲91精品| 欧美gv在线观看| 18成人免费观看视频漫画| 亚洲自拍偷拍第一页| 欧美精品一区二区三区蜜桃| a在线播放不卡| 国产午夜一区| 成人综合影院| 国产经典久久久| 2019亚洲日韩新视频| 日本韩国一区二区三区| 日本强好片久久久久久aaa| 高清不卡一区| 三级无遮挡在线观看| 老司机午夜网站|