jssyzr 2022-09-17 16:38 采纳率: 100%
浏览 78
已结题

spring状态机部分状态变更监听不到

做了一个报卡系统,报卡具有几个状态(编辑中, 已提交 , 已审核 , 已删除),对应几个事件(提交,审核,打回,删除),

其中事件对应状态变更
提交(编辑中 —— 已提交)
审核(已提交 —— 已审核)
打回(已提交 —— 编辑中)
删除(编辑中 —— 已删除)
该功能使用spring 状态机实现,但是测试过程中发现删除和提交可以正常使用,但是打回和审核均失败,状态变更的监听器一直未监听状态变更的消息

用代码块功能插入代码,请勿粘贴截图

--状态枚举
public enum CardStatus {
EDITED,SUBMITED,AUDITED,DELETED
}
--事件枚举
public enum CardStatusChangeEvent {
SUBMIT,REPULSE,AUDIT,DELETE
}
--状态机配置
@Configuration
@EnableStateMachine(name = "cardStatusMachine")
public class CardStatusMachineConfig extends StateMachineConfigurerAdapter<CardStatus, CardStatusChangeEvent>{

@Autowired
private ICardProcessRecService cardProcessRecService;

/**
 * 配置初始状态
 */
@Override
public void configure(StateMachineStateConfigurer<CardStatus, CardStatusChangeEvent> states) throws Exception {
    // TODO Auto-generated method stub
    states.withStates().initial(CardStatus.EDITED).states(EnumSet.allOf(CardStatus.class));    
}


/**
 * 配置转换器
 */
@Override
public void configure(StateMachineTransitionConfigurer<CardStatus, CardStatusChangeEvent> transitions)
        throws Exception {
    // TODO Auto-generated method stub

// super.configure(transitions);
transitions
.withExternal().source(CardStatus.EDITED).target(CardStatus.SUBMITED).event(CardStatusChangeEvent.SUBMIT)
.and()
.withExternal().source(CardStatus.EDITED).target(CardStatus.DELETED).event(CardStatusChangeEvent.DELETE)
.and()
.withExternal().source(CardStatus.SUBMITED).target(CardStatus.AUDITED).event(CardStatusChangeEvent.AUDIT)
.and()
.withExternal().source(CardStatus.SUBMITED).target(CardStatus.EDITED).event(CardStatusChangeEvent.REPULSE);
}

/**
 * 配置数据持久化bean
 * @return
 */
@Bean
public DefaultStateMachinePersister persister() {
    return new DefaultStateMachinePersister<>(new StateMachinePersist<Object, Object, CardProcessRec>() {

        @Override
        public StateMachineContext<Object, Object> read(CardProcessRec arg0) throws Exception {
            // TODO Auto-generated method stub
            return new DefaultStateMachineContext<Object, Object>(arg0.getCardStatus(), null, null, null);
        }

        @Override
        public void write(StateMachineContext<Object, Object> arg0, CardProcessRec arg1) throws Exception {
            // TODO Auto-generated method stub
            //持久化数据到数据库中
            cardProcessRecService.insertCardProcessRec(arg1);
        }
        
    });
}

}
--状态机监听
@Configuration
@WithStateMachine(name="cardStatusMachine")
public class CardStatusListener {

/**
 * 提交
 * @param message
 * @return
 */
@OnTransition(source = "EDITED",target = "SUBMITED")
public boolean submitTransition(Message message) {
    CardProcessRec cardProcessRec = (CardProcessRec)message.getHeaders().get("cardProcessRec");
    cardProcessRec.setCardStatus(CardStatus.SUBMITED.name());
    return true;
}

/**
 * 审核
 * @param message
 * @return
 */
@OnTransition(source = "SUBMITED",target = "AUDITED")
public boolean auditTransition(Message message) {
    CardProcessRec cardProcessRec = (CardProcessRec)message.getHeaders().get("cardProcessRec");
    cardProcessRec.setCardStatus(CardStatus.AUDITED.name());
    return true;
}

/**
 * 删除
 * @param message
 * @return
 */
@OnTransition(source = "EDITED",target = "DELETED")
public boolean deleteTransition(Message message) {
    CardProcessRec cardProcessRec = (CardProcessRec)message.getHeaders().get("cardProcessRec");
    cardProcessRec.setCardStatus(CardStatus.DELETED.name());
    return true;
}

/**
 * 打回
 * @param message
 * @return
 */
@OnTransition(source = "SUBMITED",target = "EDITED")
public boolean repulseTransition(Message message) {
    CardProcessRec cardProcessRec = (CardProcessRec)message.getHeaders().get("cardProcessRec");
    cardProcessRec.setCardStatus(CardStatus.EDITED.name());
    System.out.println("打回后状态:"+cardProcessRec.getCardStatus());
    return true;
}

}

--状态机服务调用

