January 13, 2021
Complete CQRS Application with Axon Framework

Complete CQRS Application with Axon Framework – 3 (Build the UI)

This is Part 3 and the final part of our CQRS Application.

Here is Part 1 and Part 2.

In this part, we would build the GUI and learn the following:

  • Building a GUI Using Bootstrap/JQuery/JavaScript
  • How Thymeleaf works
  • Making REST API call using RestTemplate

So, let’s get started!

  1. Add the JQuery and a Bootstrap Dependencies
  2. Build the HTML Page
  3. Create the JavaScript
  4. Setup the Controller file
  5. Troubleshooting Possible Errors
  6. Watch the Video


1. Add the JQuery and Bootstrap Dependencies

It’s easier to just add the JQuery and Bootstrap dependencies in your pom.xml. In this way you have all the necessary scripts and stylesheets added to your classpath.

See the dependencies below. You can also get them from Maven Repository





2. Create the HTML Page

You need to create the index.html page inside the src/main/resources/templates folder. You can find all the files in my Github repository here.

The html page would have to produce this output shown below:

I would not put the code for this page here. You can get it from Github. However, you can see below the code for the ‘Order One Now’ button.


<a id="orderButton" 
   class="btn btn-warning" >
    Order One Now!

Notice in the code the th:href attribute. The th: prefix is added so the thymeleaf engine can interpret it. Also note that two parameters are passed along with the url string: the product price and product id.

Another thing to note is how to include jquery and bootstrap links. See below


<link href="/webjars/bootstrap/4.3.1/css/bootstrap.css" rel="stylesheet" />
<script type="text/javascript" src="/webjars/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../static/main.js" th:src="@{/js/main.js}"></script>


About the Modal – when you copy the code for the modal from the bootstrap site to the index page, you need to do two things:

  • and an id of  orderModal to the modal
  • add an id of orderRef tot he primary button


3. Create the JavaScript file

I call this file main.js. This file is responsible for loading the modal confirm order. This file is placed inside the static folder

So the user can confirm the order. The content of the main.js file is shown below:


    //When the user clicks on the Order button
    $('.table #orderButton').on('click', function(event){
        event.preventDefault(); //don't redirect
        var href = $(this).attr('href'); //get the url of the button
        $('#orderModal #orderRef').attr('href', href); //assign to OrderRef
        $('#orderModal').modal(); //Display the modal


I have added the comments to the file to explain it. But it’s better you watch the video for a clearer understanding. Note that orderRef is the id of the button in the modal while orderModal is the id of the modal.


4. The Controller File

When the user interacts with the form, the request is not sent to the RestController we build in Part 2. Rather, the request goes to a controller(not Rest!). This controller, then uses RestTemplate to make REST calls to the RestController. Makes sense! Good!

Now you need to create a new file in the controllers package. I call this file HomeController. The content of this file is very important to note. This is because, you can see how to make both GET and POST request using RestTemplate.

Here is the home() function. This function retrieves a list of order and products and send them as model attributes to the html page.


public  String home(Model model){
    String productUrl = "http://localhost:8081/products";
    String orderUrl = "http://localhost:8081/orders";
    Object[] objects = restTemplate.getForObject(productUrl, Object[].class);
    List<Object> products = Arrays.asList(objects);
    List<Object> orders = Arrays.asList(restTemplate.getForObject(orderUrl, Object[].class));
    model.addAttribute("products", products);
    model.addAttribute("orders", orders);
    return "index";


Here is the createOrder() function. This function makes a post request to the RestController to create a new Order

@RequestMapping(value="/newOrder", method = {RequestMethod.POST, RequestMethod.GET})
public String createOrder(String id, String price) {
    String url = "http://localhost:8081/createOrder";
    HttpHeaders headers = new HttpHeaders();
    MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
    map.add("price", price);
    map.add("number", "1");
    map.add("productid", id);
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
    restTemplate.postForEntity(url,request, String.class);
    return "redirect:/index";


5. Possible Errors

Now you can test the application. If you encounter errors, here are the troubleshooting steps:

1. You may need to modify the createOrder() method in the orderController as follows:

public void handle(@RequestParam MultiValueMap summary) {
    CreateOrderCommand cmd = new CreateOrderCommand(

Note the @RequestParam annotation (not @RequestBody)

2. In the createOrder method in the HomeController, ensure the the “productid” is added to the map, not “id”.

3. For any other troubleshooting, you can see the video



0 0 vote
Article Rating
Notify of
1 Comment
Newest Most Voted
Inline Feedbacks
View all comments

[…] Complete CQRS Application with Axon Framework – 3 (Build the UI) […]