Spring Framework - Hibernate - JSP kullanımı

Bu yazıda Spring Boot kullanmadan Spring Framework ve Hibernate ile JSP sayfalarını kullanan bir web mvc uygulamasını nasıl oluşturabileceğinizi göstereceğim. Tabi ki uygulamayı maven ile oluşturacağım. Bu sayede bu projeyi kendinize iskelet olarak alıp üzerinde geliştirme yapabileceksiniz. Peki neden spring boot değil de sadece spring framework?

Günümüzde tabi ki mvc uygulaması dediğimizde aklımıza spring boot uygulamaları geliyor ve bu benim de benimsediğim bir yaklaşım. Fakat spring boot mvc projeleri ağırlıklı olarak html sayfaları ile entegre olmuş durumda. Bu yüzden JSP veya JSF gibi başka frontend teknolojilerinde bazı eksikleri var. Detaylar için spring boot jsp limitations 'a bakabilirsiniz. Ayrıca bir spring boot uygulaması kendi oto konfigürasyonları sebebiyle gereğinden fazla ram kullanımına veya büyük output dosyalarına da sebep olabiliyor. Son olarak da eski alışkanlıklarını terk edemeyen büyük projelerde hala spring framework ve jsp servlet yapıları kullanılıyor. Bu sebeplerden dolayı bu uygulama çoğunlukla yenilenmesi gereken eski projelere güncel bir iskelet olabilmesi için yazıldı. Günümüzde spring framework uygulamaları için gereken minimal işlevleri sağlayacak düzgün bir archetype da bulamadığım için bu uygulama örneğinin faydalı olacağını düşünüyorum.

Hibernate ise zaten günümüzde ORM aracı olarak sıklıkla kullanılan ve bizi jdbc ile sql ve connection yönetimi derdinden kurtaran bir teknoloji. Bu yüzden ben de bu projeye dahil ettim ve ayarlarını hazırladım. Bu sayede spring boot uygulamalarında bizim için arka planda otomatik konfigüre edilen ayarların spring framework 'de nasıl yapılacağını da görmüş olacağız. Bu yapıyı bir "book" sınıfını veritabanına insert edip okuyarak örneklendireceğim. Bir nevi kickstarter proje gibi olacak.

Yazının içerisinde çoğunlukla kodları paylaşacağım ve kodların içinde yorum satırları olacak. Dilerseniz proje kodlarına github 'dan ulaşabilirsiniz. Bu projeyi ayağa kaldırabilmek ve anlayabilmek için gerekecek olan araç ve bilgi birikimi ise aşağıdaki listedeki gibi.

  • Spring Framework, Maven ve JSP bilgisi
  • Java 8 veya java 11 'in bilgisayarınızda kurulu olması
  • Eclipse veya Intellij tercih ederseniz bir IDE
  • Eğer eclipse kullanıyorsanız Lombok için bir plugin kurmanız da gerekecektir
  • Postgresql veya tercih ettiğiniz başka bir RDBMS teknolojisi

Projenin oluşturulması

Bu projeyi sıfırdan oluşturmak isterseniz bir maven projesini aşağıdaki resimdeki gibi maven-archetype-webapp archetype 'ı ile oluşturabilirsiniz. Bu şekilde bir web uygulamasının gereklilikleri olan webapp ve WEB-INF klasörleri ve web.xml dosyası da oluşmuş olacaktır. Spring boot gibi hazır bir yapı kullanamadığımız ve günümüzde spring framework ve hibernate ve jsp kullanan güncel ve sade bir archetype bulamadığımız için bu noktadan başlamak gerekiyor.

Proje oluşturulduktan sonra temelde aşağıdaki adımları izlememiz gerekiyor.

  • Pom.xml dosyasında spring, hibernate ve JSP için gerekli bağımlılıkları eklemek
  • web.xml dosyasında spring dispatcherservlet ayarı yapmak
  • -servlet.xml dosyasında mapping ayarları yapmak
  • Bu noktada <context:component-scan base-package="com.myproject" /> ifadesini unutmamak :)
  • Bu archetype 'da src/main klasöründe java klasörü oluşmayabiliyor, kontrol edip yoksa oluşturmak
  • ViewResolver ve Datasource bean 'lerini bir @Component sınıfında oluşturmak
  • Spring @Controller sınıfında mapping ayarları yapmak

