Struts 2’de Kendi Interceptor Sınıfımızı Yaratmak

Struts 2’de Interceptors sayesinde tüm istekler ve yönlendirmeler üzerinde işlemler gerçekleştirebiliriz. Bir web sayfasından gönderilen parametre Interceptors sayesinde Action sınıfı içerisindeki bir değişkenin değerine set edilir.  Ayrıca action metodumuz (Action sınıfındaki execute() metodu) çalışmadan önce ve sonra yapılacak işler varsa, Interceptors bize bu işleri gerçekleştirme imkanını sağlar.

Interceptors konfigurasyon dosyasında (struts.xml) belirli bir paket tanımı içerisinde tanımlanır. Konfigurasyon dosyalarında tanımladığımız paketleri genellikle struts-default.xml dosyasından extend ederiz. Bu sayede bu dosya içerisinde tanımlanmış tüm özellikleri kullanabiliriz.

[box type=”info”] struts-default.xml dosyası struts2-core-xxx.jar dosyası içerisindedir.[/box]

struts-default.xml dosyası içerisinde de halihazırda tanımlanmış birçok Interceptor vardır. Çoğu uygulama için bu tanımlar yeterli olacaktır.

Interceptor tanımları struts.xml dosyasında basit anlamda aşağıdaki gibi yapılır.

[box type=”warning”] Aşağıdaki tanım struts-default.xml dosyasından örnek olması amacıyla alınmıştır.[/box]

[codesyntax lang=”xml” lines=”no”]

<struts>
   ...
   <package name="struts-default">
      <interceptors>
         <interceptor name="alias"/>
         <interceptor name="autowiring"/>
         ...
      </interceptors>
   </package>
   ...
</struts>

[/codesyntax]

Konfigurasyon dosyasında birden fazla action tanımlanmışsa ve her bir action aynı Interceptor’ları kullanıyorsa, kullanılan Interceptor’lar bir stack tanımı yapılarak referans gösterilir.

[codesyntax lang="xml" lines="no"]
<package name="default" namespace="/" extends="struts-default">
     <interceptors>
        <interceptor-stack name="stack1">
             <interceptor-ref name="timer"/>
             <interceptor-ref name="logger"/>
             <interceptor-ref name="defaultStack" />
        </interceptor-stack>
    </interceptors>

    <action name="login">
        <interceptor-ref name="stack1"/>
        <result name="success">/menu.jsp</result>
    </action>

    <action name="logout">
        <interceptor-ref name="stack1"/>
        <result name="success">/logout.jsp</result>
    </action>
</package>
[/codesyntax]

[box type=”info”] Yukarıdaki örnekte timer, logger ve defaultstack isimli Interceptor’lar struts-default.xml dosyasında tanımlanmışlardır. İsterseniz kendi tanımladığınız Interceptor’ları da bir stack tanımı yaparak action içerisinde referans olarak verebilirsiniz.[/box]

Çok özel uygulamalar için kendi Interceptor sınıflarımızı yazma ihtiyacı duyabiliriz. Bu gibi durumlarda Interceptor sınıflarının nasıl tanımlandığını basit bir örnekle anlatmaya çalışayım.

Projemde kullandığım teknolojiler :

–          JDK 1.7

–          Eclipse Juno 4.2

–          Struts 2.3.8

–          Apache Tomcat 7

CustomInterceptor isminde yeni bir web projesi yaratıyorum.

İlk olarak JSP sayfamı tasarlıyorum.

index.jsp

[codesyntax lang=”html4strict” lines=”no”]

<%@ page language="java" contentType="text/html; charset=ISO-8859-9" pageEncoding="ISO-8859-9"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
	<body>
       		<s:a href="tikla">Interceptor Test</s:a>
	</body>
</html>

[/codesyntax]

Basit bir sayfa ve sadece tek bir link var. Şimdi linke tıkladığımızda çalışacak Action sınıfını tasarlıyorum.

TiklaAction.java

[codesyntax lang=”java” lines=”no”]

package sample;

public class TiklaAction {

       public String execute() {
             System.out.println("Action calisti");
             return "success";
       }
}

[/codesyntax]

Bu sınıf da basit bir POJO ve sadece konsola “Action calisti” yazarak sayfayı yönlendiriyor. Yönlendirilecek sayfayı tasarlayalım.

