How to use Spring state machine for an Order object
Asked Answered
A

1

7

I'm trying to use Spring State Machine in my project, because there is an object is Order with several state

  • NEW
  • PAID
  • PACKAGED
  • DELIVERED
  • CANCELED
  • RETURNED

That object could be implement as following

public class Order {
  private String id;
  private Customer customer;
  private OrderState state;
// Some other fields with getter and setter
}

and I introduced OrderService, get order from DB, set some information including OrderState, and then save to DB.

However I don't know how to apply Spring state machine into this one, is it too complex to use with simple purpose like that?

Andy answered 10/3, 2016 at 9:5 Comment(3)
simple purpose like that-- like what? You didn't describe how transitions between states should be handled, which transitions are allowed etc. If you just store the state within the Order, simple enum is quite enough.Widner
From Spring state machine document, I would have to implement a StateChange Listener, and then get an order from DB, set state and then save back to DB. All these steps will be done by the Listener class instead of OrderService. I don't know if we have another way for implementationAndy
see example github.com/spring-projects/spring-statemachine/tree/master/…Globule
V
8

Define your states

public enum OrederStates {
   NEW, PAID, PACKAGED; // etc
}

Then define your events

public enum OrderEvents {
    PAYMENT, PACK, DELIVER; // etc 
}

Then declare your event listeners

@WithStateMachine
public class OrderEventHandler {
    @Autowired
    OrderService orderService;

    @OnTransition(src= "NEW",target = "PAID")
    handlePayment() {
       // Your code orderService.*
       // ..   
    }
    // Other handlers
}

Now configure your application to to use state machine

@Configuration
@EnableStateMachine
static class Config1 extends EnumStateMachineConfigurerAdapter<States, Events> {

    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states)
            throws Exception {
        states
            .withStates()
                .initial(OrderStates.NEW)
                .states(EnumSet.allOf(OrderStates.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
            throws Exception {
        transitions
            .withExternal()
                .source(OrderStates.NEW).target(OrderStates.PAID)
                .event(OrderEvents.PAYMENT)
                .and()
            .withExternal()
                .source(OrderStates.PAID).target(OrderStates.PACKED)
                .event(OrderEvents.PACK);
    }
}

And finally use it in your Application/Controller

public class MyApp {

    @Autowired
    StateMachine<States, Events> stateMachine;

    void doSignals() {
        stateMachine.start();
        stateMachine.sendEvent(OrderEvents.PAYMENT);
        stateMachine.sendEvent(Events.PACK);
    }
 }

Use this guide for getting started with state machine and this referce to learn more.

Violone answered 10/3, 2016 at 10:14 Comment(4)
Thanks for your suggestions, I'm developing a REST service that handling these orders, the parameter for 1 service could has 2 parameters: orderId and event. So I have to get a particular order from that orderId parameter, and change the state to target one, by that given event, I don't know how to do that with your implementation there. Please help to checkAndy
handlePayment should be public according exception I am getting.Aceldama
A very nice summary, however I'm not sure it addresses the actual use-case - changing the state of a particular order.Vigilante
I have a similar scenario, the handlePayment() function need to use some inputs from Order object that received at the endpoint. Any thoughts on that ?Handle

© 2022 - 2024 — McMap. All rights reserved.