JCart : Iteration-8

In this Iteration#8 we will implement showing the Customer Account and Order History functionality in our ShoppingCart application.

  • Customer MyAccount Page
    • Profile
    • Order History

Once the customer is logged in our system he can click on MyAccount link at the top of the header and view his profile details and order history.

First let us write the Controller handler method in our CustomerController to show myAccount details.

@Controller
public class CustomerController extends JCartSiteBaseController
{	
	@Autowired private CustomerService customerService;
	...
	...	
	
	@RequestMapping(value="/myAccount", method=RequestMethod.GET)
	protected String myAccount(Model model)
	{
		String email = getCurrentUser().getCustomer().getEmail();
		Customer customer = customerService.getCustomerByEmail(email);
		model.addAttribute("customer", customer);
		List<Order> orders = customerService.getCustomerOrders(email);
		model.addAttribute("orders", orders);
		return "myAccount";
	}
}

Now create the myAccount.html view to render customer details and customer order history.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
	layout:decorator="layout/mainLayout">
<head>
<title>My Account</title>
</head>
<body>
	<div layout:fragment="content">
		<div class="single-product-area">
			<div class="zigzag-bottom"></div>
			<div class="container">
				<div role="tabpanel">
					<ul class="customer-tab" role="tablist">
						<li role="presentation" class="active"><a href="#profile"
							aria-controls="profile" role="tab" data-toggle="tab">Customer
								Info</a></li>
						<li role="presentation"><a href="#orders"
							aria-controls="orders" role="tab" data-toggle="tab">Orders</a></li>
					</ul>
					<div class="tab-content">
						<div role="tabpanel" class="tab-pane fade in active" id="profile">
							<h2>Customer Info</h2>
							<form role="form" action="#" th:object="${customer}"
								method="post">								
								<div class="form-group">
									<label>FirstName</label> <input type="text"
										class="form-control" th:field="*{firstName}"
										readonly="readonly" />
								</div>
								<div class="form-group">
									<label>LastName</label> <input type="text" class="form-control"
										th:field="*{lastName}" readonly="readonly" />
								</div>
								<div class="form-group">
									<label>Email</label> <input type="email" class="form-control"
										th:field="*{email}" readonly="readonly" />
								</div>
								<div class="form-group">
									<label>Phone</label> <input type="text" class="form-control"
										th:field="*{phone}" readonly="readonly" />
								</div>
							</form>
						</div>
						<div role="tabpanel" class="tab-pane fade" id="orders">
							<h2>Orders</h2>
							<table cellspacing="0" class="shop_table cart">
								<thead>
									<tr>
										<th>#</th>
										<th>Order Number</th>
										<th>Status</th>
									</tr>
								</thead>
								<tbody>
									<tr th:each="order,iterStat : ${orders}">
										<td><span th:text="${iterStat.count}">1</span></td>
										<td><a href="#" th:text="${order.orderNumber}"
											th:href="@{/orders/{orderNumber}(orderNumber=${order.orderNumber})}">OrderNumber</a>
										</td>
										<td><span th:text="${order.status}">Status</span></td>

									</tr>
								</tbody>
							</table>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</body>
</html>

Now you can login as customer and click on MyAccount and see the profile. When you click on Orders tab you can see the list of orders that customer is placed. Also you can click on Order Number to see more details of the Order.

JCart : Manage Customers

For Managing Customers we need a provision to see all the list of customers and view any Customers details.

Let us start with implementing the back-end Customer service.

public interface CustomerRepository extends JpaRepository<Customer, Integer>
{

	Customer findByEmail(String email);

	@Query("select o from Order o where o.customer.email=?1")
	List<Order> getCustomerOrders(String email);

}
@Service
@Transactional
public class CustomerService {
	@Autowired CustomerRepository customerRepository;
	
	public Customer getCustomerByEmail(String email) {
		return customerRepository.findByEmail(email);
	}

	public Customer createCustomer(Customer customer) {
		return customerRepository.save(customer);
	}

	public List<Customer> getAllCustomers() {
		return customerRepository.findAll();
	}

	public Customer getCustomerById(Integer id) {
		return customerRepository.findOne(id);
	}

	public List<Order> getCustomerOrders(String email) {
		return customerRepository.getCustomerOrders(email);
	}
}

Now let us implement CustomerController to handle the requests to display list of customers and the selected customer details.

@Controller
@Secured(SecurityUtil.MANAGE_CUSTOMERS)
public class CustomerController extends JCartAdminBaseController
{
	private static final String viewPrefix = "customers/";
	
