0

我在为一个非常简单的场景配置我的 SSM 时遇到问题:

在此处输入图像描述

罪魁祸首是触发log_on事件时需要发生的“验证”操作。我重新阅读了 SSM 文档,但不确定这是“fork”、“guard”还是分层配置。

“动作”在这里执行:

@Component
public class LogonValidationAction implements Action<PickStates, PickEvents> {

Logger logger = LogManager.getLogger();

volatile int counter = 0;

@Override
public void execute(StateContext<PickStates, PickEvents> context) {
    String eventName = context.getEvent().name();
    logger.info("executing {} for event {}", LogonValidationAction.class.getName(), eventName);

    // basically, if success, send success, if failure, send failure
    // for testing
    if(counter % 2 == 0)
        context.getStateMachine().sendEvent(PickEvents.logon_sucess);
    else
        context.getStateMachine().sendEvent(PickEvents.logon_fail);
}
}

我在我的测试中使用“计数器”将流程引导到“失败”(保持登录状态)或“成功”(状态更改为登录状态)。

这是配置:

@Configuration
@EnableStateMachineFactory
public class Config extends EnumStateMachineConfigurerAdapter<PickStates, PickEvents>{

@Autowired
StateMachineListener stateMachineListener;

@Autowired
LogonValidationAction logonValidationAction;

@Override
public void configure(StateMachineStateConfigurer<PickStates, PickEvents> states) throws Exception {
    states
        .withStates()
        .initial(PickStates.logged_off)
        .state(PickStates.logged_on)
        .states(EnumSet.allOf(PickStates.class));
}

@Override
public void configure(StateMachineTransitionConfigurer<PickStates, PickEvents> transitions) throws Exception {
    transitions
        .withExternal()
        .source(PickStates.logged_off)
        .target(PickStates.logged_on)
        .event(PickEvents.log_on)
        .action(logonValidationAction)
        .and()
        .withExternal()
        .source(PickStates.logged_on)
        .target(PickStates.logged_off)
        .event(PickEvents.log_off);
}

@Override
public void configure(StateMachineConfigurationConfigurer<PickStates, PickEvents> config) throws Exception {
    config
        .withConfiguration()
        .autoStartup(true)
        .listener(stateMachineListener);
}
}

这是失败的测试(当操作触发 logon_fail 事件时期望“logged_off”):

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class EzpickStateMachineTest {

Logger logger = LogManager.getLogger();

@Autowired
StateMachineFactory<PickStates, PickEvents> stateMachineFactory;

// for testing so can toggle success/failure when logging in
@Autowired
LogonValidationAction logonValidationAction;

@Test
public void failLogon() throws Exception {
    StateMachine<PickStates, PickEvents> stateMachine = stateMachineFactory.getStateMachine();

    stateMachine.start();

    // when sm starts, state is 'logged_off'
    assertThat(stateMachine.getState().getId().name(), is(PickStates.logged_off.name()));

    // odd numbers fire 'failure' event
    logonValidationAction.setCounter(1);

    stateMachine.sendEvent(PickEvents.log_on);

    // if logon fails, state is 'logged_off'
    assertThat(stateMachine.getState().getId().name(), is(PickStates.logged_off.name()));
}
}
4

1 回答 1

0

从您尝试发送的操作中,logon_sucess或者logon_fail但在机器配置中,您没有为这些事件定义任何转换,因此机器不会做任何事情。

其他注意事项,不要存储counter在 action bean 中,使用机器扩展状态变量,因为它对每个使用 machine 或StateContext.

当它counter在扩展状态下可用时,您可以创建一个匿名转换,其中包含使用扩展状态中的计数器的保护。另一种可能性是使用选择伪状态和守卫在目标状态之间进行选择。您对计数器的使用正是 wiki 在其扩展状态部分中提到的内容https://en.wikipedia.org/wiki/UML_state_machine#Extended_states

于 2016-07-07T07:49:28.257 回答