success.jsp

[codesyntax lang=”html4strict” lines=”no”]

<%@ page language="java" contentType="text/html; charset=ISO-8859-9" pageEncoding="ISO-8859-9"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
	<body>
       		<h1>Yönlendirilen Sayfa</h1>
	</body>
</html>

[/codesyntax]

Şimdi de Interceptor sınıflarımızı tasarlayalım. Bir sınıfın Interceptor olabilmesi için;

1-      Interceptor arayüzünü gerçekleştirmesi gerekir ya da

2-      Interceptor arayüzünü gerçekleştirmiş olan AbstractInterceptor sınıfından türemesi gerekir.

AbstractInterceptor sınıfını kullanıyorsak init() ve destroy() metotlarını ezme zorunluluğumuz kalmaz. Ben iki tane Interceptor sınıfı tanımlayacağım.

MyInterceptor1.java

[codesyntax lang=”java” lines=”no”]

package com.javauzmani.interceptors;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class MyInterceptor1 extends AbstractInterceptor {
       private static final long serialVersionUID = -299349963368714122L;

       @Override
       public String intercept(ActionInvocation inv) throws Exception {
             System.out.println("MyInterceptor1 sinifinda action sinifindaki execute metodu calismadan once yapilacak isler");
             String invocationResult = inv.invoke()
             System.out.println("MyInterceptor1 sinifinda action sinifindaki execute metodu calistiktan sonra yapilacak isler");
             return invocationResult;
       }
}

[/codesyntax]

MyInterceptor2.java

[codesyntax lang=”java” lines=”no”]

package com.javauzmani.interceptors;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class MyInterceptor2 extends AbstractInterceptor {
                private static final long serialVersionUID = -7461817391953291560L;

                @Override
                public String intercept(ActionInvocation inv) throws Exception {

                               System.out.println("MyInterceptor2 sinifinda action sinifindaki execute metodu calismadan once yapilacak isler");
                               String invocationResult = inv.invoke();
                               System.out.println("MyInterceptor2 sinifinda action sinifindaki execute metodu calistiktan sonra yapilacak isler");
                               return invocationResult;
                }
}

[/codesyntax]

Şimdi de konfigurasyon dosyasını tanımlayalım.

struts.xml

[codesyntax lang=”xml” lines=”no”]

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC

       "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
       "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
             <package extends="struts-default" name="myPackage">
                    <interceptors>
                           <interceptor class="com.javauzmani.interceptors.MyInterceptor1" name="myInterceptor1"></interceptor>
                           <interceptor class="com.javauzmani.interceptors.MyInterceptor2" name="myInterceptor2"></interceptor>
                    </interceptors>

                    <action class="com.javauzmani.action.TiklaAction" name="tikla">
                           <interceptor-ref name="myInterceptor1"></interceptor-ref>
                           <interceptor-ref name="myInterceptor2"></interceptor-ref>
                           <result name="success">/success.jsp</result>
                    </action>
             </package>
</struts>

[/codesyntax]

Interceptor’lar konfigurasyon dosyasında tanımlandıkları sırada çalışırlar.

web.xml dosyası aşağıdaki gibidir.

[codesyntax lang=”xml” lines=”no”]

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

  <display-name>CustomInterceptor</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

</web-app>

[/codesyntax]

Projemizi çalıştırdığımızda index.jsp sayfası gelecektir.

1

Linke tıkladığımızda sayfa success.jsp’ye yönlendirilir.

2

Konsol çıktısı da aşağıdaki gibi olur.

3

Action sınıfları Servlet sınıflarından farklı olarak thread-safe çalışırlar. Gelen her istek için Action sınıfının bir instance’ı yaratılır. Servlet’lerde ise aynı instance gelen her istek için kullanılır.

Fakat Interceptor’lardaki durum farklıdır. Action sınıfları thread-safe olsa da Interceptor’ların instance’ları bir defa yaratılır ve aynı Servlet’ler gibi her istek için kullanılırlar. Bu yüzden Interceptor sınıfları içerisindeki kodların thread-safe yazılması gerekir.

Struts 2’de Sabit Tanımlama (Constant Configurations)

