Coffee Shop Project

Merhaba Arkadaslar

Bu bolumde Coffee Shop projesi yapacagiz.
Projemizde kullanacagimiz frameworkler/toollar

  • Eclipse
  • JDK8
  • Spring Framework MVC
  • Hibernate Native
  • HyperSQL Database
  • Maven
  • Bootstrap
  • JSP
  • Log4J
  • Apache Tomcat
  • Jetty Plugin

NOT0 : Zamanla bu yazida ve projede iyilestirmeler yapacagim insallah.
NOT1: Gordugunuz eksiklikleri/yanlisliklari bildirebilirsiniz. Sorularinizi sorabilirsiniz , zamanla eklemeler aciklamalari bol miktar eklerim. Simdilik initial version olarak dusunebiliriz.
NOT2 : Burada yer alan bir cok konu blogta diger bolumlerde yer almaktadir.
Spring MVC

Github Source / Project

eventerguder/injavawetrust.coffeeshop

Create a Maven Project

Oncelikle yeni bir Maven projesi olusturalim.
NOT : Dynamic Web Project olusturup Convert To Maven yapabilirsiniz.
Jetty Plugin ile direkt calistirmak icin bu formatta olusturdum.

maven

maven2

Projemizi olusturduk ;

eclipse project

Sonrasinda yeni bir Folder olusturalim ; src/main/java

Dikkat edecek olursak Projemizde JRE versiyonu 1.5 , bunu guncellemek icin pom.xml dosyamiza yeni bir plugin ekleyelim.

pom.xml

	<build>
		<finalName>injavawetrust.coffeeshop</finalName>

		<plugins>

			<plugin>
			
				<!-- JDK version -->
			
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>${java.specification.version}</source>
					<target>${java.specification.version}</target>
				</configuration>
			</plugin>

		</plugins>

	</build>

Sonrasinda ;

right click -> Maven -> Update Project

Add Dependencies

Projemizde kullanacagimiz dependency tanimlarini ve Jetty plugin’i ekleyelim.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com</groupId>
	<artifactId>injavawetrust.coffeeshop</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>injavawetrust.coffeeshop Maven Webapp</name>
	<url>http://maven.apache.org</url>

	<properties>
		<spring.version>4.3.2.RELEASE</spring.version>
		<hibernate.version>5.2.1.Final</hibernate.version>
		<hsqldb.version>2.3.4</hsqldb.version>
		<jstl.version>1.2</jstl.version>
		<log4j.version>1.2.17</log4j.version>
		<commons.dbcp2.version>2.1.1</commons.dbcp2.version>
		<servlet.version>3.1.0</servlet.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>


	<dependencies>

		<!-- spring dependency -->

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>


		<!-- hibernate dependency -->

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/jstl/jstl -->

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>


		<!-- https://mvnrepository.com/artifact/log4j/log4j -->

		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>


		<!-- https://mvnrepository.com/artifact/org.hsqldb/hsqldb -->

		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<version>${hsqldb.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>${commons.dbcp2.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servlet.version}</version>
		</dependency>


	</dependencies>
	<build>
		<finalName>injavawetrust.coffeeshop</finalName>

		<plugins>

			<plugin>
			<!-- JDK version -->
			
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>${java.specification.version}</source>
					<target>${java.specification.version}</target>
				</configuration>
			</plugin>

			<!-- embedded Jetty server -->
			
			<plugin>
				<groupId>org.eclipse.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>9.2.11.v20150529</version>
				<configuration>
					<scanIntervalSeconds>10</scanIntervalSeconds>
					<webApp>
						<contextPath>/injavawetrust.coffeeshop</contextPath>
					</webApp>
				</configuration>
			</plugin>

		</plugins>

	</build>
</project>

Deployment Descriptor

web.xml dosyamizda DispatcherServlet tanimini yapalim.
Projemizin Dynamic Web Module ayarini guncelleyelim ; bunun icin suraya bakabilirsiniz ;
JSF – 07 – Apache TomEE & Project Facets & Maven
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">
	<display-name>injavawetrust.coffeeshop</display-name>

	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				/WEB-INF/application-context.xml
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

application-context.xml

JSP sayfalarimiz WEB-INF/pages dizininde yer alacak. InternalResourceViewResolver bean tanimini ve diger konfigurasyon dosyalarini import edelim.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd                   
        ">

	<import resource="db-hsqldb-config.xml" />
	<import resource="i18n.xml" />
	<import resource="hibernate-config.xml" />
	<import resource="interceptors.xml" />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/" />
		<property name="suffix" value=".jsp" />
	</bean>


</beans>

db-hsqldb-config.xml

Veritabani icin HSQL kullanacagiz. Bu noktada .properties ve .sql dosyalarimizi ilgili dizine ekleyecegiz ; /src/main/resources

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/jdbc     
        http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
	   	">


	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location">
			<value>classpath:jdbc/jdbc.properties</value>
		</property>
	</bean>


	<bean id="dataSourceHSQL" class="org.apache.commons.dbcp2.BasicDataSource"
		destroy-method="close">

		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />

	</bean>


	<jdbc:initialize-database data-source="dataSourceHSQL"
		ignore-failures="ALL">
		<jdbc:script location="classpath:db/sql/create-db.sql" />
		<jdbc:script location="classpath:db/sql/insert-data.sql" />
	</jdbc:initialize-database>

</beans>

jdbc.properties

Dikkat edecek olursak #{systemProperties} Expression yardimi ile veritabani dosyamizi olusturacagimiz path’i ayarliyoruz.
Boylece projemiz portable olabilir , proje calistigi noktada user.home dizini altinda /db/data altinda dosyalar olusacaktir.

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:file:#{systemProperties['user.home']}/db/data
jdbc.username=sa
jdbc.password=

create-db.sql

Projemiz ayaga kalkarken , Product adinda bir tablo oluracagiz ve bazi kayitlar ekleyecegiz.

CREATE TABLE IF NOT EXISTS Product (
  id INTEGER PRIMARY KEY,
  name VARCHAR(50),
  description  VARCHAR(50),
  price NUMERIC,
  isCondiment BOOLEAN,
  category  VARCHAR(50)
);

insert-data.sql

Ornek kayitlarimizi ekleyelim. Burada isCondiment kolonunda true icin bu urun tek basina satilabilir , false icin bu urun tek basina satilamaz bir eklenti ozelligi gosteriyor amacli flag tutmaktayiz.

Ilk etapta category olarak da hot , cold , other gibi secenekler olabilir.

insert into Product(id,name,description,price,isCondiment,category) values (1,'Latte','Best Latte',5.00,false,'hot');
insert into Product(id,name,description,price,isCondiment,category) values (2,'Mocha','Best Mocha',6.00,false,'hot');
insert into Product(id,name,description,price,isCondiment,category) values (3,'Cay','Best Cay',3.00,false,'hot');
insert into Product(id,name,description,price,isCondiment,category) values (4,'Turk kahvesi','Best Turk kahvesi',5.00,false,'hot');

insert into Product(id,name,description,price,isCondiment,category) values (5,'Sut','Best Süt',2.00,true,'other');
insert into Product(id,name,description,price,isCondiment,category) values (6,'Findik surubu','Best Findik',3.00,true,'other');
insert into Product(id,name,description,price,isCondiment,category) values (7,'Cikolata sosu','Best Cikolata',5.00,true,'other');
insert into Product(id,name,description,price,isCondiment,category) values (8,'Limon','Best Eksi Limon',2.00,true,'other');

hibernate-config.xml

Hibernate icin LocalSessionFactoryBean ve HibernateTransactionManager bean tanimlarini gerceklestirelim.

Ilgili konuyu surada inceledim ;
Spring MVC – 24 – Hibernate

dataSource property icin , db-hsqldb-config.xml dosyamizda tanimladigimiz dataSourceHSQL id bilgisini veriyoruz.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
	    http://www.springframework.org/schema/tx/spring-tx.xsd ">

	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

		<property name="dataSource" ref="dataSourceHSQL" />
		<property name="packagesToScan" value="product.domain" />

		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.show_sql">false</prop>				
				<prop key="hibernate.hbm2ddl.auto">update</prop>
			</props>
		</property>

	</bean>

	<tx:annotation-driven transaction-manager="transactionManager"
		proxy-target-class="true" />


	<bean id="transactionManager"
		class="org.springframework.orm.hibernate5.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>


</beans>

i18n.xml

Internationalization(i18n) icin konfigurasyonumuzu gerceklestirelim ve springMessages dosyalarini ekleyelim.

i18n konusunu surada inceledim ;

Spring MVC – 10 – Internationalization (i18n) and Localization (L10n)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"	
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd                        
        ">

	<bean id="messageSource"
		class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basename" value="springMessages" />
		<property name="defaultEncoding" value="UTF-8" />
	</bean>


	<bean id="localeResolver"
		class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
		<property name="defaultLocale" value="tr" />
	</bean>

</beans>

springMessages_en.properties

Projemizde kullanacagimiz mesajlarin EN karsiligi.

product.products= Products
product.add.newproduct = Add new product
product.id=Product Id
product.name= Name
product.price = Price
.... more messages

springMessages_tr.properties

Projemizde kullanacagimiz mesajlarin TR karsiligi.

product.products= Ürünler
product.add.newproduct= Ürün Ekle
product.id= Ürün Kodu
product.name= Ürün İsmi
product.price = Ürün Fiyatı
.... more messages

Audit & Interceptor

Ilgili konuyu burada inceledim ;
Spring MVC – 13 – Interceptors & Log4J

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context" 	
	xmlns:mvc="http://www.springframework.org/schema/mvc" 	
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd    
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd            	  
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd                       
        ">

	<context:component-scan base-package="product" />

	<mvc:resources mapping="/resources/**" location="/resources/" />
	<mvc:annotation-driven />


	<bean id="localeResolver"
		class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
		<property name="defaultLocale" value="tr" />
	</bean>


	<mvc:interceptors>
		<bean id="localeChangeInterceptor"
			class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
			<property name="paramName" value="language" />
		</bean>

		<bean id="audit" class="product.logging.AuditLoggingInterceptor" />
	</mvc:interceptors>
</beans>

AuditLoggingInterceptor.java

package product.logging;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class AuditLoggingInterceptor extends HandlerInterceptorAdapter {

	Logger logger = Logger.getLogger("auditLogger");

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		String remoteHost = request.getRemoteHost();
		int remotePort = request.getRemotePort();

		logger.info("client host :  " + remoteHost);
		logger.info("client port : " + remotePort);

		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
	}
}