	@Autowired 
	private CustomerService customerService;
	
	@Override
	protected String getHeaderTitle()
	{
		return "Manage Customers";
	}
		
	@RequestMapping(value="/customers", method=RequestMethod.GET)
	public String listCustomers(Model model) {
		List<Customer> list = customerService.getAllCustomers();
		model.addAttribute("customers",list);
		return viewPrefix+"customers";
	}
	
	@RequestMapping(value="/customers/{id}", method=RequestMethod.GET)
	public String viewCustomerForm(@PathVariable Integer id, Model model) {
		Customer customer = customerService.getCustomerById(id);
		model.addAttribute("customer",customer);
		return viewPrefix+"view_customer";
	}		
}

Create the thymeleaf view template for showing list of customers customers.html as follows:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
	 xmlns:th="http://www.thymeleaf.org"
	  xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
      layout:decorator="layout/mainLayout">      
<head>
	<title>Customers</title>
</head>
<body>    	        
	<div layout:fragment="content">
		<div class="row">
		<div class="col-md-12">
		  <div class="box">
			<div class="box-header">
			  <h3 class="box-title">List of Customers</h3>
			</div>
			<div class="box-body table-responsive no-padding">
			  <table class="table table-hover">
				<tr>
				  <th style="width: 10px">#</th>
				  <th>Customer Name</th>
				  <th>Email</th>
				  <th>View</th>                      
				</tr>
				<tr th:each="customer,iterStat : ${customers}">
				  <td><span th:text="${iterStat.count}">1</span></td>
				  <td th:text="${customer.firstName}">Customer Name</td>
				  <td th:text="${customer.email}">Customer Email</td>
				  <td><a th:href="@{/customers/{id}(id=${customer.id})}" 
				  class="btn btn-sm btn-default"><i class="fa fa-search"></i> View</a></td>
				</tr>                    
			  </table>
			</div>                
		  </div>
		</div>
		</div>		  
	</div>    	
</body>    
</html>

Create the thymeleaf view template for showing customer details view_customer.html as follows:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
	layout:decorator="layout/mainLayout">

<head>
<title>Customer - View</title>
</head>
<body>
	<div layout:fragment="content">
		<div class="box box-warning">
			<div class="box-header with-border">
				<h3 class="box-title">View Customer</h3>
			</div>
			<div class="box-body">
				<form role="form" action="#" th:object="${customer}" method="post">
					<div class="form-group">
						<label>FirstName</label> <input type="text" class="form-control"
							th:field="*{firstName}" readonly="readonly" />
					</div>

					<div class="form-group">
						<label>LastName</label> <input type="text" class="form-control"
							th:field="*{lastName}" readonly="readonly" />
					</div>

					<div class="form-group">
						<label>Email</label> <input type="email" class="form-control"
							th:field="*{email}" readonly="readonly" />
					</div>

					<div class="form-group">
						<label>Phone</label> <input type="text" class="form-control"
							th:field="*{phone}" readonly="readonly" />
					</div>
				</form>
			</div>
		</div>
	</div>

</body>
</html>

Now you can run the application and click on Customers menu item in left navigation. You can see list of customers and click on View button to view customer details.

JCart : Manage Orders

For Managing Orders we need a provision to see all the list of orders and view an order details and updating the order status.

Let us start with implementing the back-end order service.

@Service
@Transactional
public class OrderService
{
	@Autowired EmailService emailService;
	@Autowired OrderRepository orderRepository;
	
	...
	...
	
	public Order getOrder(String orderNumber)
	{
		return orderRepository.findByOrderNumber(orderNumber);
	}

	public List<Order> getAllOrders()
	{
		Sort sort = new Sort(Direction.DESC, "createdOn");
		return orderRepository.findAll(sort);
	}

	public Order updateOrder(Order order) {
		Order o = getOrder(order.getOrderNumber());
		o.setStatus(order.getStatus());
		Order savedOrder = orderRepository.save(o);
		return savedOrder;
	}
}

Now let us implement OrderController to handle the requests to display list of orders, the selected order details and updating the Order status.

@Controller
@Secured(SecurityUtil.MANAGE_ORDERS)
public class OrderController extends JCartAdminBaseController
{
	private static final String viewPrefix = "orders/";

	@Autowired protected EmailService emailService;
	@Autowired protected OrderService orderService;
	@Autowired private TemplateEngine templateEngine;
	
