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

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日

悬赏问题

  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