Product Domain

Product.java , CondimentDecorator.java ve ProductInterface.java sinif ve arabirim ile Decorator Pattern’i uygulayalim.

Product.java

package product.domain;

import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
import javax.persistence.Transient;

@Entity
public class Product implements ProductInterface {

	@TableGenerator(
			name = "PRODUCT_GEN_DETAILED", 
			table = "ID_GEN", 
			pkColumnName = "ID_GEN_NAME", 
			valueColumnName = "ID_GEN_COUNT", 
			initialValue = 100,
			allocationSize = 10)
	@Id
	@GeneratedValue(generator = "PRODUCT_GEN_DETAILED")
	private int id;
	private String name;
	private String description;
	
	private BigDecimal price;
	private boolean isCondiment;
	private String category;

	@Transient
	private Map<Product, Integer> condimentsInProduct = new LinkedHashMap<Product, Integer>();

	public Product() {
		super();
	}

	public Product(String name, String description, BigDecimal price, Map<Product, Integer> condimentsInProduct) {
		//TODO builder pattern
		super();
		this.name = name;
		this.description = description;
		this.price = price;
		this.condimentsInProduct = condimentsInProduct;
	}
        // getters and setters
}

CondimentDecorator.java

package product.domain;

import java.math.BigDecimal;
import java.util.Map;

public class CondimentDecorator extends Product {

	private ProductInterface productInterface;

	public CondimentDecorator(ProductInterface beverage, String name, String description, BigDecimal price,
			Map<Product, Integer> condimentsInProduct) {
		super(name, description, price, condimentsInProduct);
		this.productInterface = beverage;
	}

	public String getName() {
		return this.productInterface.getName() + ", " + super.getName();
	}

	@Override
	public BigDecimal getPrice() {
		return super.getPrice().add(this.productInterface.getPrice());
	}

	@Override
	public String toString() {
		return this.getName() + " = " + this.getPrice();
	}

}

ProductInterface.java

package product.domain;

import java.math.BigDecimal;

public interface ProductInterface {

	String getName();

	BigDecimal getPrice();

}

Builder Pattern

Kullanacagimiz metotlara fazla parametre gecmek yerine ShoppingCartData ‘yi gececegiz. Burada Builder Pattern’i kullanacagiz.
Kodumuz daha flexible/esnek olacak.

ShoppingCartData.java

package product.domain;

import java.util.Map;
import java.util.TreeMap;

public class ShoppingCartData {