	@Override
	protected String getHeaderTitle()
	{
		return "Manage Orders";
	}
	
	
	@RequestMapping(value="/orders", method=RequestMethod.GET)
	public String listOrders(Model model) {
		List<Order> list = orderService.getAllOrders();
		model.addAttribute("orders",list);
		return viewPrefix+"orders";
	}
	
	@RequestMapping(value="/orders/{orderNumber}", method=RequestMethod.GET)
	public String editOrderForm(@PathVariable String orderNumber, Model model) {
		Order order = orderService.getOrder(orderNumber);
		model.addAttribute("order",order);
		return viewPrefix+"edit_order";
	}
	
	@RequestMapping(value="/orders/{orderNumber}", method=RequestMethod.POST)
	public String updateOrder(@ModelAttribute("order") Order order, BindingResult result, 
			Model model, RedirectAttributes redirectAttributes) {		
		Order persistedOrder = orderService.updateOrder(order);
		this.sendOrderStatusUpdateEmail(persistedOrder);
		logger.debug("Updated order with orderNumber : {}", persistedOrder.getOrderNumber());
		redirectAttributes.addFlashAttribute("info", "Order updated successfully");
		return "redirect:/orders";
	}
	
	protected void sendOrderStatusUpdateEmail(Order order)
	{
		try {
			final Context ctx = new Context();
	        ctx.setVariable("order", order);
			final String htmlContent = this.templateEngine.process("order-status-update-email", ctx);
	        
			emailService.sendEmail(order.getCustomer().getEmail(), 
								   "QuilCartCart - Order Status Update", 
								   htmlContent);
		} catch (JCartException e) {
			logger.error(e);
		}
	}
}

We are using thymeleaf email template jcart-core/src/main/resources/email-templates/order-status-update-email.html for sending the Order Status Update email.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title th:remove="all">Template for HTML email</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <p th:text="${'Hello '+order.customer.firstName}">
      Hello Customer
    </p>
    <p>
       Order Number : <span th:text="${order.orderNumber}">Number</span><br/>
       Status: <span th:text="${order.status}">Status</span>
    </p>
    <p>
      Regards, <br />
      <em>The QuilCart Team</em>
    </p>
  </body>
</html>

Create the thymeleaf view template for showing list of orders orders.html as follows:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
	  xmlns:th="http://www.thymeleaf.org"
	  xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
      layout:decorator="layout/mainLayout">      
 <head>
	<title>Orders</title>
</head>
<body>			
	<div layout:fragment="content">
		<div class="row">
		<div class="col-md-12">
		  <div class="box">
			<div class="box-header">
			  <h3 class="box-title">List of Orders</h3>
			</div>
			<div class="box-body table-responsive no-padding">
			  <table class="table table-hover">
				<tr>
				  <th style="width: 10px">#</th>
				  <th>Order Number</th>
				  <th>Customer Name</th>
				  <th>Email</th>
				  <th>Edit</th>				  
				</tr>
				<tr th:each="order,iterStat : ${orders}">
				  <td><span th:text="${iterStat.count}">1</span></td>
				  <td th:text="${order.orderNumber}">Order Number</td>
				  <td th:text="${order.customer.firstName}">Customer Name</td>
				  <td th:text="${order.customer.email}">Customer Email</td>
				  <td><a th:href="@{/orders/{orderNumber}(orderNumber=${order.orderNumber})}" 
						 class="btn btn-sm btn-default"><i class="fa fa-edit"></i> Edit</a></td>
				</tr>                    
			  </table>
			</div>			
		  </div>
		 </div>
	</div>		  
	</div>	
</body>    
</html>

Create the thymeleaf view template for showing order details edit_order.html as follows:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
	layout:decorator="layout/mainLayout">