Struts 2 Framework kullanırken uygulama içinde kullandığımız bazı ayarlar sabit değerler ile ayarlanabilir.

Struts’ın konfigurasyon dosyasında tanımlanan constant etiketleri ile framework konfigurasyonları çok basit bir şekilde yapılabilir. Ayrıca Struts ile birlikte kullanılan eklentiler de yine bu sabit değerler sayesinde ayarlanabilir. İki ana rolleri vardır.

  1. Birincisi örneğin yüklenecek maximum dosya boyutu ile standart değer olan 2 MB dışında bir değer verilebilir. Veya geliştirme ortamında çalışan uygulama için daha çok log yazılması basit bir sabit değerle belirtilebilir. Ya da başka bir örnekle kendi oluşturduğumuz tema ismi, bulunduğu dizin ve tip bilgisini tanımlayabiliriz.
  2. İkincisi Bean implementasyonu tanımlanabilir.

Sabitler standartta aşağıdaki sırada uygulama içerisinde aranırlar. Bir sonraki dosyada aynı sabit tekrar tanımlanmışsa ezilmiş olur.

  1. struts-default.xml
  2. struts-plugin.xml
  3. struts.xml
  4. struts.properties
  5. web.xml

Bu dosyalardan ilk 2 tanesi framework içerisinde standart olarak gelir. Diğer dosyaları istersek güncelleyebiliriz.

struts.xml

[codesyntax lang=”xml” lines=”no”]

<struts>
	...
	<constant name="struts.devMode" value="true" />
	<constant name="struts.ui.theme" value="mytheme" />
	<constant name="struts.ui.templateDir" value="template" />
	<constant name="struts.ui.templateSuffix" value="ftl" />
  	...
</struts>

[/codesyntax]

struts.properties

[codesyntax lang="xml" lines="no"]

# Gelistirme modu acik
struts.devMode=true
# Kendi tema ismimiz
struts.ui.theme=mytheme
# Temamizin bulundugu dizi ismi
struts.ui.templateDir=template
# Tema tipi (ftl)
struts.ui.templateSuffix=ftl
[/codesyntax]

web.xml

[codesyntax lang=”xml” lines=”no”]

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="ttp://java.sun.com/xml/ns/javaee" 
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

    ...
    <filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
        <init-param>
               <param-name>struts.devMode</param-name>
               <param-value>true</param-value>
        </init-param>
    </filter>
    ...
</web-app>

[/codesyntax]

Struts 2’de .action uzantısını nasıl silerim?

Struts 2’de her bir Action sınıfını çağırmak için standartta .action uzantısı kullanılır. Başka bir deyişle struts.xml dosyasında Action sınıfını çağırmak için tanımlanan ismin sonuna .action yazılarak istek gönderilir. İsmi “LoginAction” olan bir sınıfın çağrım ismi “login” olarak tanımlanmışsa, istek şu şekilde yapılır :

http://<host&gt;:<port>/<context-path>/login.action

Aynı Servlet sınıflarında olduğu gibi Action sınıflarında da bir mapping uzantısı kullanılabilir.

web.xml dosyasında Servlet mapping aşağıdaki şekilde yapılıyordu :

[codesyntax lang=”xml” lines=”no”]

<servlet>
	<servlet-name>LoginServlet</servlet-name>
	<servlet-class>servlets.LoginServlet</servlet-class>
</servlet>

<servlet-mapping>
	<servlet-name>LoginServlet</servlet-name>
	<url-pattern>/login</url-pattern>
</servlet-mapping>

[/codesyntax]

http://<host&gt;:<port>/<context-path>/login diyerek LoginServlet isimli sınıfın çağrılması sağlanıyordu.

Action sınıfları için bu sefer struts.xml dosyasında aşağıdaki şekilde bir sabit tanımlanır.

[codesyntax lang=”xml” lines=”no”]

<struts>

  <constant name="struts.action.extension" value="aspx"/> 

  <package name="login" extends="struts-default">
	<action name="login">
		<result>pages/login.jsp</result>
	</action>
  </package>

</struts>

[/codesyntax]

 http://<host>:<port>/<context-path>/login.aspx