	private Map<Integer, TreeMap<Integer, Product>> shoppingCart;
	private Product product;
	private int orderIndexId;
	private int condimentId;
	private Map<Integer, Product> allCondimentsInShop;

	private ShoppingCartData(ShoppingCartDataBuilder builder) {
		this.shoppingCart = builder.shoppingCart;
		this.product = builder.product;
		this.orderIndexId = builder.orderIndexId;
		this.condimentId = builder.condimentId;
		this.allCondimentsInShop = builder.allCondimentsInShop;
	}

	public Map<Integer, TreeMap<Integer, Product>> getShoppingCart() {
		return shoppingCart;
	}

	public Product getProduct() {
		return product;
	}

	public int getOrderIndexId() {
		return orderIndexId;
	}

	public int getCondimentId() {
		return condimentId;
	}

	public Map<Integer, Product> getAllCondimentsInShop() {
		return allCondimentsInShop;
	}

	public static class ShoppingCartDataBuilder {
		private Map<Integer, TreeMap<Integer, Product>> shoppingCart;
		private Product product;
		private int orderIndexId;
		private int condimentId;
		private Map<Integer, Product> allCondimentsInShop;

		public ShoppingCartDataBuilder(Map<Integer, TreeMap<Integer, Product>> shoppingCart, Product product) {
			this.shoppingCart = shoppingCart;
			this.product = product;
		}

		public ShoppingCartDataBuilder shoppingCart(Map<Integer, TreeMap<Integer, Product>> shoppingCart) {
			this.shoppingCart = shoppingCart;
			return this;
		}

		public ShoppingCartDataBuilder product(Product product) {
			this.product = product;
			return this;
		}

		public ShoppingCartDataBuilder orderIndexId(int orderIndexId) {
			this.orderIndexId = orderIndexId;
			return this;
		}

		public ShoppingCartDataBuilder condimentId(int condimentId) {
			this.condimentId = condimentId;
			return this;
		}

		public ShoppingCartDataBuilder allCondimentsInShop(Map<Integer, Product> allCondimentsInShop) {
			this.allCondimentsInShop = allCondimentsInShop;
			return this;
		}

		public ShoppingCartData build() {
			return new ShoppingCartData(this);
		}

	}

}

Web Layer / Product Crud Controller

ProductCRUDController.java
Bu sinifimizda urun ekleme / urun silme / urun guncelleme ve urun silme islemlerini gerceklestiriyoruz.

package product.controller;

import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import product.domain.Product;
import product.service.ProductService;
import product.validator.ProductValidator;

import static product.utility.URLs.PRODUCT_ADD;
import static product.utility.URLs.PRODUCT_EDIT;
import static product.utility.URLs.PRODUCT_UPDATE;
import static product.utility.URLs.PRODUCT_DELETE;

import static product.utility.ViewURLs.PRODUCT_ADD_VIEW_REDIRECT;
import static product.utility.ViewURLs.PRODUCT_ADD_VIEW;


@Controller
public class ProductCRUDController {

	@Autowired
	private ProductService productService;

	@Autowired
	private ProductValidator productValidator;

	@ModelAttribute("productCategories")
	public Map<String, String> prepareCategoryList() {
		Map<String, String> categories = new HashMap<String, String>();
		categories.put("hot", "Hot Beverage");
		categories.put("cold", "Cold Beverage");
		categories.put("other", "Other");
		return categories;
	}

	@RequestMapping(value = PRODUCT_ADD, method = RequestMethod.GET)
	public String getAddNewProductForm(@ModelAttribute("newProduct") Product newProduct, Model model) {

		model.addAttribute("allProducts", productService.getAllProductsAndCondiments());
		return PRODUCT_ADD_VIEW;
	}

	@RequestMapping(value = PRODUCT_ADD, method = RequestMethod.POST)
	public String processAddNewProductForm(@ModelAttribute("newProduct") Product productToBeAdded,
			BindingResult bindingResult, Model model) {

		productValidator.validate(productToBeAdded, bindingResult);

		if (bindingResult.hasErrors()) {
			model.addAttribute("allProducts", productService.getAllProductsAndCondiments());
			return PRODUCT_ADD_VIEW;
		}

		productService.addProduct(productToBeAdded);
		return PRODUCT_ADD_VIEW_REDIRECT;
	}

	@RequestMapping(value = PRODUCT_EDIT, method = RequestMethod.GET)
	public String editProduct(@RequestParam("id") int id, Model model) {

		model.addAttribute("newProduct", productService.getProductById(id));
		model.addAttribute("allProducts", productService.getAllProductsAndCondiments());
		model.addAttribute("update", "update");

		return PRODUCT_ADD_VIEW;
	}

	@RequestMapping(value = PRODUCT_UPDATE, method = RequestMethod.POST)
	public String updatePerson(@ModelAttribute("newProduct") Product productToBeUpdated, BindingResult bindingResult,
			Model model) {

		productValidator.validate(productToBeUpdated, bindingResult);

		if (bindingResult.hasErrors()) {
			model.addAttribute("newProduct", productToBeUpdated);
			model.addAttribute("allProducts", productService.getAllProductsAndCondiments());
			model.addAttribute("update", "update");
			return PRODUCT_ADD_VIEW;
		}

		productService.updateProduct(productToBeUpdated);

		return PRODUCT_ADD_VIEW_REDIRECT;
	}

	@RequestMapping(value = PRODUCT_DELETE, method = RequestMethod.GET)
	public String deleteProduct(@ModelAttribute("newProduct") Product newProduct, @RequestParam("id") int id) {

		productService.deleteProduct(id);
		return PRODUCT_ADD_VIEW_REDIRECT;

	}
}

Validator

ProductValidator sinifimizda org.springframework.validation.Validator arabirimini/interface uyguluyoruz.
name ve price alanlari icin validation ekleyelim , sart saglanmadigi takdirde error message ekleyelim.

ProductValidator.java

package product.validator;

import java.math.BigDecimal;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import product.domain.Product;

@Component
public class ProductValidator implements Validator {

	@Override
	public boolean supports(Class<?> clazz) {
		return false;
	}

	@Override
	public void validate(Object target, Errors errors) {
		Product product = (Product) target;

		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required.name");

		if (product.getPrice()==null || product.getPrice().compareTo(new BigDecimal(0))<0) {
			errors.rejectValue("price", "required.price");
		}
		//TODO more validation

	}

}

Web Layer / Product Menu Controller

