Spring MVC – 09 – Beginning WebStore Implementation

Merhaba Arkadaslar
Bu bolumde basit bir WebStore uygulamasini gerceklestirecegiz.
Ilerleyen bolumlerde bu WebStore uzerinde gelistirmeler yapacagiz.

Burada su annotation’lari tekrar inceleyip daha iyi anlayalim.

  • @PathVariable
  • @RequestParam
  • @MatrixVariable

URI template patterns

Dusunelim , elimizde cesitli Urunler/Product olacak ve bu urunleri kategoriye gore listelemek istersek ne yapmamiz gerekli.
Ornegin laptop ve tablet gibi kategorilerimiz oldugunu dusunelim ;

http://localhost:8080/injavawetrust.springmvc/products/laptop
http://localhost:8080/injavawetrust.springmvc/products/tablet

Bu sekilde bir cok kategori olabilir , her bir URL’e karsilik bir @RequestMapping annotation tanimlayip metot kullanmamiz mumkun olmayacaktir.
Iste bu noktada bize yardimci olarak @PathVariable annotation’ini kullanabiliriz.

@RequestMapping("/category/{productCategory}")
public String listProductsByCategory(@PathVariable("productCategory") String productCategory, Model model) {
	model.addAttribute("products", productService.getProductsByCategory(productCategory));
	return "08.webstore.view/productList";
}

Kodu inceleyecek olursak ;

  • @RequestMapping annotation’ininda path bilgisini suslu parantezler (curly brace) arasinda yaziyoruz {productCategory}. Boylece bunun bir URI template variable oldugunu belirtiyoruz.
  • @PathVariable annotation’ini , @PathVariable(“productCategory”) String productCategory seklinde kullanabiliriz.
  • @PathVariable , URI template variable’i okumak icin kullanilir.
  • @RequestMapping ‘te tanimladigimiz URI template variable ismi ile (productCategory) , @PathVariable annotation’da kullandigimiz isim ayni olmalidir.
  • Eger @PathVariable annotation’da bir isim kullanilmazsa bu durumda variable ismiyle ayni isim olur. Yani su kodlar ayni anlama gelmektedir ;
    @PathVariable String productCategory
    @PathVariable(“productCategory”) String productCategory

Request Parameters

Simdi de GET request parametreleri Spring MVC de nasil kullanabilecegimizi inceleyelim. Dusunelim ki , Urun/Product detayini gormek istiyoruz. Bunun icin primary key olarak dusunebilecegimiz product id bilgisinden yararlanabiliriz. Bu bilgiyi Urun/Product icin URL sonuna request parameter olarak ekledigimizi dusunursek istedigimiz seyi elde edebiliriz. Bu noktada karsimiza @RequestParam annotation’ini cikmaktadir.

	@RequestMapping("/product")
	public String getProductById(@RequestParam(required = false, name = "id") String productId, Model model) {
		model.addAttribute("product", productService.getProductById(productId));
		return "08.webstore.view/productDetail";
	}

Kodu inceleyecek olursak ;

  • Oncelikle @RequestMapping annotation’ini metodumuzun basina ekliyoruz. Boylece ilgili request’ler icin bu metodu kullanabiliriz.
  • Daha sonrasinda @RequestParam annotation’ini ayni @PathVariable annotation’inda oldugu gibi kullaniyoruz.
    @RequestParam(“id”) String productId
  • Boylelikle Request Parameter’lari @RequestParam annotation yardimiyla ilgili degiskenlere baglamis/iliskilendirmis/bind oluruz.

Matrix Variable

Son olarak inceleyecegimiz ozellik Matrix Variable olacaktir. Dusunelim , ornegin brand ve category degerlerine gore ( bi birden fazla brand ya da category secmek isteriz) Urun/Product listelemek istersek bu durumda bu filtreleme yapisini nasil yapabiliriz.
Iste bu noktada Spring MVC @MatrixVariable annotation’i bizim icin cozum sunacaktir.

Burada basit olarak brand’e gore filtreleme yapisini entegre edelim.

@RequestMapping("/brand/{brands}")
public String listProductsByBrands(@MatrixVariable(pathVar = "brands") List<String> brands, Model model) {
	model.addAttribute("products", productService.getProductsByBrands(brands));
	return "08.webstore.view/productList";
}

Kodu inceleyecek olursak ;

  • @PathVariable annotation taniminda oldugu gibi Matrix Variable icin de curly brace kullaniyoruz. {brands}
  • @MatrixVariable(pathVar = “brands”) List<String> brands seklinde metot deklarasyonunda @MatrixVariable annotation’ini kullaniyoruz.

Application

Simdi de uygulamiza daha yakindan goz atalim;

Domain

Bu ornegimizde Product isminde bir sinif kullaniyoruz.

Product.java

package _08.webstore.domain;

public class Product {

	private String productId;
	private String name;
	private double unitPrice;
	private String description;
	private String manufacturer;
	private String category;
	private long unitsInStock;
        //getters and setters
        //constructors
...
}

Data Access Object Layer (DAO)