<head>
<title>Orders - Edit</title>
</head>
<body>
	<div layout:fragment="content">
		<div class="box box-warning">
			<div class="box-header with-border">
				<h3 class="box-title">Edit Order</h3>
			</div>
			<!-- /.box-header -->
			<div class="box-body">
				<form role="form"
					th:action="@{/orders/{orderNumber}(orderNumber=${order.orderNumber})}"
					th:object="${order}" method="post">
					<p th:if="${#fields.hasErrors('global')}" th:errors="*{global}"
						th:class="text-red">Incorrect data</p>
					<div>
						<div th:unless="${order}">
							<h2>No order found</h2>
						</div>
						<div th:if="${order}">
							<h3>
								Order Number : <span th:text="${order.orderNumber}">Number</span>
							</h3>
							<h3>Order Item Details</h3>
							<table class="table table-hover">
								<thead>
									<tr>
										<th>Name</th>
										<th>Quantity</th>
										<th>Cost</th>
									</tr>
								</thead>
								<tbody>
									<tr th:each="item : ${order.items}">
										<td th:text="${item.product.name}">product.name</td>
										<td th:text="${item.quantity}"></td>
										<td th:text="${item.price * item.quantity}">price</td>
									</tr>
								</tbody>
								<tfoot>

									<tr class="cart-subtotal">
										<th>Order Subtotal</th>
										<td><span class="amount" th:text="${order.totalAmount}">£15.00</span>
										</td>
									</tr>

									<tr class="shipping">
										<th>Shipping and Handling</th>
										<td>Free Shipping</td>
									</tr>

									<tr class="order-total">
										<th>Order Total</th>
										<td><strong><span class="amount"
												th:text="${order.totalAmount}">£15.00</span></strong></td>
									</tr>

								</tfoot>
							</table>
							<div>
								<label>Order Status</label> <select th:field="*{status}">
									<option
										th:each="status: ${T(com.sivalabs.jcart.entities.OrderStatus).values()}"
										th:value="${status}" th:text="${status}">Status</option>
								</select>
							</div>
						</div>
					</div>
					<div class="box-footer">
						<button type="submit" class="btn btn-primary">Submit</button>
					</div>
				</form>
			</div>
		</div>
	</div>
</body>
</html>

Now you can run the application and click on Order menu item in left navigation. You can see list of order and click on Edit button to view order details or edit the order status.

JCart : Iteration-7

In Iteration#6 we have implemented features in ShoppingCart application to enable Customers place orders. In this Iteration#7 we will implement the features in Administration application to view and manage the Customers and Orders.

As part of Iteration#7 we will implement the following usecases:

JCart : Billing and Delivery Page

Once the customer reviewed his cart items details and clicks on Checkout we should display Billing & Delivery page where customer enters delivery address details, payment details etc and place the order.

Let us create a OrderDTO.java as follows:

public class OrderDTO implements Serializable
{
	private static final long serialVersionUID = 1L;

	@NotEmpty(message="FirstName is required")
	private String firstName;
	@NotEmpty(message="LastName is required")
	private String lastName;
	@NotEmpty(message="EmailId is required")
	@Email
	private String emailId;
	@NotEmpty(message="Phone is required")
	private String phone;
	
	@NotEmpty(message="Address Line1 is required")
	private String addressLine1;
	private String addressLine2;
	@NotEmpty(message="City is required")
	private String city;
	@NotEmpty(message="State is required")
	private String state;
	@NotEmpty(message="ZipCode is required")
	private String zipCode;
	@NotEmpty(message="Country is required")
	private String country;
	
	@NotEmpty(message="FirstName is required")
	private String billingFirstName;
	@NotEmpty(message="LastName is required")
	private String billingLastName;
	@NotEmpty(message="Address Line1 is required")
	private String billingAddressLine1;
	private String billingAddressLine2;
	@NotEmpty(message="City is required")
	private String billingCity;
	@NotEmpty(message="State is required")
	private String billingState;
	@NotEmpty(message="ZipCode is required")
	private String billingZipCode;
	@NotEmpty(message="Country is required")
	private String billingCountry;
	
	@NotEmpty(message="Credit Card Number is required")
	private String ccNumber;
	@NotEmpty(message="CVV is required")
	private String cvv;
	
	//setters & getters
}

Create CheckoutController to display the Billing & Delivery page as follows:

@Controller
public class CheckoutController extends JCartSiteBaseController
{

	@Override
	protected String getHeaderTitle()
	{
		return "Checkout";
	}

	@RequestMapping(value="/checkout", method=RequestMethod.GET)
	public String checkout(HttpServletRequest request, Model model)
	{
		OrderDTO order = new OrderDTO();
		model.addAttribute("order", order);
		Cart cart = getOrCreateCart(request);
		model.addAttribute("cart", cart);
		return "checkout";
	}
}

Finally create the checkout.html view as follows:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
	  xmlns:th="http://www.thymeleaf.org"
	  xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
      layout:decorator="layout/mainLayout">
      