Bu Controller sinifinda

  • Urun listeleme (listAllProducts)
  • Category ye gore filtreleme (listAllProductsByCategory)
  • Urun detay (getProductDetail)
  • Sepete urun ekleme (addProductToCart)
  • Sepetten urun silme (deleteProductFromCart)
  • Sepeti temizleme ( deleteAllProductFromCart )
  • Ilgili urun icin eklenti/condiments ekleme (addNewCondimentToProduct)
  • Ilgili urun icin eklenti/condiments silme (deleteCondimentFromProduct)
  • Sepet detay (goToShoppingCart)
  • Sepetten ilgili tum urunleri temizleme(deleteOrderFromCart)

ProductMenuController.java

package product.controller;

import static product.utility.URLs.ALL;
import static product.utility.URLs.CATEGORY;
import static product.utility.URLs.DEFAULT_URL;
import static product.utility.URLs.MENU;
import static product.utility.URLs.ORDER_DELETE_FROM_CART;
import static product.utility.URLs.PRODUCT_ADD_CONDIMENT;
import static product.utility.URLs.PRODUCT_ADD_TO_CART;
import static product.utility.URLs.PRODUCT_DELETE_ALL_CART;
import static product.utility.URLs.PRODUCT_DELETE_CONDIMENT;
import static product.utility.URLs.PRODUCT_DELETE_FROM_CART;
import static product.utility.URLs.PRODUCT_DETAIL;
import static product.utility.URLs.PRODUCT_SHOPPING_CART;
import static product.utility.ViewURLs.PRODUCT_DETAIL_VIEW;
import static product.utility.ViewURLs.PRODUCT_DETAIL_VIEW_REDIRECT;
import static product.utility.ViewURLs.PRODUCT_LIST_VIEW;
import static product.utility.ViewURLs.PRODUCT_SHOPPING_CART_VIEW;
import static product.utility.ViewURLs.PRODUCT_SHOPPING_CART_VIEW_REDIRECT;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import product.domain.Product;
import product.domain.ShoppingCartData;
import product.service.ProductCartService;
import product.service.ProductService;

@Controller
@RequestMapping(value = { MENU, DEFAULT_URL })
@SessionAttributes(value = { "product", "allCondimentsInShop", "shoppingCart" })

public class ProductMenuController {

	@Autowired
	private ProductService productService;

	@Autowired
	private ProductCartService productCartService;

	@ModelAttribute("shoppingCart")
	public void initializeShoppingCart(Model model) {

		Map<Integer, TreeMap<Integer, Product>> shoppingCart = new HashMap<Integer, TreeMap<Integer, Product>>();
		model.addAttribute("shoppingCart", shoppingCart);

	}

	@RequestMapping(value = { ALL, DEFAULT_URL }, method = RequestMethod.GET)
	public String listAllProducts(Model model) {

		model.addAttribute("products", productService.getAllProducts());
		return PRODUCT_LIST_VIEW;

	}

	@RequestMapping(value = CATEGORY, method = RequestMethod.GET)
	public String listAllProductsByCategory(@PathVariable("category") String productCategory, Model model) {

		model.addAttribute("products", productService.getProductsByCategory(productCategory));
		return PRODUCT_LIST_VIEW;

	}

	@RequestMapping(value = PRODUCT_DETAIL, method = RequestMethod.GET)
	public String getProductDetail(@RequestParam("productId") int productId, Model model) {

		Map<Integer, Product> allCondimentsInShop = productService.getAllCondiments();
		model.addAttribute("product", productService.getProductById(productId));
		model.addAttribute("allCondimentsInShop", allCondimentsInShop);
		return PRODUCT_DETAIL_VIEW;
	}

	@RequestMapping(value = PRODUCT_ADD_TO_CART, method = RequestMethod.GET)
	public String addProductToCart(@ModelAttribute("product") Product product,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		ShoppingCartData data = new ShoppingCartData.ShoppingCartDataBuilder(shoppingCart, product).build();
		productCartService.addProductToShoppingCart(data);

		return PRODUCT_DETAIL_VIEW_REDIRECT + product.getId();
	}

	@RequestMapping(value = PRODUCT_DELETE_FROM_CART, method = RequestMethod.GET)
	public String deleteProductFromCart(@RequestParam("indexId") int productIndexIdInShoppingCart,
			@ModelAttribute("product") Product product,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		ShoppingCartData data = new ShoppingCartData.ShoppingCartDataBuilder(shoppingCart, product)
				.orderIndexId(productIndexIdInShoppingCart).build();

		productCartService.deleteProductFromShoppingCart(data);

		return PRODUCT_DETAIL_VIEW_REDIRECT + product.getId();
	}

	@RequestMapping(value = PRODUCT_DELETE_ALL_CART, method = RequestMethod.GET)
	public String deleteAllProductFromCart(@ModelAttribute("product") Product product,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		ShoppingCartData data = new ShoppingCartData.ShoppingCartDataBuilder(shoppingCart, product).build();
		productCartService.deleteAllProductFromShoppingCartByProductId(data);

		return PRODUCT_DETAIL_VIEW_REDIRECT + product.getId();
	}

	@RequestMapping(value = PRODUCT_ADD_CONDIMENT, method = RequestMethod.GET)
	public String addNewCondimentToProduct(@RequestParam("indexId") int orderIndexId,
			@RequestParam("condimentId") int condimentId, @ModelAttribute("product") Product product,
			@ModelAttribute("allCondimentsInShop") Map<Integer, Product> allCondimentsInShop,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		ShoppingCartData data = new ShoppingCartData.ShoppingCartDataBuilder(shoppingCart, product)
				.orderIndexId(orderIndexId).allCondimentsInShop(allCondimentsInShop).condimentId(condimentId).build();

		productCartService.addCondimentToProductInShoppingCart(data);

		return PRODUCT_DETAIL_VIEW_REDIRECT + product.getId();
	}

	@RequestMapping(value = PRODUCT_DELETE_CONDIMENT, method = RequestMethod.GET)
	public String deleteCondimentFromProduct(@RequestParam("indexId") int orderIndexId,
			@RequestParam("condimentId") int condimentId, @ModelAttribute("product") Product product,
			@ModelAttribute("allCondimentsInShop") Map<Integer, Product> allCondimentsInShop,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		ShoppingCartData data = new ShoppingCartData.ShoppingCartDataBuilder(shoppingCart, product)
				.orderIndexId(orderIndexId).allCondimentsInShop(allCondimentsInShop).condimentId(condimentId).build();

		productCartService.deleteCondimentFromProductInShoppingCart(data);

		return PRODUCT_DETAIL_VIEW_REDIRECT + product.getId();
	}