DAO katmaninda su metotlar yer alacaktir ;
tum urunleri getirdigimiz (getAllProducts)
productId degerine gore ilgili urunu getirdigimiz (getProductById)
category degerine gore tum urunleri getirdigimiz (getProductsByCategory)
brand’e gore filtreleme yaptigimiz (getProductsByBrands)

ProductRepositoryDAO.java

package _08.webstore.dao;

import java.util.List;
import _08.webstore.domain.Product;

public interface ProductRepositoryDAO {

	public List<Product> getAllProducts();

	public Product getProductById(String productID);

	public List<Product> getProductsByCategory(String category);

	public List<Product> getProductsByBrands(List<String> brands);
}

ProductRepositoryDAOImpl.java

package _08.webstore.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.springframework.stereotype.Repository;

import _08.webstore.domain.Product;

@Repository
public class ProductRepositoryDAOImpl implements ProductRepositoryDAO {

	private List<Product> listOfProducts = new ArrayList<Product>();

	public ProductRepositoryDAOImpl() {

		Product iphone = new Product("P1001", "iPhone 5s", 549.99);
		iphone.setDescription("Apple iPhone 5s smartphone with 4.00-inch 640x1136 display and 8-megapixel rear camera");
		iphone.setCategory("SmartPhone");
		iphone.setManufacturer("Apple");
		iphone.setUnitsInStock(1000);

		//more products
		listOfProducts.add(laptopDell);
		//addd
		listOfProducts.add(laptopAppleMacbook);

	}

	@Override
	public List<Product> getAllProducts() {
		return listOfProducts;
	}

	@Override
	public Product getProductById(String productId) {
// Old way		
//		Product foundProductById = null;
//		for (Product product : listOfProducts) {
//			if (product.getProductId().equals(productId)) {
//				foundProductById = product;
//				break;
//			}
//		}
//		return foundProductById;

		Predicate<Product> predicate = (Product p) -> p.getProductId().equals(productId);
		Product foundProduct = listOfProducts.stream().filter(predicate).findAny().orElse(null);

		return foundProduct;
	}

	@Override
	public List<Product> getProductsByCategory(String category) {
		
// Old way
//		List<Product> productsByCategory = new ArrayList<Product>();
//
//		for (Product product : listOfProducts) {
//			if (category.equalsIgnoreCase(product.getCategory())) {
//				productsByCategory.add(product);
//			}
//		}
//
//		return productsByCategory;

		Predicate<Product> predicate = (Product product) -> product.getCategory().equalsIgnoreCase(category);
		List<Product> filtered = listOfProducts.stream().filter(predicate).collect(Collectors.toList());
		return filtered;
	}

	@Override
	public List<Product> getProductsByBrands(List<String> brands) {
		
// Old way
//		List<Product> productsByBrand = new ArrayList<Product>();
//		for (String brandName : brands) {
//			for (Product product : listOfProducts) {
//				if (brandName.equalsIgnoreCase(product.getManufacturer())) {
//					productsByBrand.add(product);
//				}
//			}
//		}
//      return productsByBrand;

		Predicate<Product> predicate = (Product product) -> brands.contains(product.getManufacturer().toLowerCase());
		List<Product> filtered = listOfProducts.stream().filter(predicate).collect(Collectors.toList());		
		return filtered;

	}
}

Service Layer

Controller’lardan direkt olarak DAO katmanina erisim olmamalidir. Bunun yerine Controller siniflari Service Layer’a erismelidir.
Servive Layer da DAO Layer’a erismelidir. Bu konuda bilgileri onceki yazilarda vermistim.

ProductServiceImpl.java

package _08.webstore.service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import _08.webstore.dao.ProductRepositoryDAO;
import _08.webstore.domain.Product;

@Service
public class ProductServiceImpl implements ProductService {

	@Autowired
	private ProductRepositoryDAO productRepository;

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

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

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

	@Override
	public List<Product> getProductsByBrands(List<String> brands) {
		return productRepository.getProductsByBrands(brands);
	}

}

Web Layer / Controller

ProductController sinifimizi parca parca incelemistik

ProductController.java

package _08.webstore.controller;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import _08.webstore.service.ProductService;

@Controller
@RequestMapping("/products")
public class ProductController {

	@Autowired
	private ProductService productService;

	@RequestMapping
	public String list(Model model) {
		model.addAttribute("products", productService.getAllProducts());
		return "08.webstore.view/productList";
	}

	@RequestMapping("/all")
	public ModelAndView listAllProducts() {
		ModelAndView modelAndView = new ModelAndView();

		modelAndView.addObject("products", productService.getAllProducts());
		modelAndView.setViewName("08.webstore.view/productList");
		return modelAndView;
	}

	@RequestMapping("/category/{productCategory}")
	public String listProductsByCategory(@PathVariable("productCategory") String productCategory, Model model) {
		model.addAttribute("products", productService.getProductsByCategory(productCategory));
		return "08.webstore.view/productList";
	}