Bu silsileyi takip edebilmeniz için önemli kodları göstereyim.

pom.xml dosyası ve minimum gereksinimler

Bize lazım olan minimal pom dosyası ile başlayalım. Bu projede spring boot gibi parent pom kullanmadığımız için 2 plugin 'i manuel olarak belirttik. Maven compiler ile projenin java versiyonunu belirttik. War plugin ile war dosyası çıkarmak için gereken plugin 'i ekledik. Uygulama çıktı olarak bize war dosyası oluşturacak.

Spring-webmvc bağımlılığı ile sadece spring web değil MVC özelliklerini de almış olduk. Mesela ModelAndView sınıfı gibi. Spring-orm ise sprind jdbc ve transaction 'ın birleşimi ve üzerine ekstra olarak hibernate ile konuşmasını sağlayacak sınıflar eklenmiş. Bu proje spring data jpa kullanmıyor, hibernate üzerinde kendimiz işlem yapıyoruz. Repository sınıflarından görebilirsiniz. Zaten hemen aşağıda hibernate-core görüyorsunuz. Burada spring-orm ile kullandığınız hibernate versiyonu uyumlu olmalı. Yakın zamanda javax paketleri de jakarta olacak çünkü. jstl ise arayüzde jsp tag 'leri kullandığımız için gerekiyor. Nasıl thymeleaf kullanırken thymeleaf 'in jar dosyalarını dependency olarak alıyorsak, burada da java standard tag library için bir bağımlılık kullanmamız gerekiyor. postgresql ise benim kullandığım veritabanı olduğu için burada. Siz oracle, mysql, mssql gibi veritabanlarına çevirebilirsiniz.

			
<build>
	<plugins>
		<plugin>
			<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-compiler-plugin -->
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.8.1</version>
			<configuration>
				<source>1.8</source>
				<target>1.8</target>
			</configuration>
		</plugin>
		<plugin>
			<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-war-plugin -->
			<artifactId>maven-war-plugin</artifactId>
			<version>3.3.2</version>
		</plugin>
	</plugins>
</build>
<dependencies>
	<!-- spring web mvc covers all you need from spring to serve as web application
	with context and beans and all that jazz
	otherwise you would need bean, core, context, aop, web, expresion dependencies -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- spring orm is basically spring TX + spring JDBC + some special classes
	Not relying on spring data jpa or anything, this project is hardcore hibernate
	WATCH OUT for compatibilities, spring5.3 says it is compatible with hibernate 5.2/5.3/5.4 -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-orm</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- JSTL library to be able to render JSP pages tags-->
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>jstl</artifactId>
		<version>1.2</version>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-core</artifactId>
		<version>5.6.3.Final</version>
	</dependency>
	<dependency>
		<groupId>org.postgresql</groupId>
		<artifactId>postgresql</artifactId>
		<version>42.3.1</version>
	</dependency>
</dependencies>
			
		

Web.xml ve servlet.xml dosyalarının hazırlanması