	@RequestMapping(value = PRODUCT_SHOPPING_CART, method = RequestMethod.GET)
	public String goToShoppingCart(@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart,
			Model model, final RedirectAttributes redirectAttributes) {

		TreeMap<Integer, BigDecimal> calculatedPrices = productCartService
				.calculateProductsSumByIdInShoppingCart(shoppingCart);

		BigDecimal totalAll = productCartService.calculateProductsSumAllInShoppingCart(calculatedPrices);

		Map<Integer, Product> products = new HashMap<Integer, Product>();

		for (Product product : productService.getAllProducts()) {
			products.put(product.getId(), product);
		}

		model.addAttribute("products", products);
		model.addAttribute("calculatedPrices", calculatedPrices);
		model.addAttribute("totalAll", totalAll);
		model.addAttribute("reducedPrice", productCartService.calculateDiscount(shoppingCart));
		return PRODUCT_SHOPPING_CART_VIEW;
	}

	@RequestMapping(value = ORDER_DELETE_FROM_CART, method = RequestMethod.GET)
	public String deleteOrderFromCart(@RequestParam("productId") int productId,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		shoppingCart.remove(productId);

		return PRODUCT_SHOPPING_CART_VIEW_REDIRECT;
	}

}

Web Layer /Payment Controller

Bu Controller sinifimizda ;

  • Odeme form sayfasi
  • Odeme islemi
  • Islem sonucu ve status’u tamamlama islemleri yapilmaktadir.

PaymentController.java

package product.controller;

import static product.utility.URLs.ORDER_PAYMENT;
import static product.utility.URLs.ORDER_PAYMENT_CONFIRM;
import static product.utility.URLs.ORDER_PAYMENT_SUCCESS;
import static product.utility.ViewURLs.ORDER_PAYMENT_FORM_VIEW;
import static product.utility.ViewURLs.ORDER_PAYMENT_VIEW_SUCCESS;
import static product.utility.ViewURLs.ORDER_PAYMENT_VIEW_SUCCESS_REDIRECT;

import java.math.BigDecimal;
import java.util.Map;
import java.util.TreeMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

import product.domain.Product;
import product.domain.order.Customer;
import product.domain.order.Order;
import product.domain.order.PaymentFormData;
import product.service.OrderService;
import product.service.ProductCartService;

@Controller
@SessionAttributes(value = { "shoppingCart" })
public class PaymentController {

	@Autowired
	private ProductCartService productCartService;

	@Autowired
	private OrderService orderService;

	@RequestMapping(value = ORDER_PAYMENT, method = RequestMethod.POST)
	public String payment(@ModelAttribute("paymentFormData") PaymentFormData paymentFormData,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart, Model model) {
		BigDecimal calculatedAmount = productCartService.calculateDiscount(shoppingCart);
		model.addAttribute("calculatedAmount", calculatedAmount);
		model.addAttribute("paymentFormData", paymentFormData);
		return ORDER_PAYMENT_FORM_VIEW;

	}

	@RequestMapping(value = ORDER_PAYMENT_CONFIRM, method = RequestMethod.POST)
	public String paymentConfirm(@ModelAttribute("paymentFormData") PaymentFormData paymentFormData,
			@ModelAttribute("shoppingCart") Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		Customer customer = new Customer(paymentFormData.getCustomerName());
		Order order = new Order();
		BigDecimal calculatedAmount = productCartService.calculateDiscount(shoppingCart);
		order.setAmount(calculatedAmount);
		order.setCustomer(customer);
		orderService.insertOrder(order);

		return ORDER_PAYMENT_VIEW_SUCCESS_REDIRECT;

	}

	@RequestMapping(value = ORDER_PAYMENT_SUCCESS, method = RequestMethod.GET)
	public String paymentSuccess(SessionStatus status) {
		status.setComplete();
		return ORDER_PAYMENT_VIEW_SUCCESS;

	}


}

Web Layer /Order List Controller

Bu Controller sinifinda satilan/tamamlanan siparis bilgileri yer almaktadir.

OrderListController.java

package product.controller;

import static product.utility.URLs.ORDER_LIST;
import static product.utility.ViewURLs.ORDER_LIST_VIEW;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import product.service.OrderService;
@Controller
public class OrderListController {
	
	@Autowired
	private OrderService orderService;
	
	@RequestMapping(value = ORDER_LIST, method = RequestMethod.GET)
	public String getCustomerOrderList(Model model,
			@RequestParam(value = "groupBy", required = false) String groupByCustomerName) {

		model.addAttribute("ordersTotals", orderService.getOrdersTotalAmount());
		model.addAttribute("allCustomerOrders", orderService.getOrderList());

		if (groupByCustomerName != null && groupByCustomerName.equals("customerName")) {
			model.addAttribute("ordersAmountByCustomerName", orderService.getOrdersTotalAmountByCustomerName());
		}
		return ORDER_LIST_VIEW;
	}
}

Customer/ Order Domain

Order ve Customer siniflarimizi tanimlayalim.

Customer.java

package product.domain.order;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.TableGenerator;

@Entity
public class Customer {

	@TableGenerator(
			name = "CUSTOMER_GEN_DETAILED", 
			table = "CUSTOMER_ID_GEN", 
			pkColumnName = "ID_GEN_NAME", 
			valueColumnName = "ID_GEN_COUNT", 
			initialValue = 1, allocationSize = 10)
	@Id
	@GeneratedValue(generator = "CUSTOMER_GEN_DETAILED")
	private int id;

	private String customerName;

	@OneToMany(mappedBy = "customer")
	private List<Order> orders;


	//getters and setters

}

Order.java

package product.domain.order;

import java.math.BigDecimal;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.TableGenerator;


@Entity(name = "CustomerOrder")
public class Order {

	@TableGenerator(
			name = "ORDER_GEN_DETAILED", 
			table = "ORDER_ID_GEN", 
			pkColumnName = "ID_GEN_NAME", 
			valueColumnName = "ID_GEN_COUNT", 
			initialValue = 1, 
			allocationSize = 10)
	@Id
	@GeneratedValue(generator = "ORDER_GEN_DETAILED")
	private int id;

	private BigDecimal amount;

	@ManyToOne(cascade=CascadeType.ALL)
	private Customer customer;

	//getters and setters

}

Payment Form Data Domain

PaymentFormData.java
Odeme formunda kullanacagimiz sinifimizi olusturalim ;

package product.domain.order;

public class PaymentFormData {

	private String customerName;
	private String cardNumber;
	private int month;
	private int year;
	private String cvv;

	//getters and setters

}

Service Layer