Yukarıdaki mapping’de istek tarayıcının adres satırından bir aspx sayfasına yapılıyormuş gibi gözükse de aslında login.jsp sayfası çağrılacaktır. Eğer uzantı hiç istenmiyorsa aşağıdaki tanım yeterli olacaktır.

[codesyntax lang=”xml” lines=”no”]

<struts>

  <constant name="struts.action.extension" value=""/> 

  <package name="login" extends="struts-default">
	<action name="login">
		<result>pages/login.jsp</result>
	</action>
  </package>

</struts>

[/codesyntax]

Bu şekilde bir tanım yapıldığında istek URL’si aşağıdaki gibi olmalıdır.

http://<host&gt;:<port>/<context-path>/login

Eclipse Juno üzerinde Hibernate Örneği

Kullandığım teknolojiler ve araçlar;

  • JDK 1.7
  • Eclipse Juno 4.2
  • Oracle XE 11g
  • Hibernate 4.2

Yazdığım proje basit bir konsol uygulamasıdır. Hibernate’in son sürümü olan 4.2 ile geliştirilmiştir. Dolayısıyla SessionFactory nesnesi yaratılırken deprecate edilen eski metot yerine yenisi kullanılmıştır.

Öncelikle Eclipse’de yeni bir Java projesi yaratalım. Ben ismine HibernateCRUD dedim. Projemin “Build Path” ine Hibernate’in JAR dosyalarını ekliyorum. Bu işlemi proje üzerinde sağ tıklayarak BuildPath -> Add External Archives.. seçeneği ile gerçekleştirebilirsiniz.

1

Kullandığım JAR listesi aşağıdaki gibidir.

  • Öncelikle buradan indirmiş olduğunuz hibernate-search-4.2.0.Final ZIP dosyasını dilediğiniz bir yere çıkartın. Daha sonra distlibrequired  altındaki tüm JAR’ları ekleyin.
  • İkinci adımda eğer benim gibi annotation kullanacaksanız gereken hibernate-annotations.jar, hibernate-commons-annotations.jar, ejb3-persistence.jar dosyalarını ekleyin. Eğer annotation yerine konfigurasyon dosyaları (*.hbm.xml) kullancaksanız o zaman bu JAR’lara gerek yok. Bu JAR’ları şu adresten indirebilirsiniz.
  • Üçüncü adımda hibernate-search-4.2.0.Final dosyası içerisinden distlibprovided dizini altındaki hibernate-jpa-2.0-api-1.0.1.Final.jar dosyasını ekliyoruz.
  • Son olarak da bağlanacağımız veri tabanının driver’ını ekliyoruz. Ben Oracle kullandığım için ojdbc6.jar  dosyasını da CLASSPATH’ime ekliyorum.

Projemin kullandığı kütüphaneler en son aşağıdaki gibi oluyor.

2

 

Veri tabanımızda halihazırda bulunan örnek tablolardan REGIONS tablosunu kullanacağım. Hibernate’in veri tabanına bağlanabilmesi için gerekli olan konfigurasyon dosyasını yaratıyorum. Kaynak kodlarımın bulunduğu yerde yarattığımın hibernate.cfg.xml dosyası aşağıdaki gibi olacaktır. Eğer siz başka bir veri tabanına bağlanıyorsanız bağlantı ayarlarınızı değiştirmelisiniz.

[codesyntax lang=”xml” lines=”no”]

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory>
		<property name="hibernate.dialect">
			org.hibernate.dialect.OracleDialect
		</property>
		<property name="hibernate.connection.driver_class">
			oracle.jdbc.OracleDriver
		</property>

		<property name="hibernate.connection.url">
			jdbc:oracle:thin:@localhost:1521:xe
		</property>
		<property name="hibernate.connection.username">
			hr
		</property>
		<property name="hibernate.connection.password">
			hr
		</property>

		<!-- List of XML mapping files -->
		<mapping class="com.javauzmani.entities.Regions" />

	</session-factory>
</hibernate-configuration>

[/codesyntax]

Alt yapımızı hazırladıktan sonra şimdi kodu yazmaya başlayalım. Önce veri tabanındaki tabloya karşılık gelen entity sınıfını yaratıyorum.

[codesyntax lang=”java” lines=”no”]

