当前位置: 首页 > news >正文

车辆订单状态管理的优化方案:状态机设计模式

1、背景描述

        在一家小型主机厂,我们正规划开发监控系统、配套 APP 及订单管理系统。鉴于公司对业务发展有较高期许,还计划搭建自主电商平台。近期需优先完成订单功能开发,而订单业务天然适合采用状态机模式实现。

        在技术选型上,我们评估了三种方案:自主开发状态机、采用 ColaMachine 框架,以及使用 Spring StateMachine。考虑到项目时间紧张,且现有技术栈基于 Spring 生态,最终决定采用 Spring StateMachine 来实现订单功能,力求通过优化设计确保逻辑清晰、状态流转路径明确。

2、代码实现

2.1 配置项

@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStateEnum, OrderStatusConversionEvent> {/** 配置状态* @param states* @throws Exception**/public void configure(StateMachineStateConfigurer<OrderStateEnum, OrderStatusConversionEvent> states) throws Exception {states.withStates().initial(OrderStateEnum.AWAITING_PAYMENT).states(EnumSet.allOf(OrderStateEnum.class));}/*** 配置状态转换事件关系* @param transitions* @throws Exception**/public void configure(StateMachineTransitionConfigurer<OrderStateEnum, OrderStatusConversionEvent> transitions) throws Exception {transitions//订单支付成功事件:待支付-》支付完成.withExternal().source(OrderStateEnum.AWAITING_PAYMENT).target(OrderStateEnum.PAYMENT_COMPLETED).event(OrderStatusConversionEvent.PAYED).and()//订单支付失败事件:待支付-》已取消.withExternal().source(OrderStateEnum.AWAITING_PAYMENT).target(OrderStateEnum.CANCELLED).event(OrderStatusConversionEvent.CANCEL).and()//开始生产事件:支付完成-》生产中.withExternal().source(OrderStateEnum.PAYMENT_COMPLETED).target(OrderStateEnum.PRODUCING).event(OrderStatusConversionEvent.PRODUCTION_START).and()//生产完成事件:生产中-》生产完成.withExternal().source(OrderStateEnum.PRODUCING).target(OrderStateEnum.PRODUCTION_COMPLETED).event(OrderStatusConversionEvent.PRODUCTION_END).and()//发货事件:生产中-》发货中.withExternal().source(OrderStateEnum.PRODUCTION_COMPLETED).target(OrderStateEnum.IN_TRANSIT).event(OrderStatusConversionEvent.DELIVERY).and()//完成事件:发货中-》已完成.withExternal().source(OrderStateEnum.IN_TRANSIT).target(OrderStateEnum.COMPLETED).event(OrderStatusConversionEvent.DELIVERY_END).and()//申请退款事件:支付完成-》申请退款.withExternal().source(OrderStateEnum.PAYMENT_COMPLETED).target(OrderStateEnum.REFUND_PENDING).event(OrderStatusConversionEvent.REFUND).and()//同意退款事件:申请退款-》退款中.withExternal().source(OrderStateEnum.REFUND_PENDING).target(OrderStateEnum.REFUND_IN_PROGRESS).event(OrderStatusConversionEvent.REFUND_OK).and()//退款完成:退款中-》退款完成.withExternal().source(OrderStateEnum.REFUND_IN_PROGRESS).target(OrderStateEnum.REFUNDED).event(OrderStatusConversionEvent.REFUND_COMPLETE);}
}
@Configuration
@Slf4j
public class OrderMachinePersist<E, S> {/*** 创建基于内存Map的状态机持久化器(适用于单机环境)** @return StateMachinePersister 状态机持久化实例*/@Bean(name = "stateMachineMemPersister")public static StateMachinePersister getPersister() {return new DefaultStateMachinePersister(new StateMachinePersist() {// 使用HashMap存储状态机上下文private Map<Object, StateMachineContext> map = new HashMap<Object, StateMachineContext>();/*** 持久化状态机上下文到内存Map* @param context 状态机上下文* @param contextObj 业务上下文对象(如订单ID)*/@Overridepublic void write(StateMachineContext context, Object contextObj) throws Exception {log.info("持久化状态机, context:{}, contextObj:{}",JSON.toJSONString(context),JSON.toJSONString(contextObj));map.put(contextObj, context);}/*** 从内存Map恢复状态机上下文* @param contextObj 业务上下文对象(如订单ID)* @return 状态机上下文*/@Overridepublic StateMachineContext read(Object contextObj) throws Exception {log.info("获取状态机, contextObj:{}", JSON.toJSONString(contextObj));StateMachineContext stateMachineContext = map.get(contextObj);log.info("获取状态机结果, stateMachineContext:{}",JSON.toJSONString(stateMachineContext));return stateMachineContext;}});}
}

2.2 事件状态枚举项

/*** 订单状态枚举*/
@Getter
@AllArgsConstructor
public enum OrderStateEnum {/*** 待付款*/AWAITING_PAYMENT(1, "待付款"),/*** 已支付*/PAYMENT_COMPLETED(2, "已支付"),/*** 生产中*/PRODUCING(3, "生产中"),/*** 生产完成*/PRODUCTION_COMPLETED(4, "生产完成"),/*** 运输中*/IN_TRANSIT(5, "运输中"),/*** 已完成*/COMPLETED(6, "已完成"),/*** 申请退款*/REFUND_PENDING(7, "申请退款"),/*** 退款中*/REFUND_IN_PROGRESS(8, "退款中"),/*** 退款完成*/REFUNDED(9, "退款完成"),/*** 已取消*/CANCELLED(10, "已取消"),;final Integer status;final String describe;public static OrderStateEnum fromStatus(Integer status) {return Arrays.stream(OrderStateEnum.values()).filter(e -> e.getStatus().equals(status)).findFirst().orElseThrow(() -> new IllegalArgumentException("Unknown order status: " + status));}}
public enum OrderStatusConversionEvent {// 支付PAYED,// 开始生产PRODUCTION_START,// 生产完成PRODUCTION_END,// 开始发货DELIVERY,// 运输完成DELIVERY_END,//退款REFUND,//同意退款REFUND_OK,//同意拒绝REFUND_REJECTED,//退款完成REFUND_COMPLETE,//取消CANCEL;
}

2.3 处理项

@Component("orderStateListener")
@WithStateMachine(name = "orderStateMachine")
@Slf4j
public class OrderStateListener{@Autowiredprivate OrderService orderService;/*** 支付完成-已支付*/@OnTransition(source = "AWAITING_PAYMENT", target = "PAYMENT_COMPLETED")@EventListenerResult(key = payTransition)public void payTransition(Message<OrderStatusConversionEvent> message) {OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("支付,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.PAYMENT_COMPLETED.getStatus()).build());}/*** 生产中*/@OnTransition(source = "PAYMENT_COMPLETED", target = "PRODUCING")@EventListenerResult(key = OrderConstants.producingTransition)public void  producingTransition(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("生产中,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.PRODUCING.getStatus()).build());}/*** 生产完成*/@OnTransition(source = "PRODUCING", target = "PRODUCTION_COMPLETED")@EventListenerResult(key = OrderConstants.productionCompleted)public void  productionCompleted(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("生产完成,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.PRODUCTION_COMPLETED.getStatus()).build());}/*** 运输中*/@OnTransition(source = "PRODUCTION_COMPLETED", target = "IN_TRANSIT")@EventListenerResult(key = OrderConstants.inTransit)public void  inTransit(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("运输中,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.IN_TRANSIT.getStatus()).build());}/*** 已完成*/@OnTransition(source = "IN_TRANSIT", target = "COMPLETED")@EventListenerResult(key = OrderConstants.completed)public void  completed(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("已完成,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.COMPLETED.getStatus()).build());}/*** 申请退款*/@OnTransition(source = "WAIT_PAYMENT", target = "REFUND_PENDING")@EventListenerResult(key = OrderConstants.refundPending)public void  refundPending(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("申请退款,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.REFUND_PENDING.getStatus()).build());}/*** 退款中*/@OnTransition(source = "REFUND_PENDING", target = "REFUND_IN_PROGRESS")@EventListenerResult(key = OrderConstants.refundInProgress)public void  refundInProgress(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("退款中,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.REFUND_IN_PROGRESS.getStatus()).build());}/*** 退款完成*/@OnTransition(source = "REFUND_IN_PROGRESS", target = "REFUNDED")@EventListenerResult(key = OrderConstants.refunded)public void  refunded(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("退款完成,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.REFUNDED.getStatus()).build());}/*** 已取消*/@OnTransition(source = "AWAITING_PAYMENT", target = "CANCELLED")@EventListenerResult(key = OrderConstants.cancelled)public void  cancelled(Message<OrderStatusConversionEvent> message){OrderDO order = (OrderDO) message.getHeaders().get("order");log.info("已取消,状态机反馈信息:{}",  message.getHeaders().toString());// 调用订单服务 修改订单信息orderService.updateByDTO(OrderDTO.builder().id(order.getId()).status(OrderStateEnum.CANCELLED.getStatus()).build());}
}
@Service("OrderStatusChangeService")
@AllArgsConstructor
public class OrderStatusChangeServiceImpl implements OrderStateService {private static final Logger log = LoggerFactory.getLogger(OrderStatusChangeServiceImpl.class);@Autowiredprivate OrderService orderService;@Autowiredprivate OrderPaymentService orderPaymentService;@Resourceprivate StateMachine<OrderStateEnum, OrderStatusConversionEvent> orderStateMachine;@Resourceprivate StateMachinePersister<OrderStateEnum, OrderStatusConversionEvent, String> stateMachineMemPersister;@Overridepublic boolean paymentCompleted(Long orderId, String number, BigDecimal amount) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.PAYED, orderDO, OrderConstants.payTransition)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean producing(Long orderId) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.PRODUCTION_START, orderDO, OrderConstants.producingTransition)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean productionCompleted(Long orderId) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.PRODUCTION_END, orderDO, OrderConstants.productionCompleted)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean inTransit(Long orderId, String waybillNo) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.DELIVERY, orderDO, OrderConstants.inTransit)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean completed(Long orderId) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.DELIVERY_END, orderDO, OrderConstants.completed)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean refundPending(Long orderId) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.REFUND, orderDO, OrderConstants.refundPending)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean refundInProgress(Long orderId) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.REFUND_OK, orderDO, OrderConstants.refundInProgress)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean refunded(String number, BigDecimal amount) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetByNumber(number);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderDO.getId());if (!sendEvent(OrderStatusConversionEvent.REFUND_COMPLETE, orderDO, OrderConstants.refunded)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic boolean cancelled(Long orderId) {// 通过订单编号 获取订单idOrderDO orderDO = orderService.tryGetById(orderId);log.info("线程名称:{},,订单号:{}" ,Thread.currentThread().getName() , orderId);if (!sendEvent(OrderStatusConversionEvent.CANCEL, orderDO, OrderConstants.cancelled)) {log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), orderDO);return false;}return true;}@Overridepublic OrderStateEnum getStateEnum() {return null;}/*** 发送订单状态转换事件(持久化到内存)* synchronized修饰保证这个方法是线程安全的* @param changeEvent* @param order* @return**/private synchronized boolean sendEvent(OrderStatusConversionEvent changeEvent, OrderDO order,String key) {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);if(!result){return false;}//获取到监听的结果信息Integer o = (Integer) orderStateMachine.getExtendedState().getVariables().get(key  + order.getId());//操作完成之后,删除本次对应的key信息orderStateMachine.getExtendedState().getVariables().remove(key +order.getId());//如果事务执行成功,则持久化状态机if(Objects.equals(1,Integer.valueOf(o))){//持久化状态机状态stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId()));}else {//订单执行业务异常return false;}} catch (Exception e) {log.error("订单操作失败:{}", e);} finally {orderStateMachine.stop();}return result;}
}

2.4 针对异常的捕获

@Component
@Aspect
@Slf4j
public class EventListenerResultAspect {@Resourceprivate StateMachine<OrderStateEnum, OrderStatusConversionEvent> orderStateMachine;@Around("@annotation(cn.bool.tsp.cloud.mall.modular.order.listener.annotation.EventListenerResult)")public Object logResultAround(ProceedingJoinPoint pjp) throws Throwable {//获取参数Object[] args = pjp.getArgs();log.info("参数args:{}", args);Message message = (Message) args[0];OrderDO order = (OrderDO) message.getHeaders().get("order");//获取方法Method method = ((MethodSignature) pjp.getSignature()).getMethod();// 获取DemoEventListenerResult注解EventListenerResult eventListenerResult = method.getAnnotation(EventListenerResult.class);String key = eventListenerResult.key();Object returnVal = null;try {//执行方法log.info("执行代理方法");returnVal = pjp.proceed();//如果业务执行正常,则保存信息//成功 则为1log.info("代理方法执行完毕。保存ExtendedState状态为正常。");orderStateMachine.getExtendedState().getVariables().put(key + order.getId(), 1);} catch (Throwable e) {log.error("e:{}", e.getMessage());//如果业务执行异常,则保存信息//将异常信息变量信息中,失败则为0orderStateMachine.getExtendedState().getVariables().put(key + order.getId(), 0);throw e;}return returnVal;}
}

http://www.dtcms.com/a/341113.html

相关文章:

  • 从ioutil到os:Golang在线客服聊天系统文件读取的迁移实践
  • 从零开发Java坦克大战Ⅱ(上) -- 从单机到联机(架构演进与设计模式剖析)
  • 音频大模型学习笔记
  • CS+ for CC编译超慢的问题该如何解决
  • 0-1 背包问题(模板)
  • 汽车ECU实现数据安全存储(机密性保护)的一种方案
  • Ubuntu apt安装nginx
  • 使用Spring Retry组件优雅地实现重试
  • Java 定时任务 - 从基础到高阶使用 - 从 Timer 到 Quart
  • 数据结构 二叉树 二叉树链式结构的实现
  • 数据分析师常用命令
  • 数据结构中的列表:深度解析数组与链表的实现与抉择
  • PyTorch API 3 - distributed
  • 前后端联合实现文件上传,实现 SQL Server image 类型文件上传
  • 51单片机-驱动LED点阵模块教程
  • SQL-leetcode—3374. 首字母大写 II
  • Docker--安装MySQL、Redis
  • 面试常考的 SQL 窗口函数汇总
  • 【Tech Arch】Apache Pig大数据处理的高效利器
  • 深入理解数据结构:从数组、链表到B树家族
  • 数据结构:利用旋转在AVL树中维持平衡(Inserting in AVL with Rotation)
  • FastAPI初学
  • PyTorch API 1
  • 新能源知识库(81)新能源半实物仿真平台介绍
  • C/C++ Linux系统编程:详解常见的系统调用函数,文件I/O核心:open, close, read, write
  • 【C++】基础:C++11-14-17常用新特性介绍
  • 计算机网络技术-局域网配置(Day.4)
  • 微信小程序授权登录+JWT
  • shell间接引用
  • CVE-2018-12613 漏洞复现