做了一个报卡系统,报卡具有几个状态(编辑中, 已提交 , 已审核 , 已删除),对应几个事件(提交,审核,打回,删除),
其中事件对应状态变更
提交(编辑中 —— 已提交)
审核(已提交 —— 已审核)
打回(已提交 —— 编辑中)
删除(编辑中 —— 已删除)
该功能使用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