package com.javauzmani.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Regions {

	@Id
	@Column(name = "region_id")
	private int regionId;

	@Column(name = "region_name")
	private String regionName;

	public Regions() {
		super();
	}

	public Regions(int regionId, String regionName) {
		super();
		this.regionId = regionId;
		this.regionName = regionName;
	}

	public int getRegionId() {
		return regionId;
	}

	public void setRegionId(int regionId) {
		this.regionId = regionId;
	}

	public String getRegionName() {
		return regionName;
	}

	public void setRegionName(String regionName) {
		this.regionName = regionName;
	}
}

[/codesyntax]

Daha sonra ekleme, silme, güncelleme ve listeleme işlemlerini yapacak olan sınıfımı yazıyorum.

[codesyntax lang=”java” lines=”no”]

package com.javauzmani.dao;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

import com.javauzmani.entities.Regions;

public class RegionsDAO {
	static ServiceRegistry serviceRegistry = null;
	static SessionFactory factory = null;
	static Configuration configuration = null;

	static {
		try {
			configuration = new Configuration().configure("hibernate.cfg.xml");
			serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
			factory = configuration.buildSessionFactory(serviceRegistry);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void addRegions(int regionId, String name) {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Regions regions = new Regions(regionId, name);
			session.save(regions);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null) {
				tx.rollback();
			}
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	@SuppressWarnings("unchecked")
	public List<Regions> listRegions() {
		Session session = factory.openSession();
		Transaction tx = null;
		List<Regions> regions = null;
		try {
			tx = session.beginTransaction();
			regions = session.createQuery("from Regions").list();
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null) {
				tx.rollback();
			}
			e.printStackTrace();
		} finally {
			session.close();
		}
		return regions;
	}

	public void updateRegions(Integer regionsId, String regionName) {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Regions region = (Regions) session.get(Regions.class, regionsId);
			region.setRegionName(regionName);
			session.update(region);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null) {
				tx.rollback();
			}
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	public void deleteRegions(Integer regionsId) {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Regions region = (Regions) session.get(Regions.class, regionsId);
			session.delete(region);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null) {
				tx.rollback();
			}
			e.printStackTrace();
		} finally {
			session.close();
		}
	}
}

[/codesyntax]

Son olarak da yazmış olduğum DAO sınıfındaki metotları çağıracak örnek bir test sınıfı yaratıyorum.

[codesyntax lang=”java” lines=”no”]

package com.javauzmani.calistir;

import java.util.List;

import com.javauzmani.dao.RegionsDAO;
import com.javauzmani.entities.Regions;

public class CrudDeneme {
	public static void main(String[] args) {

		RegionsDAO dao = new RegionsDAO();
		List<Regions> regions = dao.listRegions();

		for (Regions region : regions) {
			System.out.print("Region Id : " + region.getRegionId());
			System.out.print(", Region Name : " + region.getRegionName());
			System.out.println();
		}
	}
}

[/codesyntax]

[box type=”warning”]Veri tabanı sunucunuzun açık olduğundan emin olunuz !!![/box]

Kodumuzu çalıştırdığımızda çıktı aşağıdaki gibi oluyor.

3

 

Hibernate Mapping Types

Hibernate’te Java sınıflarını veri tabanındaki tablolara eşleştirmek için kullanılan “mapping” dosyalarında tipler karşımıza çıkar. Bu tipler Java tipi ya da SQL tipi değildirler. Bunlar tam olarak Java tiplerini SQL tiplere, SQL tiplerini de Java tiplerine dönüştürmeyi sağlayan Hibernate tipleridir. Örnek bir “mapping” dosyası aşağıdaki gibidir.

Araba.hbm.xml

[codesyntax lang=”xml” lines=”no”]

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name="Araba" table="ARABA">
      <id name="id" type="int" column="id">
         <generator class="native"/>
      </id>
      <property name="marka" column="marka" type="string"/>
      <property name="model" column="model" type="string"/>
      <property name="uretimYili" column="uretim_yili" type="int"/>
   </class>
</hibernate-mapping>

[/codesyntax]

Dönüşümleri sağlayan Hibernate tiplerinin neler olduğu ve hangi dönüşümleri gerçekleştirdiği bilgisinin işinize yarayacağını düşünüyorum.

1 2