OrderService arabiriminde ;

  • Siparis kaydi ekleme (insertOrder)
  • Tum siparislerin getirilmesi ( getOrderList)
  • Tum siparisler icin toplam amount bilgisi getirilmesi ( getOrdersTotalAmount )
  • Musteriye gore farkli siparisler icin toplam amount bilgisi getirilmesi

OrderService.java

package product.service;

import java.math.BigDecimal;
import java.util.List;

import product.domain.order.Order;

public interface OrderService {
	
	public void insertOrder(Order order);
	
	public List<Order> getOrderList();
	
	public BigDecimal getOrdersTotalAmount();
	
	public List<Object[]> getOrdersTotalAmountByCustomerName();
}

OrderServiceImpl.java

package product.service;

import java.math.BigDecimal;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import product.dao.OrderDAO;
import product.domain.order.Order;

@Service
public class OrderServiceImpl implements OrderService {

	@Autowired
	private OrderDAO orderDAOImpl;

	@Transactional
	public void insertOrder(Order order) {
		orderDAOImpl.insertOrder(order);
	}

	@Override
	@Transactional
	public List<Order> getOrderList() {
		return orderDAOImpl.getOrderList();
	}

	@Override
	@Transactional
	public BigDecimal getOrdersTotalAmount() {
		return orderDAOImpl.getOrdersTotalAmount();
	}

	@Override
	@Transactional
	public List<Object[]> getOrdersTotalAmountByCustomerName() {
		return orderDAOImpl.getOrdersTotalAmountByCustomerName();
	}
}

ProductService.java

  • Tum Urunleri listeleme
  • Tum Urunleri ve Condimentsleri listeleme
  • Tum Condimentleri listeleme
  • Urunu id ye gore getirme
  • Category’e gore urunleri getirme
  • Urun ekleme
  • Urun silme
  • Urun guncelleme islemleri yapilmaktadir.
package product.service;

import java.util.List;
import java.util.Map;

import product.domain.Product;

public interface ProductService {

	public List<Product> getAllProducts();

	public List<Product> getAllProductsAndCondiments();

	public Map<Integer, Product> getAllCondiments();

	public Product getProductById(int id);

	public List<Product> getProductsByCategory(String category);

	public void addProduct(Product product);

	public void deleteProduct(int id);

	public void updateProduct(Product product);

}

ProductServiceImpl.java

package product.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import product.dao.ProductRepositoryDAO;
import product.domain.Product;

@Service
public class ProductServiceImpl implements ProductService {

	@Autowired
	private ProductRepositoryDAO productRepository;

	@Transactional
	@Override
	public List<Product> getAllProductsAndCondiments() {
		return productRepository.getAllProductsAndCondiments();
	}

	@Transactional
	@Override
	public List<Product> getAllProducts() {
		return productRepository.getAllProducts();
	}

	@Transactional
	@Override
	public Map<Integer, Product> getAllCondiments() {

		List<Product> results = productRepository.getAllCondiments();

		Map<Integer, Product> map = new HashMap<Integer, Product>();
		for (Product product : results) {
			map.put(product.getId(), product);
		}
		return map;

	}

	@Transactional
	@Override
	public Product getProductById(int productID) {
		return productRepository.getProductById(productID);
	}

	@Transactional
	@Override
	public List<Product> getProductsByCategory(String category) {
		return productRepository.getProductsByCategory(category);
	}

	@Transactional
	@Override
	public void addProduct(Product product) {
		productRepository.addProduct(product);
	}

	@Override
	@Transactional
	public void deleteProduct(int id) {
		productRepository.deleteProduct(id);

	}

	@Override
	@Transactional
	public void updateProduct(Product product) {
		productRepository.updateProduct(product);
	}

}

ProductCartService.java

  • Shopping Cart’a product/urun ekleme , urun silme
  • Condiment/eklenti ekleme/silme
  • Discount/indirimleri ve amount hesaplama islemleri yapilmaktadir.
package product.service;

import java.math.BigDecimal;
import java.util.Map;
import java.util.TreeMap;

import product.domain.Product;
import product.domain.ShoppingCartData;

public interface ProductCartService {

	public void addProductToShoppingCart(ShoppingCartData data);

	public void deleteProductFromShoppingCart(ShoppingCartData data);

	public void deleteAllProductFromShoppingCartByProductId(ShoppingCartData data);

	public void addCondimentToProductInShoppingCart(ShoppingCartData data);

	public void deleteCondimentFromProductInShoppingCart(ShoppingCartData data);

	public TreeMap<Integer, BigDecimal>  calculateProductsSumByIdInShoppingCart(Map<Integer, TreeMap<Integer, Product>> shoppingCart);

	public BigDecimal calculateProductsSumAllInShoppingCart(TreeMap<Integer, BigDecimal> sumByProductId);
	
	public BigDecimal calculateDiscount(Map<Integer, TreeMap<Integer, Product>> shoppingCart);
}

ProductCartServiceImpl.java

package product.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.springframework.stereotype.Service;

import product.domain.CondimentDecorator;
import product.domain.Product;
import product.domain.ShoppingCartData;

@Service
public class ProductCartServiceImpl implements ProductCartService {

	@Override
	public void addProductToShoppingCart(ShoppingCartData data) {

		TreeMap<Integer, Product> productMap = data.getShoppingCart().get(data.getProduct().getId());
		if (productMap == null) {
			productMap = new TreeMap<Integer, Product>();
		}

		int count = 0;
		if (productMap.size() > 0) {
			count = productMap.lastKey();
		}

		productMap.put(++count, data.getProduct());
		data.getShoppingCart().put(data.getProduct().getId(), productMap);

	}

	public TreeMap<Integer, BigDecimal> calculateProductsSumByIdInShoppingCart(
			Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		TreeMap<Integer, BigDecimal> sumByProductId = new TreeMap<Integer, BigDecimal>();

		for (Map.Entry<Integer, TreeMap<Integer, Product>> productsByIds : shoppingCart.entrySet()) {

			BigDecimal totalPriceByProductId = new BigDecimal(0);

			TreeMap<Integer, Product> mapByProductId = productsByIds.getValue();

			for (Map.Entry<Integer, Product> entry : mapByProductId.entrySet()) {
				totalPriceByProductId = totalPriceByProductId.add(entry.getValue().getPrice());
				sumByProductId.put(productsByIds.getKey(), totalPriceByProductId);
			}

		}

		for (Map.Entry<Integer, BigDecimal> abc : sumByProductId.entrySet()) {
			System.out.println("product id : " + abc.getKey() + " total : " + abc.getValue());
		}

		return sumByProductId;

	}