	@RequestMapping("/product")
	public String getProductById(@RequestParam(required = false, name = "id") String productId, Model model) {
		model.addAttribute("product", productService.getProductById(productId));
		return "08.webstore.view/productDetail";
	}

	@RequestMapping("/brand/{brands}")
	public String listProductsByBrands(@MatrixVariable(pathVar = "brands") List<String> brands, Model model) {
		model.addAttribute("products", productService.getProductsByBrands(brands));
		return "08.webstore.view/productList";
	}

}

Maven Dependency

JSP sayfalarimizda JSTL taglarini kullanacagiz ilgili dependency tanimini ekleyelim ;

pom.xml

<properties>
	....
	<jstl.version>1.2</jstl.version>
	...
</properties>

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

View

Bu uygulamada Bootstrap kullanacagiz. JSP dosyalarinda yer alan kodlarinda dikkat etmemiz gereken bir kac noktayi inceleyecek olursak ;

JSTL taglarini kullanabilmek icin oncelikle taglib directive tanimini yapiyoruz.
Daha sonrasida linklerde kullanabilecegimiz <c:set> tagiyla attribute’ler ekliyoruz.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<c:set var="productUrlAll" value="${pageContext.request.contextPath}/products/all"/>
<c:set var="productUrlCategory" value="${pageContext.request.contextPath}/products/category"/>
<c:set var="matrixUrl" value="${pageContext.request.contextPath}/products/brand"/>

Projemizde css ve js dosyalari WebContent/resources altinda yer alacak. Ilgili dizinlerdeki dosyalari gosteriyoruz. Bununla birlikte ek bir konfigurasyon yapmamiz gerekli. Yazinin ilerleyen bolumunde bahsedecegim.

 
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/resources/css/sidebar.css" />" /> 
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/resources/css/bootstrap.min.css" />" />
<script src="<c:url value="/resources/js/jquery.min.js" />"></script>
	

Matrix Variable’lar icin link’i tekrar duzenlemek icin basit bir Javascript function yazalim.

function prepareMatrix(){
	
	var selectedBrands="";
	$('input:checkbox[name=brand]').each(function() 
		{    
			if($(this).is(':checked'))
				selectedBrands=selectedBrands+$(this).val()+",";
		});
	

	var url= '${matrixUrl}/brands='+selectedBrands;
		
	$("#search").attr("href", url);

}
</script>

XML Configuration

Son olarak XML dosyamizi inceleyelim ;

  • Oncelikle Matrix Variable ozelligini aktif etmek icin <mvc:annotation-driven> tagini kullaniyoruz.
  • <mvc:annotation-driven> tagini kullanabilmek ek olarak xlms ve xsi:schemaLocation eklememiz gereklidir.
  • css ve js dosyalarini JSP dosyamizda kullanabilmek icin <mvc:resources> annotation ile ilgili location bilgisini veriyoruz.

08.webstore.xml

<?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
        ">

	<!-- enabled matrix variable -->
	<mvc:annotation-driven	enable-matrix-variables="true"/>
	
	<mvc:resources mapping="/resources/**" location="resources/"/>
	
	<context:component-scan base-package="_08.webstore" />
	
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/" />
		<property name="suffix" value=".jsp" />
	</bean>
	
	<bean id= "messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
   		<property name="basename" value="messages"/> 
	</bean>

</beans>

Son olarak web.xml dosyamiza contextConfigLocation olarak 08.webstore.xml bilgisini verelim.

web.xml

..
	<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/01.appContext.xml
			 /WEB-INF/02.00.appContext.xml
			--> 			 					 
			 /WEB-INF/08.webstore.xml
			 <!-- 	 									 		 	 				 
			 							 
			 	-->	
			</param-value> 
		 </init-param>

		<load-on-startup>1</load-on-startup>
	</servlet>
...

Run Application

Ornegimizi calistiralim ;

http://localhost:8080/injavawetrust.springmvc/products/all

Laptops , Tablets , Smart Phone linklerinden birine tikladigimizda ilgili category’de yer alan urunler listelenecektir.
Bunun icin @PathVariable annotation’dan yararlandik.

<li class="">
	<a href="${productUrlAll}">All Products</a>
</li>
<li>
	<a href="${productUrlCategory}/laptop">Laptops</a>
</li>
<li class="">
	<a href="${productUrlCategory}/tablet">Tablets</a>
</li>
<li class="">
	<a href="${productUrlCategory}/smartPhone">Smart Phones</a>
</li>

Bir diger test olarak Details linkine tikladigimizda ilgili Urun/Product’a ait detail sayfasi gelecektir.
Bunun icin @RequestParam annotation da yararlandik.

<a
	href=" <c:url value="/products/product?id=${product.productId}" /> "
	class="btn btn-primary"> <span
	class="glyphicon-info-sign glyphicon" /></span> Details
</a>

request mapping2

Bir diger test olarak Side Barda yer alan ilgili checboxlar secildiginde filtreleme yapacaktir. Bunun icin @MatrixVariable annotationdan yararlaniyoruz.

Github kaynak kodlar / source folder
Injavawetrust-springmvc-tutorial

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 *