Web.xml dosyasında dikkat edeceğimiz birkaç nokta var. Birincisi yukarıdaki namespace 'ler. Burada hata olursa gerekli ayarları yaparken hata veriyor ve tag 'leri göremeyebiliyor. Hemen atlında servlet tanımı görüyoruz. Spring framework tarafından geliştirilen HttpServlet extension 'ı olan DispatcherServlet 'i kullanıyoruz tabi. Aynı servlet ismi ile altında mapping bilgileri tanımlıyoruz. Bu sayede gelen url 'ler bu servlet 'e yönlendiriliyor. Burada da /* path 'i veremiyoruz, çünkü aksi takdirde servlet sonsuz döngüye girebiliyor veya bütün forward 'ları veya return 'leri tekrar kendisi handle etmeye çalışabiliyor.

			
<?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_4_0.xsd" id="WebApp_ID" version="4.0">
	<servlet>
		<servlet-name>defaultservlet</servlet-name>
		<!-- Servlet xml name must be defaultservlet-servlet.xml because of the naming convention of webapps -->
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>defaultservlet</servlet-name>
		<!-- DON'T change it to (/*) -->
		<!-- otherwise it will keep looking for get or post mapping urls in your controllers instead of returning the jsp pages -->
		<!-- Also, all my JSP files are in the same folder, so all i need is one / url mapping here -->
		<!-- otherwise you would need different patterns like /book /user /shop ..etc -->
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>
			
		

Servlet adı defaultservlet olduğu için defaultservlet-servlet.xml dosyası oluşturuyoruz. Bu format sabit bir format çünkü. Burada da xml namespace 'leri önemli. Burada bean 'ler oluşturulur ve gerekli context ayarları yapılır. Transaction veya MVC veya viewresolver veya datasource gibi ayarlar da burada yapılabilirdi. Ben beanfactory sınıfına taşıdım bu ayarları. Spring framework için en önemli özelliğimiz burada context:component-scan bilgisi. Burada @Component, @Repository, @Service, @Configuration şeklinde bütün classlarımın hangi pakette ve atlında olduğunu belirtiyorum.

			
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- Don't forget the schemas, otherwise you can't use mcv or context or bean definitions here -->
	<context:component-scan base-package="com.numankaraaslan" />
	<!-- If you forget component-scan property here, spring will not be able to scan your controllers or beans or stereotypes -->
	<!-- You can also initialize all the beans and transaction settings here, i did it in BeanFactory class -->
</beans>
			
		

Bean factory sınıfı ve gerekli bean 'ler

Bu aşamada servlet.xml dosyasını kalabalıklaştırmak yerine java kodu ile anlaşılabilir bean 'ler oluşturmaya karar verdim. ÖNCELİKLE import 'lara dikkat ediniz. Aşağıdaki sınıftaki ViewResolver isimli bean ile Controller tarafından "hello" döndürürsem spring framework benim webapp klasörümün içinde "jsp" klasörümde "hello.jsp" isimli dosyayı görüntülesin ayarını yapıyoruz. Projenin klasör yapısına dikkat!

Datasource bean 'i ise postgresql tarafındaki veritabanı bağlantı bilgilerimiz. Bu datasource 'dan ayrıca hibernate 'in nasıl davranacağını söylediğimiz bir LocalSessionFactoryBean oluşturuyoruz. Bu bean spring-orm tarafından geliyor. setHibernateProperties metodu ile aşağıdaki metodda tanımladığımız propertiy 'leri veriyoruz. Bu property 'lerde hbm2ddl.auto yani tabloların uygulama ayağa kaldırılırken otomatik oluşturulması ve dialect önemlidir. Dialect kullandığınız postgresql versiyonu ile uyumlu olmalıdır. Dilerseniz bütün bu ayarları da bir "hibernate.cfg.xml" dosyasından okuyacak hale getirebilirsiniz.

Son olarak HibernateTransactionManager da spring-orm tarafından geliyor ve hibernate ile veriye ulaşırken metodların başında @Transactional yazdığımızda bizim transaction 'ımızı kimin yöneteceğini belirtiyor. Buradaki dependsOn ilişkilerine dikkat. Ayrıca sınıfın başında @EnableTransactionManagement ifadesi de bu uygulamanın transaction 'ları yönetmesi gerektiği anlamına geliyor. Ben transaction 'ları yönetemeyecek kadar tembelim demek aslında. Bu sınıf için de minimal konfigürasyonumuz bu kadar.

			
import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;

@Configuration
// this is tx:annotation-driven
@EnableTransactionManagement
public class BeanFactory
{
	// All these can be defined in defaultservlet-servlet file
	// tx:annotation-driven and bean definitions ...etc.

	@Bean
	public ViewResolver viewResolver()
	{
		// If i return "wellcome" as modelandview object, the resolver will look for /jsp/wellcome.jsp inside the webapp folder
		UrlBasedViewResolver resolver = new UrlBasedViewResolver();
		resolver.setPrefix("/jsp/");
		resolver.setSuffix(".jsp");
		resolver.setViewClass(JstlView.class);
		return resolver;
	}

	@Bean(name = "datasource")
	@Profile(value = "default")
	public DataSource dataSource()
	{
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setDriverClassName("org.postgresql.Driver");
		dataSource.setUrl("jdbc:postgresql://localhost:5433/postgres");
		dataSource.setUsername("postgres");
		// change the password here
		dataSource.setPassword("yourpassword");
		return dataSource;
	}

	@Bean(name = "sessionFactory")
	@DependsOn(value = "datasource")
	public LocalSessionFactoryBean sessionFactory(@Autowired @Qualifier(value = "datasource") DataSource ds)
	{
		LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
		sessionFactory.setDataSource(ds);
		// where are the model (@entity) classes
		sessionFactory.setPackagesToScan("com.numankaraaslan.springHibernateJSPdemo.model");
		sessionFactory.setHibernateProperties(hibernateProperties());
		// you can set configurations manually like
		// sessionFactory.getConfiguration().setProperty(propertyName, value);
		// OR from custom "/com/numankaraaslan/springjspdemo/persistence/hibernate.cfg.xml" like
		// SessionFactory SF = new org.hibernate.cfg.Configuration().configure("/com/numankaraaslan/springjspdemo/persistence/hibernate.cfg.xml").buildSessionFactory();
		return sessionFactory;
	}

	private final Properties hibernateProperties()
	{
		Properties hibernateProperties = new Properties();
		hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "create");
		hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL10Dialect");
		return hibernateProperties;
	}

	@Bean(name = "txManager")
	@DependsOn(value =
	{ "datasource", "sessionFactory" })
	public HibernateTransactionManager getManager(@Autowired @Qualifier(value = "datasource") DataSource ds, @Autowired @Qualifier(value = "sessionFactory") LocalSessionFactoryBean sf)
	{
		return new HibernateTransactionManager(sf.getObject());
	}
}
			
		

Basit bir repository

Bu uygulama veritabanına hibernate vasıtasıyla bağlanıyor demiştik. O zaman spring boot ile gelen hazır repository yapılarını da (JPA repository gibi) kullanmayacağız demektir. Tabi ki dilerseniz spring-data-jpa 'yı projeye ekleyerek bu repository 'den kurtulabilirsiniz. Sadece interface yazarak geçiştirebilirsiniz. Fakat bu örnekte basic işlemler için kullandığım kodları yazayım. @Transactional anotasyonlarına dikkat. Bu sayede spring framework transaction 'ları yönetecek.

			
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository;

import com.numankaraaslan.springHibernateJSPdemo.model.Book;

import lombok.AllArgsConstructor;

@Repository
@AllArgsConstructor
public class BookRepo
{
	private SessionFactory sessionFactory;

	@org.springframework.transaction.annotation.Transactional
	// NOT @javax.transaction.Transactional
	public void save(Book newBook)
	{
		Session session = sessionFactory.openSession();
		session.save(newBook);
		session.close();
	}

	@org.springframework.transaction.annotation.Transactional
	public List<Book> getBooks()
	{
		// let the spring handle the transaction
		Session session = sessionFactory.openSession();
		List<Book> books = session.createQuery("select b from Book b", Book.class).getResultList();
		session.close();
		return books;
	}
}
			
		

Bu sistemde benim kullandığım model (yada entity nesnesi diyebiliriz) çok basit ve hibernate entity 'lerinin basic özelliklerini kullanıyor. Aşağıda kodları görebilirsiniz fakat postgresql tarafında public şemasını değil de kendi şemanızı kullanmak isterseniz öncelikle şema oluşturmayı unutmayınız. Anotasyonlara da dikkat tabi.

			
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Table(schema = "springhibernate", name = "Book")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
// Remember to create "springhibernate" schema in posgtresql database
// CREATE SCHEMA springhibernate AUTHORIZATION postgres; GRANT ALL ON SCHEMA springhibernate TO postgres;
public class Book
{
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@Column
	private String name;

	@Column
	private int year;

	@Column
	private String author;

	public Book(String name, int year, String author)
	{
		this.name = name;
		this.year = year;
		this.author = author;
	}
}
			
		

Basit bir JSP sayfası ve controller sınıfı

Bu şekilde uygulama ayağa kalkabilir ve veritabanlarını oluşturabilir hale geliyor. Tek yapmamız gereken controller sınıfı ile MVC altyapısını oturtmak. Aşağıdaki küçük sınıf localhost:8080/books veya localhost:8080/addbook şeklindeki url 'lerde çalışır. Bu istekler geldiğinde ekranda ${books} gibi kullanılabilecek nesneleri model olarak ekler ve örneğin "new ModelAndView("books")" olarak döndürür. Return ederken "books" ifadesi geldiğinde yukarıdaki viewresolver çözümleme yapar ve isteği /jsp/books.jsp olarak iletir. Bu kısım spring boot ile yapacağınız bir mvc uygulaması ile aynı.

			
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

import com.numankaraaslan.springHibernateJSPdemo.model.Book;
import com.numankaraaslan.springHibernateJSPdemo.service.BookService;

import lombok.AllArgsConstructor;

@Controller
@AllArgsConstructor
public class JSPController
{
	private BookService bookService;

	@GetMapping("/books")
	public ModelAndView getBooks()
	{
		ModelAndView booksJSP = new ModelAndView("books");
		booksJSP.addObject("books", bookService.getBooks());
		return booksJSP;
	}

	@GetMapping("/addbook")
	public ModelAndView addbook()
	{
		ModelAndView booksJSP = new ModelAndView("addbook");
		booksJSP.addObject("book", new Book());
		return booksJSP;
	}

	@PostMapping("/addbook")
	public ModelAndView addbookPost(@ModelAttribute Book newBook)
	{
		bookService.save(newBook);
		return new ModelAndView("redirect:/books");
	}
}
			
		

Son olarak kitap listeleme yaptığım JSP sayfasını örnek vereyim. JSP sayfalarında JTSL tag 'leri yardımı ile thymeleaf 'de "th:each" gibi ifadelerin benzerlerini "c:forEach" şeklinde kullanabiliriz. Bu sayfa server tarafında render edilir ve kullanıcıya düz bir html sayfası döndürür. Burada da sayfanın üstündeki <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> ifadesine dikkat etmemiz gerekiyor. Ayrıca "page language = "java"" görüyorsunuz. Controller tarafından modelandview nesnesine eklenen books listesi burada foreach ile yazdırılır ve döngüdeki değişkenler book olarak isimlendirilir. Aşağıda da "book.name" gibi nesne bilgilerine ulaşılır ki burada da reflection işin içine girer ve sizin nesnenizin getName metodunu arar bulur ve çalıştırır.

			
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring JSP demo</title>
</head>
<body>
	<a href="index">home</a>
	<br/>
	<table>
		<thead>
			<tr>
				<th>Name</th>
				<th>Year</th>
				<th>Author</th>
			</tr>
		</thead>
		<tbody>
			<c:forEach items="${books}" var="book">
				<tr>
					<td>${book.name}</td>
					<td>${book.year}</td>
					<td>${book.author}</td>
				</tr>
			</c:forEach>
		</tbody>
	</table>
</body>
</html>
			
		

Bu şekilde oluşturacağınız projenin yapısı aşağıdaki resimdekine benzer olacaktır. Bütün jsp sayfalarını tek bir jsp klasörüne koymak mantıklı olmayabilir. Fakat farklı klasörlere ayırdığımda web.xml dosyaında daha fazla mapping karmaşası oluşurdu ve sayfalar içerisinden href ile diğer sayfalara link vermek zorlaşırdı. Tabi ki bu aşılmaz bir engel değil.

Projeyi ayağa kaldırmak için eclipse içerisinde bir tomcat sunucusu ayağa kaldırabilir veya ayrıca kendi sunucunuza deploy edebilirsiniz. Kullanacağınız tomcat sürümü yanlış bilmiyorsam 8 ve üstü olmalı. Projenizin kullandığı JDK versiyonuna göre bu gereksinim değişebilir. Uygulamayı ayağa kaldırırsanız localhost:8080/springHibernateJSPdemo/wellcome sayfasından ulaşabilirsiniz. Buradaki context path benim projemin ismidir, sizinki farklı ise değiştiriniz.

Minimal ve basit konfigürasyon ile uçuşa hazırız

Bu sayede spring framework, hibernate ve JSP teknolojilerini kullanan güncel bir proje çatısı oluşturmuş olduk. JSP yerine HTML kullanmak isterseniz viewresolver nesnesini thymeleaf için farklı oluşturmanız ve tabi ki gerekli dependency 'yi de eklemeniz gerekirdi. Her ne kadar thymeleaf güncel bir teknoloji olsa da eski monolitik JSP projelerinin dönüşümünde bu projeyi baz alabilirsiniz. En azından 2022 yılı Ocak itibariyle kullandığım bağımlılıklar ve sürümleri çalışır görünüyor. Bir sonraki yazıda görüşmek üzere :)


Bir yorum yazabilirsiniz