<head>
<title>Cart</title>
</head>
<body>
<div layout:fragment="content">
<div class="single-product-area">
<div class="zigzag-bottom"></div>
<div class="container">
<div class="row">
					
	<div class="woocommerce-info col-md-offset-2 col-md-8" th:if="${#lists.isEmpty(cart.items)}">
			<h2>Cart is Empty</h2>
	</div>
	 <div class="col-md-offset-2 col-md-8" th:unless="${#lists.isEmpty(cart.items)}">
		<div class="product-content-right">
			<div class="woocommerce">
										
					<h3 id="order_review_heading">Your order</h3>

					<div id="order_review" style="position: relative;">
						<table class="shop_table">
							<thead>
								<tr>
									<th class="product-name">Product</th>
									<th class="product-total">Total</th>
								</tr>
							</thead>
							<tbody>
								<tr class="cart_item" th:each="item : ${cart.items}">
									<td class="product-name" >
										<span th:text="${item.product.name}" >Product Name </span> 
										<strong class="product-quantity" th:text="'× '+${item.quantity}">× 1</strong> </td>
									<td class="product-total">
										<span class="amount" th:text="${item.product.price * item.quantity}">£15.00</span> </td>
								</tr>
							</tbody>
							<tfoot>
								<tr class="cart-subtotal">
									<th>Cart Subtotal</th>
									<td><span class="amount" th:text="${cart.totalAmount}">£15.00</span>
									</td>
								</tr>
								<tr class="shipping">
									<th>Shipping and Handling</th>
									<td>

										Free Shipping
										<input type="hidden" class="shipping_method" value="free_shipping" id="shipping_method_0" data-index="0" name="shipping_method[0]"/>
									</td>
								</tr>

								<tr class="order-total">
									<th>Order Total</th>
									<td><strong><span class="amount" th:text="${cart.totalAmount}">£15.00</span></strong> </td>
								</tr>
							</tfoot>
						</table>
					</div>
					
				<form action="#" th:action="@{/orders}" class="checkout" method="post" th:object="${order}">

					<div id="customer_details" class="col2-set">
						<div class="col-1">
							<div class="woocommerce-billing-fields">
								<h3>Billing Details</h3>

								<p id="billing_first_name_field" class="form-row form-row-first validate-required">
									<label class="" for="billing_first_name">First Name <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" value="" placeholder="" th:field="*{billingFirstName}" class="input-text "/>
									<p th:if="${#fields.hasErrors('billingFirstName')}" th:errors="*{billingFirstName}" th:errorclass="text-danger">Incorrect firstName</p>
								</p>

								<p id="billing_last_name_field" class="form-row form-row-last validate-required">
									<label class="" for="billing_last_name">Last Name <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" value="" placeholder="" th:field="*{billingLastName}" class="input-text "/>
									<p th:if="${#fields.hasErrors('billingLastName')}" 
										th:errors="*{billingLastName}" th:errorclass="text-danger">Incorrect lastName</p>
								</p>
								<p id="billing_email_field" class="form-row form-row-first validate-required validate-email">
									<label class="" for="billing_email">Email Address <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" value="" placeholder="" th:field="*{emailId}" class="input-text "/>
									<p th:if="${#fields.hasErrors('emailId')}" 
										th:errors="*{emailId}" th:errorclass="text-danger">Incorrect emailId</p>
								</p>

								<p id="billing_phone_field" class="form-row form-row-last validate-required validate-phone">
									<label class="" for="billing_phone">Phone <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" value="" placeholder="" th:field="*{phone}"  class="input-text "/>
									<p th:if="${#fields.hasErrors('phone')}" 
										th:errors="*{phone}" th:errorclass="text-danger">Incorrect phone</p>
								</p>
								<div class="clear"></div>
								
								<p id="billing_address_1_field" class="form-row form-row-wide address-field validate-required">
									<label class="" for="billing_address_1">Address <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" value="" placeholder="Street address" th:field="*{billingAddressLine1}" class="input-text "/>
									<p th:if="${#fields.hasErrors('billingAddressLine1')}" th:errors="*{billingAddressLine1}" th:errorclass="text-danger">Incorrect addressLine1</p>
								</p>

								<p id="billing_address_2_field" class="form-row form-row-wide address-field">
									<input type="text" value="" placeholder="Apartment, suite, unit etc. (optional)" th:field="*{billingAddressLine2}"  class="input-text "/>
									<p th:if="${#fields.hasErrors('billingAddressLine2')}" th:errors="*{billingAddressLine2}" th:errorclass="text-danger">Incorrect addressLine2</p>
								</p>

								<p id="billing_city_field" class="form-row form-row-wide address-field validate-required" data-o_class="form-row form-row-wide address-field validate-required">
									<label class="" for="billing_city">Town / City <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" value="" placeholder="Town / City" th:field="*{billingCity}" class="input-text "/>
									<p th:if="${#fields.hasErrors('billingCity')}" th:errors="*{billingCity}" th:errorclass="text-danger">Incorrect city</p>
								</p>

								<p id="billing_state_field" class="form-row form-row-first address-field validate-state" data-o_class="form-row form-row-first address-field validate-state">
									<label class="" for="billing_state">State</label>
									<input type="text" th:field="*{billingState}" placeholder="State / County" value="" class="input-text "/>
									<p th:if="${#fields.hasErrors('billingState')}" th:errors="*{billingState}" th:errorclass="text-danger">Incorrect state</p>
								</p>
								<p id="billing_postcode_field" class="form-row form-row-last address-field validate-required validate-postcode" data-o_class="form-row form-row-last address-field validate-required validate-postcode">
									<label class="" for="billing_postcode">Zip Code <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" value="" placeholder="Postcode / Zip" th:field="*{billingZipCode}" class="input-text "/>
									<p th:if="${#fields.hasErrors('billingZipCode')}" th:errors="*{billingZipCode}" th:errorclass="text-danger">Incorrect zipCode</p>
								</p>
								<p id="billing_country_field" class="form-row form-row-wide address-field update_totals_on_change validate-required woocommerce-validated">
									<label class="" for="billing_country">Country <abbr title="required" class="required">*</abbr>
									</label>
									<select class="country_to_state country_select" th:field="*{billingCountry}">                                                    
										<option value="IN">India</option>
									</select>
								</p>
								<div class="clear"></div>                                            
							</div>
						</div>

						<div class="col-2">
							<div class="woocommerce-shipping-fields">
								<h3 id="ship-to-different-address">
									<label class="checkbox" for="ship-to-different-address-checkbox">Ship to same address?</label>
									<input type="checkbox" value="1" name="ship_to_different_address" checked="checked" 
											class="input-checkbox" id="ship-to-different-address-checkbox"/>
								</h3>
								<div class="shipping_address" style="display: block;">                                                

									<p id="shipping_first_name_field" class="form-row form-row-first validate-required">
										<label class="" for="shipping_first_name">First Name <abbr title="required" class="required">*</abbr>
										</label>
										<input type="text" value="" placeholder="" th:field="*{firstName}" class="input-text "/>
										<p th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}" th:errorclass="text-danger">Incorrect firstName</p>
									</p>

									<p id="shipping_last_name_field" class="form-row form-row-last validate-required">
										<label class="" for="shipping_last_name">Last Name <abbr title="required" class="required">*</abbr>
										</label>
										<input type="text" value="" placeholder="" th:field="*{lastName}" class="input-text "/>
										<p th:if="${#fields.hasErrors('lastName')}" 
											th:errors="*{lastName}" th:errorclass="text-danger">Incorrect lastName</p>
									</p>
									<div class="clear"></div>

									<p id="shipping_address_1_field" class="form-row form-row-wide address-field validate-required">
										<label class="" for="shipping_address_1">Address <abbr title="required" class="required">*</abbr>
										</label>
										<input type="text" value="" placeholder="Street address" th:field="*{addressLine1}"  class="input-text "/>
										<p th:if="${#fields.hasErrors('addressLine1')}" th:errors="*{addressLine1}" th:errorclass="text-danger">Incorrect addressLine1</p>
									</p>

									<p id="shipping_address_2_field" class="form-row form-row-wide address-field">
										<input type="text" value="" placeholder="Apartment, suite, unit etc. (optional)" th:field="*{addressLine2}" class="input-text "/>
										<p th:if="${#fields.hasErrors('addressLine2')}" th:errors="*{addressLine2}" th:errorclass="text-danger">Incorrect addressLine2</p>
									</p>

									<p id="shipping_city_field" class="form-row form-row-wide address-field validate-required" data-o_class="form-row form-row-wide address-field validate-required">
										<label class="" for="shipping_city">City <abbr title="required" class="required">*</abbr>
										</label>
										<input type="text" value="" placeholder="Town / City" th:field="*{city}" class="input-text "/>
										<p th:if="${#fields.hasErrors('city')}" th:errors="*{city}" th:errorclass="text-danger">Incorrect city</p>
									</p>

									<p id="shipping_state_field" class="form-row form-row-first address-field validate-state" data-o_class="form-row form-row-first address-field validate-state">
										<label class="" for="shipping_state">State</label>
										<input type="text" th:field="*{state}" placeholder="State / County" value="" class="input-text "/>
										<p th:if="${#fields.hasErrors('state')}" th:errors="*{state}" th:errorclass="text-danger">Incorrect state</p>
									</p>
									<p id="shipping_postcode_field" class="form-row form-row-last address-field validate-required validate-postcode" data-o_class="form-row form-row-last address-field validate-required validate-postcode">
										<label class="" for="shipping_postcode">Zip Code <abbr title="required" class="required">*</abbr>
										</label>
										<input type="text" value="" placeholder="Postcode / Zip" th:field="*{zipCode}" class="input-text "/>
										<p th:if="${#fields.hasErrors('zipCode')}" th:errors="*{zipCode}" th:errorclass="text-danger">Incorrect zipCode</p>
									</p>
									<p id="shipping_country_field" class="form-row form-row-wide address-field update_totals_on_change validate-required woocommerce-validated">
										<label class="" for="shipping_country">Country <abbr title="required" class="required">*</abbr>
										</label>
										<select class="country_to_state country_select" th:field="*{country}" >
											<option value="IN">India</option>
										</select>
									</p>
									<div class="clear"></div>
								</div>
							</div>
						</div>
					</div>                                
					<div id="customer_details" class="col2-set">
						<div class="col-1">
							<div class="woocommerce-billing-fields">
								<h3>Payment Details</h3>

								<p id="cc_number" class="form-row form-row-first validate-required">
									<label class="" for="cc_number">Credit Card Number <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" th:field="*{ccNumber}" class="input-text "/>
									<p th:if="${#fields.hasErrors('ccNumber')}" th:errors="*{ccNumber}" th:errorclass="text-danger">Invalid Credit Card</p>
								</p>
								
								<p id="cc_cvv" class="form-row form-row-first validate-required">
									<label class="" for="cc_cvv">CCV <abbr title="required" class="required">*</abbr>
									</label>
									<input type="text" th:field="*{cvv}" class="input-text "/>
									<p th:if="${#fields.hasErrors('cvv')}" th:errors="*{cvv}" th:errorclass="text-danger">Invalid CVV</p>
								</p>
								<p id="payment_expiry_date" class="form-row form-row-wide validate-required woocommerce-validated">
									<label class="" for="shipping_country">Expiry Date <abbr title="required" class="required">*</abbr></label>
									<div style="display: inline;">
									<select style="width: 25%">
										<option value="2015">2015</option>
										<option value="2016">2016</option>
										<option value="2017">2017</option>
										<option value="2018">2018</option>
									</select>
									
									<select style="width: 25%">
										<option value="1">Jan</option>
										<option value="2">Feb</option>
										<option value="3">Mar</option>
										<option value="4">Apr</option>
									</select>
									</div>
								</p>
								
							</div>
						</div>
				   </div>

					<div id="payment">
							
						 <div class="form-row place-order">
							 <input type="submit" data-value="Place order" value="Place order" id="place_order" name="woocommerce_checkout_place_order" class="button alt"/>
						 </div>

						 <div class="clear"></div>

				  </div>
				</form>

			</div>                       
		</div>                    
	</div>