	public BigDecimal calculateProductsSumAllInShoppingCart(TreeMap<Integer, BigDecimal> sumByProductId) {

		BigDecimal total = new BigDecimal(0);

		for (Map.Entry<Integer, BigDecimal> entry : sumByProductId.entrySet()) {
			total = total.add(entry.getValue());
		}

		return total;
	}

	@Override
	public BigDecimal calculateDiscount(Map<Integer, TreeMap<Integer, Product>> shoppingCart) {

		List<BigDecimal> priceList = new ArrayList<BigDecimal>();

		BigDecimal totalPrice = new BigDecimal(0);

		for (Map.Entry<Integer, TreeMap<Integer, Product>> productsByIds : shoppingCart.entrySet()) {

			TreeMap<Integer, Product> mapByProductId = productsByIds.getValue();

			for (Map.Entry<Integer, Product> entry : mapByProductId.entrySet()) {

				Product product = entry.getValue();
				totalPrice = totalPrice.add(product.getPrice());
				priceList.add(product.getPrice());

			}

		}

		BigDecimal reducedPriceByProductCount = totalPrice; // default total
															// price
		
		//TODO , make it dynamic by properties
		if (priceList.size() >= 3) {
			BigDecimal minimumPriceInShoppingCart = Collections.min(priceList);
			reducedPriceByProductCount = totalPrice.subtract(minimumPriceInShoppingCart);
		}
		
		BigDecimal reducedPriceByPercentage = totalPrice; // detault total price
		if (totalPrice.compareTo(new BigDecimal(12)) > 0) {
			BigDecimal remainder = totalPrice.divide(new BigDecimal(4));
			reducedPriceByPercentage = totalPrice.subtract(remainder);
		}

		if (reducedPriceByPercentage.compareTo(reducedPriceByProductCount) < 0) {
			return reducedPriceByPercentage;
		} else {
			return reducedPriceByProductCount;
		}
	}

	@Override
	public void deleteProductFromShoppingCart(ShoppingCartData data) {
		TreeMap<Integer, Product> productMap = data.getShoppingCart().get(data.getProduct().getId());
		productMap.remove(data.getOrderIndexId());

	}

	@Override
	public void deleteAllProductFromShoppingCartByProductId(ShoppingCartData data) {
		data.getShoppingCart().remove(data.getProduct().getId());
	}

	public void addCondimentToProductInShoppingCart(ShoppingCartData data) {

		TreeMap<Integer, Product> productMap = data.getShoppingCart().get(data.getProduct().getId());
		Product selectedProductForCondimentProcess = productMap.get(data.getOrderIndexId());

		Product condiment = data.getAllCondimentsInShop().get(data.getCondimentId());

		selectedProductForCondimentProcess = new CondimentDecorator(selectedProductForCondimentProcess,
				condiment.getName(), condiment.getDescription(), condiment.getPrice(),
				selectedProductForCondimentProcess.getCondimentsInProduct());

		Map<Product, Integer> map = selectedProductForCondimentProcess.getCondimentsInProduct();

		Integer count = map.get(condiment);

		if (count == null) {
			count = 0;
		}

		selectedProductForCondimentProcess.getCondimentsInProduct().put(condiment, ++count);

		productMap.put(data.getOrderIndexId(), selectedProductForCondimentProcess);

	}

	@Override
	public void deleteCondimentFromProductInShoppingCart(ShoppingCartData data) {

		TreeMap<Integer, Product> productMap = data.getShoppingCart().get(data.getProduct().getId());
		Product selectedProductForCondimentProcess = productMap.get(data.getOrderIndexId());

		Product condiment = data.getAllCondimentsInShop().get(data.getCondimentId());

		Map<Product, Integer> map = selectedProductForCondimentProcess.getCondimentsInProduct();

		Integer count = map.get(condiment);

		selectedProductForCondimentProcess = new CondimentDecorator(selectedProductForCondimentProcess,
				condiment.getName(), condiment.getDescription(),
				(condiment.getPrice().multiply(new BigDecimal(count)).negate()),
				selectedProductForCondimentProcess.getCondimentsInProduct());

		selectedProductForCondimentProcess.getCondimentsInProduct().remove(condiment);

		productMap.put(data.getOrderIndexId(), selectedProductForCondimentProcess);

	}

}

DAO Layer

OrderDAO.java

package product.dao;

import java.math.BigDecimal;
import java.util.List;

import product.domain.order.Order;

public interface OrderDAO {

	public void insertOrder(Order order);
	
	public List<Order> getOrderList();
	
	public BigDecimal getOrdersTotalAmount();
	
	public List<Object[]> getOrdersTotalAmountByCustomerName();
}

OrderDAOImpl.java

package product.dao;

import java.math.BigDecimal;
import java.util.List;

import javax.persistence.TypedQuery;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import product.domain.order.Order;

@Repository
public class OrderDAOImpl implements OrderDAO {
	@Autowired
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	private Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void insertOrder(Order order) {
		Session session = getCurrentSession();
		session.persist(order);
	}

	@Override
	public List<Order> getOrderList() {
		Session session = getCurrentSession();
		TypedQuery<Order> query = session.createQuery("from CustomerOrder", Order.class);
		return query.getResultList();

	}

	@Override
	public BigDecimal getOrdersTotalAmount() {
		Session session = getCurrentSession();
		TypedQuery<BigDecimal> query = session.createQuery("Select sum(o.amount) from CustomerOrder o",
				BigDecimal.class);
		return query.getSingleResult();
	}

	public List<Object[]> getOrdersTotalAmountByCustomerName() {
		Session session = getCurrentSession();
		TypedQuery<Object[]> query = session.createQuery(
				"Select o.customer.customerName , sum(o.amount) from CustomerOrder o group by o.customer.customerName",
				Object[].class);
		return query.getResultList();
	}
}

ProductRepositoryDAO.java

package product.dao;

import java.util.List;

import product.domain.Product;

public interface ProductRepositoryDAO {

	public List<Product> getAllProducts();

	public List<Product> getAllCondiments();

	public List<Product> getAllProductsAndCondiments();

	public Product getProductById(int productID);

	public List<Product> getProductsByCategory(String category);	

	public void addProduct(Product product);

	public void deleteProduct(int id);

	public void updateProduct(Product product);
		
}

ProductRepositoryDAOImpl.java

package product.dao;

import java.util.List;

import javax.persistence.TypedQuery;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import product.domain.Product;

@Repository
public class ProductRepositoryDAOImpl implements ProductRepositoryDAO {

