Session Based Shopping Cart - Development and coding

Article Index

1 1 1 1 1 1 1 1 1 1 Rating 3.61 (54 Votes)

 

Setting up the environment for development:

We will be using Tomcat 6.x for running and testing our shopping cart. Refer ‘First JSP/Servlet workshop’ for Tomcat installation details.
We will be developing using Eclipse 3.x integrated with Tomcat via Sysdeo plugin. Refer ‘Integration of Eclipse with Tomcat’ article for details.

Let us create a new Tomcat Project, with context name as /ShoppingCart.
Set the source path and build path correctly. We will need JSTL libraries (jstl.jar and standard.jar) as we will be using JSTL/EL for the shopping cart page.

We should be able to start Tomcat from Eclipse, and access the any JSP page inside /ShoppingCart context which we created using the URL http://localhost:8080/ShoppingCart/<AnyFile.jsp>

The following will be approximate directory structure of the ShoppingCart project.

ShoppingCart
- ModelList.jsp
- ShoppingCart.jsp
WEB-INF
src
- in.techfreaks.shoppingcart.beans.CartBean.java
- in.techfreaks.shoppingcart.beans.CartItemBean.java
- in.techfreaks.shoppingcart.servlet.CartController.java
classes
lib
- jstl.jar
-standard.jar

 


Codin’ the Cart:
Such detailed design generally makes coding just a formality. Below is the code for each of the element identified during design. The code is pretty straight forward.


CartItemBean:

package in.techfreaks.shoppingcart.beans;

public class CartItemBean {
    private String strPartNumber;
    private String strModelDescription;
    private double dblUnitCost;
    private int iQuantity;
    private double dblTotalCost;
    
    public String getPartNumber() {
        return strPartNumber;
    }
    public void setPartNumber(String strPartNumber) {
        this.strPartNumber = strPartNumber;
    }
    public String getModelDescription() {
        return strModelDescription;
    }
    public void setModelDescription(String strModelDescription) {
        this.strModelDescription = strModelDescription;
    }
    public double getUnitCost() {
        return dblUnitCost;
    }
    public void setUnitCost(double dblUnitCost) {
        this.dblUnitCost = dblUnitCost;
    }
    public int getQuantity() {
        return iQuantity;
    }
    public void setQuantity(int quantity) {
        iQuantity = quantity;
    }
    public double getTotalCost() {
        return dblTotalCost;
    }
    public void setTotalCost(double dblTotalCost) {
        this.dblTotalCost = dblTotalCost;
    }
}


CartBean:

package in.techfreaks.shoppingcart.beans;

import java.util.ArrayList;


public class CartBean {
 private ArrayList alCartItems = new ArrayList();
 private double dblOrderTotal ;
 
 public int getLineItemCount() {
  return alCartItems.size();
 }
 
 public void deleteCartItem(String strItemIndex) {
  int iItemIndex = 0;
  try {
   iItemIndex = Integer.parseInt(strItemIndex);
   alCartItems.remove(iItemIndex - 1);
   calculateOrderTotal();
  } catch(NumberFormatException nfe) {
   System.out.println("Error while deleting cart item: "+nfe.getMessage());
   nfe.printStackTrace();
  }
 }
 
 public void updateCartItem(String strItemIndex, String strQuantity) {
  double dblTotalCost = 0.0;
  double dblUnitCost = 0.0;
  int iQuantity = 0;
  int iItemIndex = 0;
  CartItemBean cartItem = null;
  try {
   iItemIndex = Integer.parseInt(strItemIndex);
   iQuantity = Integer.parseInt(strQuantity);
   if(iQuantity>0) {
    cartItem = (CartItemBean)alCartItems.get(iItemIndex-1);
    dblUnitCost = cartItem.getUnitCost();
    dblTotalCost = dblUnitCost*iQuantity;
    cartItem.setQuantity(iQuantity);
    cartItem.setTotalCost(dblTotalCost);
    calculateOrderTotal();
   }
  } catch (NumberFormatException nfe) {
   System.out.println("Error while updating cart: "+nfe.getMessage());
   nfe.printStackTrace();
  }
  
 }
 