</div>
</div>
</div>
</div>
</body>
</html>

Next we need to implement the back-end services for Order related operations.

public interface OrderRepository extends JpaRepository<Order, Integer>
{
	Order findByOrderNumber(String orderNumber);
}
@Service
@Transactional
public class OrderService
{	
	@Autowired OrderRepository orderRepository;
	
	public Order createOrder(Order order)
	{
		order.setOrderNumber(String.valueOf(System.currentTimeMillis()));
		Order savedOrder = orderRepository.save(order);
		return savedOrder;
	}
	
	public Order getOrder(String orderNumber)
	{
		return orderRepository.findByOrderNumber(orderNumber);
	}

}
@Controller
public class OrderController extends JCartSiteBaseController
{

	@Autowired private CustomerService customerService;
	@Autowired protected OrderService orderService;
	@Autowired protected EmailService emailService;
	
	@Override
	protected String getHeaderTitle()
	{
		return "Order";
	}

	@RequestMapping(value="/orders", method=RequestMethod.POST)
	public String placeOrder(@Valid @ModelAttribute("order") OrderDTO order, 
			BindingResult result, Model model, HttpServletRequest request)
	{
		Cart cart = getOrCreateCart(request);
		if (result.hasErrors()) {
			model.addAttribute("cart", cart);
			return "checkout";
        }
		
		Order newOrder = new Order();
		
		String email = getCurrentUser().getCustomer().getEmail();
		Customer customer = customerService.getCustomerByEmail(email);
		newOrder.setCustomer(customer);
		Address address = new Address();
		address.setAddressLine1(order.getAddressLine1());
		address.setAddressLine2(order.getAddressLine2());
		address.setCity(order.getCity());
		address.setState(order.getState());
		address.setZipCode(order.getZipCode());
		address.setCountry(order.getCountry());
		
		newOrder.setDeliveryAddress(address);
		
		Address billingAddress = new Address();
		billingAddress.setAddressLine1(order.getAddressLine1());
		billingAddress.setAddressLine2(order.getAddressLine2());
		billingAddress.setCity(order.getCity());
		billingAddress.setState(order.getState());
		billingAddress.setZipCode(order.getZipCode());
		billingAddress.setCountry(order.getCountry());
		
		newOrder.setBillingAddress(billingAddress);
		
		Set<OrderItem> orderItems = new HashSet<OrderItem>();
		List<LineItem> lineItems = cart.getItems();
		for (LineItem lineItem : lineItems)
		{
			OrderItem item = new OrderItem();
			item.setProduct(lineItem.getProduct());
			item.setQuantity(lineItem.getQuantity());
			item.setPrice(lineItem.getProduct().getPrice());
			item.setOrder(newOrder);
			orderItems.add(item);
		}
		
		newOrder.setItems(orderItems);
		
		Payment payment = new Payment();
		payment.setCcNumber(order.getCcNumber());
		payment.setCvv(order.getCvv());
		
		newOrder.setPayment(payment);
		Order savedOrder = orderService.createOrder(newOrder);
		
		this.sendOrderConfirmationEmail(savedOrder);
		
		request.getSession().removeAttribute("CART_KEY");
		return "redirect:orderconfirmation?orderNumber="+savedOrder.getOrderNumber();
	}
	
