The goal of this project is to play with Axon. For this, we implemented a food-ordering app that consists of three Spring Boot applications: customer-service, restaurant-service, and food-ordering-service. These services were implemented with CQRS and Event Sourcing in mind. To achieve this, we used the Axon Framework. The three services are connected to axon-server, which serves as the Event Store and Message Routing solution.
On ivangfr.github.io, I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.
- [Medium] Event Sourcing vs Traditional CRUD: A Side-by-Side Comparison with Real Spring Boot Code
- [Medium] From Zero to Event-Driven: Migrating a Traditional CRUD App to Axon Framework
-
Spring Bootapplication that exposes a REST API to manageCustomers. It also has a UI implemented usingJavaScript,jQuery, andTailwind CSS.customer-servicewas implemented using theAxon Framework. Every time a customer is added, updated, or deleted, the service emits the respective event, i.e.,CustomerAddedEvent,CustomerUpdatedEvent, orCustomerDeletedEvent.customer-serviceusesMySQLto store customer data. Additionally, it listens to order events, collects the order information that it needs, and stores it in an order table present in its own database, so that it doesn't need to call another service to get this information. -
Spring Bootapplication that exposes a REST API to manageRestaurants. It also has a UI implemented usingJavaScript,jQuery, andTailwind CSS.restaurant-servicewas implemented using theAxon Framework. Every time a restaurant is added, updated, or deleted, the service emits the respective event, i.e.,RestaurantAddedEvent,RestaurantUpdatedEvent, orRestaurantDeletedEvent. The same applies to the restaurant dishes, whose events are:RestaurantDishAddedEvent,RestaurantDishUpdatedEvent, orRestaurantDishDeletedEvent.restaurant-serviceusesPostgreSQLto store restaurant/dish data. Additionally, it listens to order events, collects the order information that it needs, and stores it in an order table present in its own database, so that it doesn't need to call another service to get this information. -
Spring Bootapplication that exposes a REST API to manageOrders. It has a UI implemented usingJavaScript,jQuery, andTailwind CSS.food-ordering-servicewas implemented using theAxon Framework. Every time an order is created, the service emits the respective event, i.e.,OrderCreatedEvent.food-ordering-serviceusesMongoDBto store order data. Additionally, it listens to customer and restaurant/dish events, collects the information that it needs, and stores them in a customer or restaurant/dish table present in its own database, so that it doesn't need to call another service to get this information. -
Mavenproject where all events mentioned above are defined. It generates a JAR file that is added as a dependency in thepom.xmlofcustomer-service,restaurant-service, andfood-ordering-service.
- Open a terminal and inside the
axon-springboot-websocketroot folder run:./init-environment.sh
Inside the axon-springboot-websocket root folder, run the following commands in different terminals:
-
axon-event-commons
./mvnw clean install --projects axon-event-commons
-
customer-service
./mvnw clean spring-boot:run --projects customer-service -Dspring-boot.run.jvmArguments="-Dserver.port=9080" -
restaurant-service
./mvnw clean spring-boot:run --projects restaurant-service -Dspring-boot.run.jvmArguments="-Dserver.port=9081" -
food-ordering-service
./mvnw clean spring-boot:run --projects food-ordering-service -Dspring-boot.run.jvmArguments="-Dserver.port=9082"
-
- In a terminal, make sure you are in the
axon-springboot-websocketroot folder. - Run the following script to build the Docker images:
./build-docker-images.sh
- In a terminal, make sure you are in the
-
-
customer-service
Environment Variable Description MYSQL_HOSTSpecify the host of the MySQLdatabase to use (defaultlocalhost)MYSQL_PORTSpecify the port of the MySQLdatabase to use (default3306)AXON_SERVER_HOSTSpecify the host of the Axon Serverto use (defaultlocalhost)AXON_SERVER_PORTSpecify the port of the Axon Serverto use (default8124) -
restaurant-service
Environment Variable Description POSTGRES_HOSTSpecify the host of the Postgresdatabase to use (defaultlocalhost)POSTGRES_PORTSpecify the port of the Postgresdatabase to use (default5432)AXON_SERVER_HOSTSpecify the host of the Axon Serverto use (defaultlocalhost)AXON_SERVER_PORTSpecify the port of the Axon Serverto use (default8124) -
food-ordering-service
Environment Variable Description MONGODB_HOSTSpecify the host of the Mongodatabase to use (defaultlocalhost)MONGODB_PORTSpecify the port of the Mongodatabase to use (default27017)AXON_SERVER_HOSTSpecify the host of the Axon Serverto use (defaultlocalhost)AXON_SERVER_PORTSpecify the port of the Axon Serverto use (default8124)
-
-
- In a terminal, make sure you are inside the
axon-springboot-websocketroot folder. - Run the following command:
./start-apps.sh
- In a terminal, make sure you are inside the
| Application | URL |
|---|---|
| customer-service | http://localhost:9080 |
| restaurant-service | http://localhost:9081 |
| food-ordering-service | http://localhost:9082 |
The GIF below shows a user creating a customer in the customer-service UI. Then, in the restaurant-service UI, they create a restaurant and add a dish. Finally, using the food-ordering-service UI, they submit an order using the customer and restaurant/dish created. Note that as soon as a customer or restaurant/dish is created, an event is sent, and the consumer of this event updates its UI in real-time using WebSockets.
-
Axon Server
The
Axon Serverdashboard can be accessed at http://localhost:8024 -
MySQL
docker exec -it -e MYSQL_PWD=secret mysql mysql -uroot --database customerdbSELECT * FROM customers; SELECT * FROM orders;
Type
exitto exit -
PostgreSQL
docker exec -it postgres psql -U postgres -d restaurantdbSELECT * FROM restaurants; SELECT * FROM dishes; SELECT * FROM orders;
Type
\qto exit -
MongoDB
docker exec -it mongodb mongo foodorderingdbdb.customers.find() db.restaurants.find() db.orders.find()
Type
exitto exit
- To stop applications:
- If you start them with
Maven, go to the terminals where they are running and pressCtrl+C. - If you start them as Docker containers, make sure you are inside the
axon-springboot-websocketroot folder and run the following script:./stop-apps.sh
- If you start them with
- To stop and remove environment containers and network, go to a terminal and, inside the
axon-springboot-websocketroot folder, run the following script:./shutdown-environment.sh
-
In a terminal, make sure you are inside the
axon-springboot-websocketroot folder. -
Run the following commands to execute the tests for each module:
-
customer-service
./mvnw clean test --projects customer-service -
restaurant-service
./mvnw clean test --projects restaurant-service -
food-ordering-service
./mvnw clean test --projects food-ordering-service
-
-
Alternatively, to run all tests at once:
./mvnw clean test
To remove the docker images created by this project, go to a terminal and, inside the axon-springboot-websocket root folder, run the following script:
./remove-docker-images.shUses Spotless Maven Plugin + Google Java Format (Java) and Prettier (JS/HTML) for automated formatting.
-
Check formatting:
./mvnw spotless:check
-
Auto-fix formatting:
./mvnw spotless:apply
Formatting is enforced automatically during ./mvnw verify.
[Medium]: How I Reduce GIF and Screenshot Sizes for My Technical Articles on macOS
If you find this useful, consider buying me a coffee:
This project is licensed under the MIT License.