 public void addCartItem(String strModelNo, String strDescription,
String strUnitCost, String strQuantity) {
  double dblTotalCost = 0.0;
  double dblUnitCost = 0.0;
  int iQuantity = 0;
  CartItemBean cartItem = new CartItemBean();
  try {
   dblUnitCost = Double.parseDouble(strUnitCost);
   iQuantity = Integer.parseInt(strQuantity);
   if(iQuantity>0) {
    dblTotalCost = dblUnitCost*iQuantity;
    cartItem.setPartNumber(strModelNo);
    cartItem.setModelDescription(strDescription);
    cartItem.setUnitCost(dblUnitCost);
    cartItem.setQuantity(iQuantity);
    cartItem.setTotalCost(dblTotalCost);
    alCartItems.add(cartItem);
    calculateOrderTotal();
   }
   
  } catch (NumberFormatException nfe) {
   System.out.println("Error while parsing from String to primitive types: "+nfe.getMessage());
   nfe.printStackTrace();
  }
 }
 
 public void addCartItem(CartItemBean cartItem) {
  alCartItems.add(cartItem);
 }
 
 public CartItemBean getCartItem(int iItemIndex) {
  CartItemBean cartItem = null;
  if(alCartItems.size()>iItemIndex) {
   cartItem = (CartItemBean) alCartItems.get(iItemIndex);
  }
  return cartItem;
 }
 
 public ArrayList getCartItems() {
  return alCartItems;
 }
 public void setCartItems(ArrayList alCartItems) {
  this.alCartItems = alCartItems;
 }
 public double getOrderTotal() {
  return dblOrderTotal;
 }
 public void setOrderTotal(double dblOrderTotal) {
  this.dblOrderTotal = dblOrderTotal;
 }
 
 protected void calculateOrderTotal() {
  double dblTotal = 0;
  for(int counter=0;counter<alCartItems.size();counter++) {
   CartItemBean cartItem = (CartItemBean) alCartItems.get(counter);
   dblTotal+=cartItem.getTotalCost();
   
  }
  setOrderTotal(dblTotal);
 }

}


CartController:

package in.techfreaks.shoppingcart.servlet;

import in.techfreaks.shoppingcart.beans.CartBean;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class CartController extends HttpServlet {
 
 //public static final String addToCart
 
 public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

  String strAction = request.getParameter("action");
  
  
  if(strAction!=null && !strAction.equals("")) {
   if(strAction.equals("add")) {
    addToCart(request);
   } else if (strAction.equals("Update")) {
    updateCart(request);
   } else if (strAction.equals("Delete")) {
    deleteCart(request);
   }
  }
  response.sendRedirect("../ShoppingCart.jsp");
 }
 
 protected void deleteCart(HttpServletRequest request) {
  HttpSession session = request.getSession();
  String strItemIndex = request.getParameter("itemIndex");
  CartBean cartBean = null;
  
  Object objCartBean = session.getAttribute("cart");
  if(objCartBean!=null) {
   cartBean = (CartBean) objCartBean ;
  } else {
   cartBean = new CartBean();
  }
  cartBean.deleteCartItem(strItemIndex);
 }
 
 protected void updateCart(HttpServletRequest request) {
  HttpSession session = request.getSession();
  String strQuantity = request.getParameter("quantity");
  String strItemIndex = request.getParameter("itemIndex");
 
  CartBean cartBean = null;
  
  Object objCartBean = session.getAttribute("cart");
  if(objCartBean!=null) {
   cartBean = (CartBean) objCartBean ;
  } else {
   cartBean = new CartBean();
  }
  cartBean.updateCartItem(strItemIndex, strQuantity);
 }
 
 protected void addToCart(HttpServletRequest request) {
  HttpSession session = request.getSession();
  String strModelNo = request.getParameter("modelNo");
  String strDescription = request.getParameter("description");
  String strPrice = request.getParameter("price");
  String strQuantity = request.getParameter("quantity");
  
  CartBean cartBean = null;
  
  Object objCartBean = session.getAttribute("cart");

  if(objCartBean!=null) {
   cartBean = (CartBean) objCartBean ;
  } else {
   cartBean = new CartBean();
   session.setAttribute("cart", cartBean);
  }
  
  cartBean.addCartItem(strModelNo, strDescription, strPrice, strQuantity);
 }

}
  • Do not ever maintain any state in servlet’s instance variables. You may find mixing of data between requests or user sessions. The best part of this is that, it will only happen in a production environment and you win a severity 1 ticket and that too completely free!

 ModelList.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>www.tech-freaks.in - Model List</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<p><font size="3" face="Verdana, Arial, Helvetica, sans-serif"><strong>Model List
  </strong></font></p>