@RestController
@RequestMapping("")
public class CardStatusController extends BaseController{

private static final Logger log = LoggerFactory.getLogger(CardStatusController.class);

@Autowired
private StateMachine cardStatusMachine;

@Autowired
private StateMachinePersister persister;

@PreAuthorize("@ss.hasPermi('tuberculosis:cardstatus:submit')")
@Log(title = "报卡提交", businessType = BusinessType.UPDATE)
@PostMapping("/submit")
public AjaxResult submit(@RequestBody CardProcessRec cardProcessRec) {
    cardProcessRec.setEventType(CardStatusChangeEvent.SUBMIT.name());
    cardProcessRec.setCreateBy(getUsername());
    Message message = MessageBuilder.withPayload(CardStatusChangeEvent.SUBMIT)
            .setHeader("cardProcessRec", cardProcessRec).build();
    if(sendEvent(message, cardProcessRec)) {
        return AjaxResult.success(cardProcessRec);
    }else {
        return AjaxResult.error("提交失败");
    }
}

@PreAuthorize("@ss.hasPermi('tuberculosis:cardstatus:submit')")
@Log(title = "报卡删除", businessType = BusinessType.UPDATE)
@PostMapping("/delete")
public AjaxResult delete(@RequestBody CardProcessRec cardProcessRec) {
    cardProcessRec.setEventType(CardStatusChangeEvent.DELETE.name());
    cardProcessRec.setCreateBy(getUsername());
    Message message = MessageBuilder.withPayload(CardStatusChangeEvent.DELETE)
            .setHeader("cardProcessRec", cardProcessRec).build();
    if(sendEvent(message, cardProcessRec)) {
        return AjaxResult.success(cardProcessRec);
    }else {
        return AjaxResult.error("删除失败");
    }
}

@PreAuthorize("@ss.hasPermi('tuberculosis:cardstatus:repulse')")
@Log(title = "报卡打回", businessType = BusinessType.UPDATE)
@PostMapping("/repulse")
public AjaxResult repulse(@RequestBody CardProcessRec cardProcessRec) {
    cardProcessRec.setEventType(CardStatusChangeEvent.REPULSE.name());
    cardProcessRec.setCreateBy(getUsername());
    Message message = MessageBuilder.withPayload(CardStatusChangeEvent.REPULSE)
            .setHeader("cardProcessRec", cardProcessRec).build();
    if(sendEvent(message, cardProcessRec)) {
        return AjaxResult.success(cardProcessRec);
    }else {
        return AjaxResult.error("打回失败");
    }
}

@PreAuthorize("@ss.hasPermi('tuberculosis:cardstatus:audit')")
@Log(title = "报卡审核", businessType = BusinessType.UPDATE)
@PostMapping("/audit")
public AjaxResult audit(@RequestBody CardProcessRec cardProcessRec) {
    cardProcessRec.setEventType(CardStatusChangeEvent.AUDIT.name());
    cardProcessRec.setCreateBy(getUsername());
    Message message = MessageBuilder.withPayload(CardStatusChangeEvent.AUDIT)
            .setHeader("cardProcessRec", cardProcessRec).build();
    if(sendEvent(message, cardProcessRec)) {
        return AjaxResult.success(cardProcessRec);
    }else {
        return AjaxResult.error("审核失败");
    }
}


/**
 * 发送报卡状态变更消息
 * @param message
 * @param card
 * @return
 */
private synchronized boolean sendEvent(Message message,CardProcessRec card) {
    boolean result = false;
    try {
        cardStatusMachine.start();
        persister.restore(cardStatusMachine, card);
        log.info("id=" + card.getCardId() + " 状态机 orderStateMachine id=" + card.getCardStatus());

        result = cardStatusMachine.sendEvent(message);
        if(result) {
            persister.persist(cardStatusMachine, card);
        } else {
            log.info("状态变更失败");
        }
        
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    } finally {
        cardStatusMachine.stop();
    }
    return result;
}

}

运行结果及报错内容

调用打回(/repulse)服务后返回失败

16:31:02.897 [http-nio-8080-exec-1] INFO o.a.c.c.C.[/] - [log,173] - Initializing Spring DispatcherServlet 'dispatcherServlet'
16:31:02.983 [http-nio-8080-exec-1] INFO c.r.t.c.CardStatusController - [sendEvent,106] - id=1 状态机 orderStateMachine id=SUBMITED
16:31:02.984 [http-nio-8080-exec-1] INFO c.r.t.c.CardStatusController - [sendEvent,112] - 状态变更失败

我的解答思路和尝试过的方法

尝试将状态机配置中初始态改为提交(SUBMITED)测试,结果打回和审核可以,但是删除和提交又失败了,所以怀疑是不是需要将过程中所有状态都作为初始态设置一遍才行,但是感觉这样有点傻,所以觉得不太可能

我想要达到的结果

修复bug

  • 写回答

2条回答 默认 最新

  • jssyzr 2022-09-18 16:53
    关注

    已解决
    new DefaultStateMachineContext<Object, Object>(arg0.getCardStatus(), null, null, null) 在重置当前状态时,此处的传参不可以是字符串,需要使用枚举变量,改为
    new DefaultStateMachineContext<Object, Object>(CardStatus.valueOf(arg0.getCardStatus()), null, null, null)
    这样就可以了

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 9月26日
  • 已采纳回答 9月18日
  • 创建了问题 9月17日

悬赏问题

  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀
  • ¥15 mifare plus卡认证
  • ¥30 LSTM预测结果是一条直线
  • ¥15 stnodeeditor自定义控件
  • ¥15 SDO如何更改STM32的波特率