偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

基于 Spring 狀態(tài)機實現(xiàn)電商訂單狀態(tài)流轉(zhuǎn)管理

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

引言

在電商系統(tǒng)中,訂單狀態(tài)的流轉(zhuǎn)是核心業(yè)務(wù)流程之一。從用戶下單、支付、商家發(fā)貨到用戶收貨、售后等環(huán)節(jié),每個環(huán)節(jié)對應(yīng)不同的訂單狀態(tài),且狀態(tài)之間的轉(zhuǎn)移需要滿足嚴格的業(yè)務(wù)規(guī)則。

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

實現(xiàn)

圖片圖片


圖片圖片

案例代碼

訂單狀態(tài)枚舉

定義訂單的所有狀態(tài),每個狀態(tài)對應(yīng)業(yè)務(wù)中的一個環(huán)節(jié):

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

    @Getter
    private final String desc;

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

訂單事件枚舉

事件是觸發(fā)狀態(tài)轉(zhuǎn)移的動作,每個事件對應(yīng)一次狀態(tài)變更的觸發(fā)條件:

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

    @Getter
    private final String desc;

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

狀態(tài)機配置

配置狀態(tài)機的狀態(tài)、事件、轉(zhuǎn)移邏輯及監(jiān)聽器:

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

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

    /**
     * 配置狀態(tài)機的“轉(zhuǎn)移規(guī)則”(事件觸發(fā)狀態(tài)變更)
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) throws Exception {
        transitions
                // 待支付 → 待發(fā)貨:支付成功
                .withExternal()
                .source(OrderStatus.WAIT_PAY).target(OrderStatus.WAIT_DELIVER)
                .event(OrderEvent.PAY_SUCCESS)
                .and()
                // 待支付 → 已關(guān)閉:用戶取消/超時
                .withExternal()
                .source(OrderStatus.WAIT_PAY).target(OrderStatus.CLOSED)
                .event(OrderEvent.CANCEL)
                .and()
                // 待發(fā)貨 → 待收貨:倉庫發(fā)貨
                .withExternal()
                .source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE)
                .event(OrderEvent.DELIVER)
                .and()
                // 待發(fā)貨 → 已關(guān)閉:審核退款
                .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);
    }

    /**
     * 配置狀態(tài)機的“全局配置”(如監(jiān)聽器)
     */
    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderEvent> config) throws Exception {
        config.withConfiguration()
                .listener(new OrderStateMachineListener()); // 注冊狀態(tài)變更監(jiān)聽器
    }
}
@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("訂單狀態(tài)從: " + from.getId().getDesc() + " 變更為: " + to.getId().getDesc());
        } else {
            log.info("訂單初始狀態(tài): " + to.getId().getDesc());
        }
    }
}

業(yè)務(wù)邏輯層實現(xiàn)

封裝狀態(tài)機觸發(fā)邏輯與數(shù)據(jù)庫操作,保證事務(wù)一致性:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private StateMachine<OrderStatus, OrderEvent> stateMachine;

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

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

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

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

}
接口層實現(xiàn)

對外暴露HTTP接口,用于創(chuàng)建訂單和觸發(fā)狀態(tài)事件:

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

    @Resource
    private OrderService orderService;

    /**
     * 創(chuàng)建訂單
     */
    @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);
    }

    /**
     * 觸發(fā)訂單狀態(tài)事件
     */
    @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 {

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

            @Override
            public void write(StateMachineContext<OrderStatus, OrderEvent> context, Order order) throws Exception {
                log.info("內(nèi)存持久化狀態(tài)機 - 寫入,訂單ID: {}, 狀態(tài)上下文: {}", 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("內(nèi)存持久化狀態(tài)機 - 讀取,訂單ID: {}, 狀態(tài)上下文: {}", order.getId(), JSON.toJSONString(context));
                return context;
            }
        };

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

Redis持久化配置案例:

@Configuration
public class StateMachinePersistConfig {

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

2025-04-14 09:30:11

Spring狀態(tài)機訂單

2023-03-06 07:35:30

狀態(tài)機工具訂單狀態(tài)

2025-07-29 09:36:13

2024-10-10 17:46:06

2011-06-24 16:09:24

Qt 動畫 狀態(tài)機

2021-04-29 09:31:05

前端開發(fā)技術(shù)

2010-06-18 12:38:38

UML狀態(tài)機視圖

2024-04-16 09:21:59

Spring流轉(zhuǎn)狀態(tài)數(shù)據(jù)狀態(tài)處理

2020-10-15 10:38:35

C語言狀態(tài)模型

2010-06-18 13:25:44

UML狀態(tài)機視圖

2013-09-03 09:57:43

JavaScript有限狀態(tài)機

2020-12-02 13:33:58

函數(shù)指針編程語言

2020-03-27 10:50:29

DSL 狀態(tài)機工具

2025-09-26 04:11:00

Spring狀態(tài)機業(yè)務(wù)流程

2021-07-08 09:15:20

單片機編程狀態(tài)機編程語言

2024-01-08 09:46:47

2010-07-08 13:03:31

UML狀態(tài)機圖

2011-06-29 18:36:59

Qt 動畫 狀態(tài)機

2023-08-07 18:45:30

電商訂單訂單類型批量發(fā)貨

2010-07-12 15:00:56

UML狀態(tài)機視圖
點贊
收藏

51CTO技術(shù)棧公眾號