<a href="/ShoppingCart.jsp" mce_href="ShoppingCart.jsp">View Cart</a>
<p/>    
<table width="75%" border="1">
  <tr>
    <td><form name="modelDetail1" method="POST" action="servlet/CartController">
 <font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Model:</strong>
        TF-Model1</font><input type="hidden" name="modelNo" value="TF-MODEL1">
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Description:</strong>
        Tech-Freaks imaginary model 1. </font><input type="hidden" name="description" value="Tech-Freaks imaginary model 1."></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Quantity:<input type="text" size="2" value="1" name="quantity"></strong></font></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Price:</strong>
        $10.00</font><input type="hidden" name="price" value="10"></p><input type="hidden" name="action" value="add"><input type="submit" name="addToCart" value="Add To Cart">
      </form></td>
    <td><form name="modelDetail2" method="POST" action="servlet/CartController"><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Model</strong>:
      TF-Model2 </font><input type="hidden" name="modelNo" value="TF-MODEL2">
<font face="Verdana, Arial, Helvetica, sans-serif">
      <p><font size="2"><strong>Description</strong>: Tech-Freaks imaginary model
        2. </font><input type="hidden" name="description" value="Tech-Freaks imaginary model 2."></p>
      <p><font size="2"><strong>Quantity</strong>: <input type="text" size="2" value="1" name="quantity"></font></p>
      <p><font size="2"><strong>Price</strong>: $20.00<input type="hidden" name="price" value="20"></font></p>
           <input type="hidden" name="action" value="add">
             <input type="submit" name="addToCart" value="Add To Cart">
      </font></form></td>
  </tr>
  <tr>
    <td><form name="modelDetail3" method="POST" action="servlet/CartController"><p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Model:</strong>
        TF-Model3</font><input type="hidden" name="modelNo" value="TF-MODEL3"></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Description:</strong>
        Tech-Freaks imaginary model 3. </font><input type="hidden" name="description" value="Tech-Freaks imaginary model 3."></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Quantity:</strong></font> <input type="text" size="2" value="1" name="quantity"></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Price: $30.00</strong></font><input type="hidden" name="price" value="30"></p>        <input type="hidden" name="action" value="add">
        <input type="submit" name="addToCart" value="Add To Cart">
</form></td>
    <td><form name="modelDetail4" method="POST" action="servlet/CartController"><p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Model</strong>:
        TF-Model4</font><input type="hidden" name="modelNo" value="TF-MODEL4"></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Description</strong>:
        Tech-Freaks imaginary model 4. </font><input type="hidden" name="description" value="Tech-Freaks imaginary model 4."></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Quantity</strong>:</font> <input type="text" size="2" value="1" name="quantity"></p>
      <p><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><strong>Price</strong>: $40.00</font><input type="hidden" name="price" value="40"></p>
   <input type="hidden" name="action" value="add"><input type="submit" name="addToCart" value="Add To Cart"></form></td>
  </tr>
</table>
<p> </p>
</body>
</html>

 

ShoppingCart.jsp