	@Autowired
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	private Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public List<Product> getAllProductsAndCondiments() {
		Session session = getCurrentSession();
		TypedQuery<Product> query = session.createQuery("from Product", Product.class);
		return query.getResultList();
	}

	@Override
	public List<Product> getAllProducts() {
		Session session = getCurrentSession();
		TypedQuery<Product> query = session.createQuery("from Product where isCondiment = false", Product.class);
		return query.getResultList();
	}

	@Override
	public List<Product> getAllCondiments() {
		Session session = getCurrentSession();
		TypedQuery<Product> query = session.createQuery("from Product where isCondiment = true", Product.class);
		return query.getResultList();
	}

	@Override
	public Product getProductById(int id) {
		Session session = getCurrentSession();
		Product product = session.get(Product.class, id);
		return product;
	}

	@Override
	public List<Product> getProductsByCategory(String category) {
		Session session = getCurrentSession();
		TypedQuery<Product> query = session.createQuery("from Product p where p.category =:category", Product.class)
				.setParameter("category", category);
		return query.getResultList();
	}

	@Override
	public void addProduct(Product product) {
		Session session = getCurrentSession();
		session.persist(product);
	}

	@Override
	public void deleteProduct(int id) {
		Session session = getCurrentSession();
		Product p = (Product) session.get(Product.class, id);
		System.out.println(p);
		if (p != null) {
			session.delete(p);
		}

	}

	@Override
	public void updateProduct(Product product) {
		Session session = getCurrentSession();
		session.update(product);
	}

}

Utility

Projemizde URL adreslerini ve View’leri toplu olarak siniflarda tanimlayabiliriz.

URLs.java

package product.utility;

public interface URLs {

	public static final String MENU = "/menu";
	public static final String ALL = "/all";
	public static final String CATEGORY = "/{category}"; // URI template
	public static final String PRODUCT_DETAIL = "/product.detail";
	public static final String PRODUCT_ADD_TO_CART = "/product.add.to.cart";
	public static final String PRODUCT_DELETE_FROM_CART = "/product.delete.from.cart";
	public static final String PRODUCT_DELETE_ALL_CART = "/product.delete.all.cart";
	public static final String PRODUCT_ADD_CONDIMENT = "/product.add.condiment";
	public static final String PRODUCT_DELETE_CONDIMENT = "/product.delete.condiment";
	public static final String PRODUCT_SHOPPING_CART = "/product.shopping.cart";
	public static final String ORDER_DELETE_FROM_CART = "/order.delete.from.cart";

	public static final String DEFAULT_URL = "/";

	// CRUD menu
	public static final String ADMIN_LOGIN ="/login.admin";
	public static final String PRODUCT_ADD = "/product.add";
	public static final String PRODUCT_EDIT = "/product.edit";
	public static final String PRODUCT_UPDATE = "/product.update";
	public static final String PRODUCT_DELETE = "/product.delete";
	
	//PAYMENT
	public static final String ORDER_PAYMENT = "/order.payment";
	public static final String ORDER_PAYMENT_CONFIRM = "/order.payment.confirm";
	public static final String ORDER_PAYMENT_SUCCESS ="/order.payment.success";
	public static final String ORDER_LIST ="/order.list";
}

ViewURLs.java

package product.utility;

public interface ViewURLs {

	public static final String PRODUCT_LIST_VIEW = "product.views/productList";
	public static final String PRODUCT_DETAIL_VIEW = "product.views/productDetail";
	public static final String PRODUCT_DETAIL_VIEW_REDIRECT = "redirect:/menu/product.detail?productId=";
	public static final String PRODUCT_SHOPPING_CART_VIEW = "product.views/shoppingCart";
	public static final String PRODUCT_SHOPPING_CART_VIEW_REDIRECT = "redirect:/menu/product.shopping.cart";	
	
	public static final String PRODUCT_ADD_VIEW="product.views/addProduct";
	public static final String PRODUCT_ADD_VIEW_REDIRECT="redirect:/product.add";
	
	public static final String ORDER_PAYMENT_FORM_VIEW = "product.views/paymentForm";
	public static final String ORDER_PAYMENT_VIEW_SUCCESS ="product.views/paymentSuccess";
	public static final String ORDER_PAYMENT_VIEW_SUCCESS_REDIRECT ="redirect:/order.payment.success";
	
	public static final String ORDER_LIST_VIEW="product.views/orderList";
	
}

View Layer

View Layer’da JSP sayfalari kullanildi.
Ilerleyen zamanlarda guncelleme yapip , bu kisimlar icin de onemli noktalari aciklamalari ekleyecegim.
Simdilik icerikleri proje icerisinde bulabilirsiniz.

Log4j

log4j.properties

#all logs
log4j.rootLogger=INFO, file
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File= ${catalina.home}/logs/all.txt
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n


log4j.logger.auditLogger=INFO, auditLogger
log4j.appender.auditLogger=org.apache.log4j.RollingFileAppender
log4j.appender.auditLogger.File= ${catalina.home}/logs/audit.txt
log4j.appender.auditLogger.layout=org.apache.log4j.PatternLayout
log4j.appender.auditLogger.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %c : %m%n


log4j.logger.admin=INFO, admin
log4j.appender.admin=org.apache.log4j.RollingFileAppender
log4j.appender.admin.File= ${catalina.home}/logs/admin.txt
log4j.appender.admin.layout=org.apache.log4j.PatternLayout
log4j.appender.admin.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %c : %m%n

Run Application

Projemizi calistiralim ;
Projemiz sorunsuzca ayaga kalkti ve sql scriptleri ile ekledigimiz urunleri gormekteyiz.

run example1

Admin iconuna tiklayalim , CRUD menusune gidelim.
Bu menude Urun/Condiment(Eklenti) ekleme , silme , guncelleme islemlerini yapabiliriz.
Turkiye bayragina tiklarsak tum mesajlar TR olacaktir.

product crud

Ev iconuna tiklayip tekradan urunler sayfasina gelebiliriz , sonrasinda bir urunun detayina girerek ayni urunden birden fazla ekleyebilir , diledigimize istedigimiz eklentiyi istedigimiz sayida ekleyebiliriz.

product detail

 

Sepetim butonuna tikladigimizda , Sepete ekledigimiz urunleri toplu olarak gorebiliriz.
Burada urun fiyati ve ilgili senaryolara gore indirimli fiyati gorebiliriz.

shopping cart

Odeme sayfasina gidelim ;

payment

Son olarak Siparis Listelerini inceleyelim ;

order list

Yazimi burada sonlandiriyorum.
Herkese bol Javali gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *