In this post, we are exploring the use of session attributes in Spring MVC. We will explore the use of @SessionAttribute
and @SessionAttributes
annotation available in the Spring MVC framework.
Introduction
While working on the web application, we may come into a situation where the same attributes referred to in multiple pages. In an online shopping, we may need to refer to a user shopping cart at multiple pages.
To make sure the availability of the attributes (shopping cart in our case), we need to store/persist this information so as we can pull the same information on the next page. In a web application, a good place to store those attributes is in the user’s session.
Let’s explore the option to use @SessionAttribute
and @SessionAttributes
annotation to do this task.
1. Application Setup
We are using Spring Boot to build our sample application. We will use Spring Boot starters to bootstrap our web application. This is how our pom.xml look like.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. Sample Use Case
To understand session attributes in Spring MVC or specifically the @SessionAttribute
and @SessionAttributes
annotation, let’s take an example of a shopping cart with the following workflow.
- Customer adds products to the cart by going to the PDP.
- Once the customer clicks on add to cart button that product goes to the shopping cart.
- Customer has the option to check all the products in the shopping cart by clicking on the view shopping cart link.
- When the customer clicks on the view cart link, they land on the shopping cart page to view all products from the cart.
Here is the Shopping cart POJO
package com.javadevjournal.model;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class ShoppingCart {
private String customerName;
private List < String > products;
private String product;
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public List < String > getProducts() {
return products;
}
public void setProducts(List < String > products) {
this.products = products;
}
public void setProduct(String product) {
if (CollectionUtils.isEmpty(this.getProducts())) {
List < String > products = new ArrayList < > ();
products.add(product);
this.setProducts(products);
} else {
this.getProducts().add(product);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ShoppingCart)) return false;
ShoppingCart that = (ShoppingCart) o;
return Objects.equals(getCustomerName(), that.getCustomerName()) &&
Objects.equals(getProducts(), that.getProducts());
}
@Override
public int hashCode() {
return Objects.hash(getCustomerName(), getProducts());
}
}
We need two controllers to complete our application. One controller is responsible to add a product to the shopping cart and the second controller is responsible to give shopping cart details which include products in the cart.
2.1 @ModelAttribute Annotation
We will use @ModelAttribute
annotation to support our @SessionAttribute
and @SessionAttributes
annotation. This annotation binds a method parameter or method return value to a named model attribute, exposed to a web view. When our controller is accessed for the first time, Spring instantiate an instance and place it in the Model.
@ModelAttribute("shoppingCart")
public ShoppingCart shoppingCart() {
return new ShoppingCart();
}
2.2 @SessionAttributes
We need to tell the Spring MVC framework to consider our ShoppingCart as session scope object. To to this, we use @SessionAttributes
annotation in our AddToCartController
.
@Controller
@SessionAttributes("shoppingCart")
public class AddToCartController { //controller logic
}
This is how our ShoppingCart controller looks like
package com.javadevjournal.controller;
import com.javadevjournal.model.ShoppingCart;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@SessionAttributes("shoppingCart")
public class AddToCartController {
@PostMapping("/addToCart")
public String addToCart(final Model model, @ModelAttribute ShoppingCart shoppingCart, final String productCode) {
if (shoppingCart != null) {
//add product to the shopping cart list
shoppingCart.setProduct(productCode);
model.addAttribute("cart", shoppingCart);
} else {
ShoppingCart cart = new ShoppingCart();
cart.setCustomerName("Super customer");
cart.setProduct(productCode);
model.addAttribute("cart", cart);
}
return "redirect:" + "product-detail-page";
}
@GetMapping("/product-detail-page")
public String viewPDP(Model model, @ModelAttribute("shoppingCart") ShoppingCart shoppingCart) {
if (shoppingCart != null) {
model.addAttribute("cart", shoppingCart);
} else {
model.addAttribute("cart", new ShoppingCart());
}
return "product";
}
@ModelAttribute("shoppingCart")
public ShoppingCart shoppingCart() {
return new ShoppingCart();
}
}
2.3 @SessionAttribute
In our ShoppingCart controller, we are binding the ShoppingCart object to the session by using @SessionAttribues
annotation.@SessionAttribute
annotation retrieve the existing attribute from the session. This annotation allows you to tell Spring which of your model attributes will also be copied to HttpSession before rendering the view.
Let’s continue with our example, In this step, we are creating a new CartPageController
which is responsible to get all the products from the customer shopping cart. We are using Session to store our shopping cart, to retrieve this shopping cart, we are will use @SessionAttribute
annotation.
public String cart(@SessionAttribute("shoppingCart") ShoppingCart cart, final Model model) { // }
This is how our CartPageController look like
package com.javadevjournal.controller;
import com.javadevjournal.model.ShoppingCart;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
public class CartPageController {
@GetMapping("/cart")
public String cart(@SessionAttribute("shoppingCart") ShoppingCart cart, final Model model) {
model.addAttribute("cart", cart);
return "cart";
}
}
2.4. Running Application
Let’s see our application in action, In the first step, add to cart page shown to the customer where customer adds products to the shopping cart.
For this post, we are adding following 4 products to the shopping cart
- 123
- 234
- 321
- 432
Please remember, all these products are in the ShoppingCart object stored in the session. When we click on the “Go To cart Page” link, we land on the shopping cart page served by ShoppingCartController.
Using @SessionAttribute,@SessionAttributes
with @ModelAttribute
is a simple and easy strategy and does not need any complex logic.
Summary
In this post, we explore the use of session attributes in Spring MVC. We got an understanding of using @SessionAttribute,@SessionAttributes
with @ModelAttribute
annotation. Download the complete application for this project from GitHub
how to test this application