Fork me on GitHub

Introduction

In this exercise you will develop a web application. We will use:

  • Spring Framework
  • Spring Boot
  • Spring MVC
  • Thymeleaf

All of this technologies are briefly described in the sections below. If you need more information: Spring and for quick start go and see Spring guides.

Exercise

In this exercise you will develop a simple shop that will allow:

  • list all available products
  • add/remove product to cart
  • calculate the price, considering different promotions

UI team designed two views for us:

  • All products - you can see all available products and can add selected to cart
  • My cart - you can see all products in your cart and also can remove some of them. In this view you can also choose promotions and then calculate the value of the cart according to the selected promotion

Views have already bean implemented. We just need to test, if all necessary values, are transfered to/from controller.

Endpoint Parameters
GET /products 'products' - List of all products
GET /cart 'productsInCart' - List all products in cart
'sum' - total price of products in cart
'calculationContext' - context use to calculate sum, it tells us about promotion
POST /cart 'name' - name of product
POST /cart/remove 'index' - number of product in cart, start from 0
POST /cart/calculate 'secondForHalf' - if set to true indicate that we use this promotion (it is part of calculationContext)
'thirdForFree' - if set to true indicate that we use this promotion (it is part of calculationContext)

Testing controler

At this point the controller has only a skeleton methods. We need them to UI work properly. If you notice something that does not work, please feel free to correct it.

We will start by testing whether the controller is working properly. In a standalone mode, we will send requests to check if all required parameters are properly supported.

Add business logic to our controller

Next, we start developing all functionality, so write test to get all products.

  • Right now we get two of them: beer and wine. Check if all of theme was returned. Test should fail. Then go and implement what you need to test pass
  • Next add test to check if you can add something to your cart
  • And what when you try add product that is not in our list?
  • If you add more products are total price recalculated?
  • What about promotions? Is a price calculated properly? Maybe it is a good idea to write separate test case to check only the calculated promotions?
  • Now let's remove something from our cart. What happened? Is price correctly calculated? With all promotions?
  • And what with wrong product index?
  • Any other ideas?

Spring Framework

Spring is a framework for simple and fast building of powerful applications. It has many features but we will use only few of them.

Bean injection

One of the most interesting features of the spring is the IOC container. It gives us the ability to define beans, and then the container deals with the preparation and creation of such bean. We can use @Autowire annotation to indicate how the given bean is to be constructed.

Suppose we want to build a ProductController which will use PriceService.

public class ProductController {

    @Autowice
    private PriceService priceService;

    // rest of the class
}

In example above container inject PriceService instance into ProductController. User don't need to do it manually.

Spring MVC

Spring MVC is the web framework built on the Servlet API and included in the Spring Framework from the very beginning. To make use of this framework we need to create controller. To do it we use annotation @Controller. In controller we can create methods responsible for handling individual requests. We use two annotations for this: @GetMapping and @PostMapping. In most cases, the methods for GetMapping will add the returned parameters to the model. PostMapping method will receive data. You can see example in ProductController.java file.

To render web page Spring MVC use one of view technologies. In our project we use Thymeleaf. This technology assumes that method to handling request will return a name of the view which should be render. If you can see example pages go to resources/templates/cart.html file.

How to test it?

Spring provides classes that help us test web requests. The org.springframework.test.web.servlet.MockMvc class allows us to simulate such requests. In addition, it gives us the opportunity to check the status of such request and obtain the object org.springframework.test.web.servlet.MvcResult. This class can be used for additional assertions.

final MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/products"))
    .andExpect(status().isOk())
    .andReturn();

assertThat(mvcResult.getModelAndView().getModel()).containsKeys("products");
final MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/cart").param("name", "wine"))
    .andExpect(MockMvcResultMatchers.status().is3xxRedirection())
    .andReturn();

assertThat(mvcResult.getModelAndView().getViewName()).contains("products");

Spring Boot

Spring Boot is responsible for all this magic to work. It configure and start our container, create beans, configure web context and much more.