For iterating the elements in the cart session, we are using simple JSTL tags with EL.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>www.tech-freaks.in - Shopping Cart</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<p><font face="Verdana, Arial, Helvetica, sans-serif"><strong>Shopping Cart</strong></font></p>
<p><a href="/ModelList.jsp" mce_href="ModelList.jsp">Model List</a> </p>
<table width="75%" border="1">
  <tr bgcolor="#CCCCCC">
    <td><strong><font size="2" face="Verdana, Arial, Helvetica, sans-serif">Model
      Description</font></strong></td>
    <td><strong><font size="2" face="Verdana, Arial, Helvetica, sans-serif">Quantity</font></strong></td>
    <td><strong><font size="2" face="Verdana, Arial, Helvetica, sans-serif">Unit
      Price</font></strong></td>
    <td><strong><font size="2" face="Verdana, Arial, Helvetica, sans-serif">Total</font></strong></td>
  </tr>
  <jsp:useBean id="cart" scope="session" class="in.techfreaks.shoppingcart.beans.CartBean" />
  <c:if test="${cart.lineItemCount==0}">
  <tr>
  <td colspan="4"><font size="2" face="Verdana, Arial, Helvetica, sans-serif">- Cart is currently empty -<br/>
  </tr>
  </c:if>
  <c:forEach var="cartItem" items="${cart.cartItems}" varStatus="counter">
  <form name="item" method="POST" action="servlet/CartController">
  <tr>
    <td><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><b><c:out value="${cartItem.partNumber}"/></b><br/>
      <c:out value="${cartItem.modelDescription}"/></font></td>
    <td><font size="2" face="Verdana, Arial, Helvetica, sans-serif"><input type='hidden' name='itemIndex' value='<c:out value="${counter.count}"/>'><input type='text' name="quantity" value='<c:out value="${cartItem.quantity}"/>' size='2'> <input type="submit" name="action" value="Update">
 <br/>         <input type="submit" name="action" value="Delete"></font></td>
    <td><font size="2" face="Verdana, Arial, Helvetica, sans-serif">$<c:out value="${cartItem.unitCost}"/></font></td>
    <td><font size="2" face="Verdana, Arial, Helvetica, sans-serif">$<c:out value="${cartItem.totalCost}"/></font></td>
  </tr>
  </form>
  </c:forEach>
  <tr>
    <td colspan="2"> </td>
    <td> </td>
    <td><font size="2" face="Verdana, Arial, Helvetica, sans-serif">Subtotal: $<c:out value="${cart.orderTotal}"/></font></td>
  </tr>
</table>
</body>
</html>

 

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

  <display-name>Shopping Cart</display-name>
  <description>
    Simple Shopping Cart
  </description>

  <servlet>
    <servlet-name>CartController</servlet-name>
    <servlet-class>in.techfreaks.shoppingcart.servlet.CartController</servlet-class>
  </servlet>

  <!-- Define the Manager Servlet Mapping -->
  <servlet-mapping>
    <servlet-name>CartController</servlet-name>
      <url-pattern>/servlet/*</url-pattern>
  </servlet-mapping>

</web-app>

 

 

Putting the cart to test:
We mainly want to test the below three functionalities:
1. Add to cart
2. Update the quantity
3. Remove an item from cart

Start Tomcat from Eclipse and access URL http://localhost:8080/ShoppingCart/ModelList.jsp to test the above functionality.

Change requests:
Change is the essence of life! Same happens to business requirements and code. This means, that a ‘hardly working’ developer has to become ‘hardworking’. So, we would like you to be the ‘hardworking’ programmer to add the below functionality in this existing cart.
1. Currently, if the same item is again added to cart, a new line item is added. Modify this in such a way that, if the same item is added again, the existing item’s quantity should be incremented by one. All other state of the cart/cart items should be adjusted accordingly.
2. In the cart page, provide a new text box for redeeming promotion codes. The discount of 5% should be provided on the order total, when any of the promotion code from a list of pre-defined codes is used.

Feel free to write to us at This email address is being protected from spambots. You need JavaScript enabled to view it. for any queries regarding this change request.

Enjoy! Coding and rock n roll, always rulz!

UPDATE: Checkout our latest article on Session Based Shopping Cart using Struts 1 Framework.


Joomla SEO by MijoSEF