	protected void sendOrderConfirmationEmail(Order order)
	{
		try {
			emailService.sendEmail(order.getCustomer().getEmail(), 
					"QuilCartCart - Order Confirmation", 
					"Your order has been placed successfully.\n"
					+ "Order Number : "+order.getOrderNumber());
		} catch (JCartException e) {
			logger.error(e);
		}
	}
	
	@RequestMapping(value="/orderconfirmation", method=RequestMethod.GET)
	public String showOrderConfirmation(@RequestParam(value="orderNumber")String orderNumber, Model model)
	{
		Order order = orderService.getOrder(orderNumber);
		model.addAttribute("order", order);
		return "orderconfirmation";
	}

}

Create the template orderconfirmation.html for showing order confirmation as follows:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
	layout:decorator="layout/mainLayout">
<head>
<title>Order Confirmation</title>
</head>
<body>
	<div layout:fragment="content">
		<div class="single-product-area">
			<div class="zigzag-bottom"></div>
			<div class="container">
				<div class="row">

					<div class="woocommerce-info col-md-offset-2 col-md-8">
						<div th:unless="${order}" >
							<h2>No order found</h2>
						</div>
						<div th:if="${order}" >
							<h2>Your order has been placed successfully.</h2>
							<h2>
								Order Number : <span th:text="${order.orderNumber}">Number</span>
							</h2>
							<table class="table">
								<thead>
									<tr>
										<th>Name</th>
										<th>Quantity</th>
										<th>Cost</th>
									</tr>
								</thead>
								<tbody>
									<tr th:each="item : ${order.items}">
										<td th:text="${item.product.name}">product.name</td>
										<td th:text="${item.quantity}"></td>
										<td th:text="${item.price * item.quantity}">price</td>
									</tr>
								</tbody>
								<tfoot>
									<tr class="cart-subtotal">
										<th>Order Subtotal</th>
										<td><span class="amount" th:text="${order.totalAmount}">£15.00</span>
										</td>
									</tr>

									<tr class="shipping">
										<th>Shipping and Handling</th>
										<td>Free Shipping</td>
									</tr>

									<tr class="order-total">
										<th>Order Total</th>
										<td><strong><span class="amount" th:text="${order.totalAmount}">£15.00</span></strong> </td>
									</tr>

								</tfoot>
							</table>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</body>
</html>

Now you can add items to cart, view cart item details, and checkout by providing delivery and billing info and finally place order. Once the order is successfully placed it will display the order confirmation page.