7. QuiEst Uygulaması
Burada, eğitim amaçlı olması nedeniyle basit tutulması gereken önceki uygulamalardan biraz daha gelişmiş bir Struts uygulamasını anlatıyoruz.
7.1. users sınıfı
Bir Unix makinesindeki kullanıcı bilgilerini depolayan bir Java sınıfımız var. Bu bilgiler üç ayrı dosyada kaydedilir:
- /etc/passwd: kullanıcı listesi
- /etc/group: grup listesi
- /etc/aliases: e-posta takma adları listesi
Bu üç dosyanın içeriği şu şekildedir:
- /etc/passwd
Bu dosyadaki satırlar şu biçimdedir:
login:pwd:uid:gid:id:dir:shell
ile
kullanıcının kullanıcı adı | |
şifrelenmiş şifresi | |
kullanıcı numarası | |
grup numarası | |
kimliği | |
bağlantı dizini | |
komut yorumlayıcısı |
Böylece bir kullanıcının satırı şu şekilde olabilir:
Yukarıdaki kullanıcı 110 numaralıdır ve 57 numaralı gruba aittir. 57 numaralı grubun tanımı /etc/group dosyasında bulunur.
- /etc/group
Bu dosyanın satırları şu biçimdedir:
nomGroupe:pwd:gid:membre1,membre2,....
ile
grup adı | |
şifrelenmiş şifresi - genellikle bu alan boştur | |
grup numarası | |
kullanıcı giriş bilgileri - bu alan boş olabilir |
Böylece, yukarıdaki 57 numaralı grubun satırı şu şekilde olabilir:
Bu, 57 numaralı grubun adının iup2-auto olduğunu gösterir.
- /etc/aliases
Bu dosyadaki satırlar şu biçimdedir:
ile
takma ad | |
bir veya daha fazla sekme | |
takma adın ait olduğu kullanıcının oturum açma adı |
Böylece şu satır
guillaume.dupond: dupond
satırı, guillaume.dupond takma adının dupond kullanıcı adına ait olduğu anlamına gelir. Takma adların e-posta adreslerinde kullanıldığını hatırlayalım. Dolayısıyla, önceki örnekte Unix makinesinin adı shiva.istia.univ-angers.fr ise, guillaume.dupond@shiva.istia.univ-angers.fr adresine gönderilen bir e-posta, bu makinedeki dupond kullanıcı adının posta kutusuna teslim edilecektir.
Burada users sınıfının arayüzünün tamamıyla değil, sadece oluşturucusu ve birkaç yöntemiyle ilgileneceğiz:
import java.io.*;
import java.util.*;
public class users{
// özellikler
private Hashtable usersByLogin=new Hashtable(); // giriş --> kullanıcı adı, şifre, ..., dizin
private ArrayList erreurs=new ArrayList(); // hata mesajları listesi
....
// oluşturucu
public users(String usersFileName, String groupsFileName, String aliasesFileName) throws Exception {
// usersFileName : şu biçimdeki satırları içeren kullanıcı dosyasının adı
// login:pwd:uid:gid:id:dir:shell
// groupsFileName : şu biçimdeki satırları içeren gruplar dosyasının adı
// ad:şifre:numara:üye1,üye2,..
// aliasesFileName : şu biçimdeki satırları içeren takma ad dosyasının adı
// takma ad:[tab]login
// usersByLogin sözlüğünü oluşturur
....
}// oluşturucu
// kullanıcı listesi
public Hashtable getUsersByLogin(){
return usersByLogin;
}
// hatalar
public ArrayList getErreurs(){
return erreurs;
}
Anahtarları passwd dosyasındaki kullanıcı adları olan bir sözlük (Hashtable). Anahtara atanan değer, kullanıcı adıyla ilişkili passwd dosyası satırındaki 7 alanı içeren bir dize dizisidir (String [7]). Satırda 7'den az alan varsa, bazı alanlar boş olabilir. | |
hata mesajları listesi - hata yoksa boştur |
7.2. Web uygulaması
Aşağıdaki web uygulamasını (form sayfası) oluşturmayı planlıyoruz:
![]() |
no | ad | tür HTML | rol |
1 | cmbLogins | <select ...>...</select> | hakkında bilgi talep edilebilecek tüm giriş bilgilerinin listesini gösterir |
2 | btnChercher | <input type="submit" ...> | arama işlemini başlatmak için |
Kullanıcı [Chercher] (2) düğmesine bastığında, (1) numaralı giriş bilgisi users türündeki bir U nesnesinden istenir. Giriş bilgisi mevcutsa, şu yanıt alınır (bilgi sayfası):
![]() |
Yukarıda tarayıcının URL'inde görüldüğü gibi, form parametreleri bir GET aracılığıyla sunucuya gönderilir. Dolayısıyla, bu parametreleri içeren URL'i doğrudan tarayıcıya verebiliriz. Burada, var olmayan bir kullanıcı adı girmek için bunu yapıyoruz. Aşağıdaki yanıtı alıyoruz (hata sayfası):
![]() |
7.3. Uygulamanın mimarisi
![]() |
Bu mimaride aşağıdaki bileşenleri buluyoruz:
- görünümler:
- logins.jsp, oturum açma bilgilerinin listesini görüntülemek için kullanılır (görünüm 1)
- infos.jsp, bir oturum açma bilgisini görüntülemek için kullanılır (görünüm 2)
- erreurs.jsp, hata listesini görüntülemek için kullanılır (görünüm 3)
- eylemler tarafından kullanılan ActionForm türü formlar:
- formLogins, logins.jsp formundaki verileri toplamak için kullanılır
- Eylemler:
- SetupLoginAction, formulaire.jsp'in içeriğini hazırlar ve ardından bu görünümü görüntüler
- InfosLoginAction, logins.jsp'in içeriğini sunucuya gönderildikten sonra işleyen
- ForwardAction: [Retour vers le formulaire] bağlantısını işleyen, infos.jsp ve erreurs.jsp görünümleri
- eylemlerin verilerini almak için kullandıkları users iş sınıfı
- passwd, group ve aliases adlı üç düz dosya tarafından sağlanan model
7.4. Web uygulamasının yapılandırma dosyaları
7.4.1. server.xml dosyası
Uygulamanın bağlamı /strutsquiest2 olarak adlandırılacaktır. Bu nedenle, Tomcat'in server.xml dosyasına aşağıdaki satır eklenecektir:
Bu işlem tamamlandıktan sonra, yeni bağlamın dikkate alınması için gerekirse Tomcat'i yeniden başlatırız. URL http://localhost:8080/strutsquiest2 adresini çağırarak bağlamın geçerliliğini kontrol edebiliriz.
7.4.2. web.xml dosyası
Uygulamanın web.xml yapılandırma dosyası aşağıdaki gibi olacaktır:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<servlet>
<servlet-name>strutsquiest2</servlet-name>
<servlet-class>istia.st.struts.quiest.Quiest2ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>passwdFileName</param-name>
<param-value>data/passwd</param-value>
</init-param>
<init-param>
<param-name>groupFileName</param-name>
<param-value>data/group</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>strutsquiest2</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
Bu web.xml dosyası bir yenilik getiriyor. Struts denetleyicisi artık org.apache.struts.action.ActionServlet değil, burada istia.st.struts.quiest.Quiest2ActionServlet olarak adlandırdığımız türetilmiş bir sınıftır. Bu sayede, passwdFileName (passwd dosyasının konumu) ve groupFileName (group dosyasının konumu) olmak üzere iki başlatma parametresini alabileceğiz. Aliases dosyası bu uygulamada gereksizdir.
7.4.3. struts-config.xml dosyası
struts-config.xml dosyası şu şekilde olacaktır:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="formLogins" type="org.apache.struts.action.DynaActionForm">
<form-property name="cmbLogins" type="java.lang.String" initial=""/>
<form-property name="tLogins" type="java.lang.String[]"/>
</form-bean>
</form-beans>
<action-mappings>
<action
path="/init"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.SetupLoginsAction"
>
<forward name="afficherLogins" path="/vues/logins.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
<action
path="/infosLogin"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.InfosLoginAction"
>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
<forward name="afficherInfos" path="/vues/infos.jsp"/>
</action>
<action
path="/retourLogins"
parameter="/vues/logins.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
</action-mappings>
<message-resources
parameter="istia.st.struts.quiest.ApplicationResources"
null="false"
/>
</struts-config>
Burada üç ana bölüm bulunmaktadır:
- <form-beans> bölümünde formların tanımlanması
- <action-mappings> bölümünde eylemlerin tanımlanması
- <message-ressources> içindeki kaynak dosyasının bildirimi
7.4.4. Uygulamadaki form nesneleri (bean'ler)
<form-beans>
<form-bean name="formLogins" type="org.apache.struts.action.DynaActionForm">
<form-property name="cmbLogins" type="java.lang.String" initial=""/>
<form-property name="tLogins" type="java.lang.String[]"/>
</form-bean>
</form-beans>
Uygulamamızda, formLogins adlı ve DynaActionForm'ten türetilmiş bir form bean'i bulunmaktadır. Bu bean, aşağıdaki durumlarda kullanılacaktır:
- 1 numaralı görünümün görüntülenmesi için gerekli verileri içermek
- kullanıcı 1 numaralı görünümdeki formu gönderdiğinde (submit) form değerlerini almak
formLogins bean'inin yapısı, 1 numaralı görünümün formuyla bağlantılıdır. Bunu inceleyelim:
![]() |
No | ad | tür HTML | rol |
1 | cmbLogins | <select ...>...</select> | hakkında bilgi talep edilebilecek tüm giriş bilgilerinin listesini gösterir |
2 | btnChercher | <input type="submit" ...> | arama işlemini başlatmak için |
Birkaç durumu ayırt edelim:
- istemciden sunucuya gönderim sırasında, formLogins nesnesi, yukarıdaki HTML formunun değerlerini içermek üzere kullanılır; bu form, [Envoyer] düğmesi ile gönderilecektir. Bu nedenle, kullanıcının seçtiği giriş bilgisini içeren HTML, cmbLogins ve c.a.d alanlarının değerlerini alacak bir cmbLogins alanı gereklidir.
- Sunucudan istemciye, formLogins nesnesi, 1 numaralı görünümün başlangıç içeriğini sağlamak için kullanılır. Bu nesnenin tLogins alanı, liste 1'in içeriği olarak kullanılacaktır. cmbLogins alanı ise Liste 1'den seçilecek öğenin belirlenmesini sağlayacaktır.
7.4.5. Uygulamadaki eylemler
Eylemler, Action türü veya türevleri olan nesneler tarafından gerçekleştirilir. Eylemlerin yapılandırması <action-mappings> etiketleri içinde yapılır:
<action-mappings>
<action
path="/init"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.SetupLoginsAction"
>
<forward name="afficherLogins" path="/vues/logins.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
<action
path="/infosLogin"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.InfosLoginAction"
>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
<forward name="afficherInfos" path="/vues/infos.jsp"/>
</action>
<action
path="/retourLogins"
parameter="/vues/logins.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
</action-mappings>
/init komutu
<action
path="/init"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.SetupLoginsAction"
>
<forward name="afficherLogins" path="/vues/logins.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
/init eyleminin işleyişini açıklayalım:
- /init eylemi normalde, kullanıcının URL http://localhost:8080/strutsquiest2/init.do'yi talep ettiği ilk istek-yanıt döngüsünde tek bir kez gerçekleşir
- formsLogins nesnesi oluşturulur veya geri dönüştürülür. Bu nesne, scope özniteliğinin gerektirdiği şekilde oturumda geri kazanılır (geri dönüşüm) veya yerleştirilir (oluşturma).
- reset yöntemi çağrılır. Bu yöntemin, ActionForm sınıfında ve türevlerinde varsayılan olarak hiçbir işlem yapmadığını hatırlayalım. Bu yöntem, istemcinin isteğindeki verilerin ActionForm nesnesine kopyalanmasından hemen önce çağrılır ve bu kopyalama işleminden önce nesneyi temizlemek için kullanılır. Burada istemcinin isteği nedir? /init eylemi, istenen URL http://localhost:8080/strutsquiest2/init.do olduğunda tetiklenir. Bu URL nesnesi, bir GET veya bir POST nesnesi tarafından çağrılabilir. Bu isteğe, formLogins'teki alan adlarını taşıyan parametreler eklenmesi yeterlidir; böylece bu alanlar aşağıdaki örnekte gösterildiği gibi başlatılır:

- istek, cmbLogins (afterpak) parametresini içerir. Dolayısıyla Struts denetleyicisi, bu parametrenin değerini formLogins'teki cmbLogins alanına kopyalamıştır. Ardından SetupLoginsAction eylemi gerçekleştirildi ve logins.jsp görünümünün görüntülenmesiyle sonuçlandı. Bu görünümde, bazı alanları değerlerini formLogins'ten alan bir form bulunmaktadır. Böylece, cmbLogins olarak adlandırılan HTML select alanı, formLogins'teki cmbLogins (=afterpak) alanından değerini almıştır. Bu nedenle, oturum açma bilgileri listesi afterpak oturum açma bilgisi üzerinde konumlandırılmış olarak görünür.
- Aşağıdaki şekilde tLogins parametresini de ileterek deneme yapabilirsiniz:
Bu, formLogins alanını {"login1","login2"} dizisiyle başlatır. Ancak, ilerleyen bölümlerde göreceğimiz üzere, SetupLoginsAction eylemi tLogins alanına bir değer atar ve bu şekilde oluşturulan diziyi yeni bir diziyle değiştirir. Dolayısıyla, logins.jsp görünümünde görünen bu yeni dizidir.
- Yukarıdaki tartışma, biraz karmaşık olsa da, /init eyleminin istemciden gelen parametreler olmadan tetikleneceği varsayımında bulunulamayacağını gösterme açısından önemlidir. Bu nedenle, formLogins'i temizlemek için reset yöntemini kullanmak faydalı olabilir. Bu durumda, DynaActionForm sınıfını türetmemiz gerekir. Burada bunu yapmadık.
- formLogins sınıfının reset yöntemi çağrıldığında, denetleyici istemciden gelen istek verilerini formLogins sınıfındaki aynı adlı alanlara kopyalar. Normalde /init eylemi, istemciden parametre alınmadan çağrılır; ancak daha önce, istemcinin /init eylemini rastgele parametrelerle çağırmasını engelleyen hiçbir şeyin olmadığını göstermiştik. Bu aşamanın sonunda, cmbLogins ve tLogins alanlarının bir değere sahip olması gayet olasıdır. cmbLogins alanının bu değeri koruyacağını, ancak tLogins alanının korumayacağını görmüştük.
- Denetleyici daha sonra eylemin validate özniteliğine bakar. Burada bu özniteliğin değeri "false"dır. formLogins'in validate yöntemi çağrılmayacaktır. Dolayısıyla bunu yazmayacağız.
- SetupLoginsAction nesnesi oluşturulur veya daha önce mevcutsa geri dönüştürülür ve execute yöntemi çalıştırılır. Bu nesnenin tek işlevi, formLogins nesnesinin tLogins alanına bir değer atamaktır. Bu değer, kullanıcı adı dizisidir; bu dizi, users iş sınıfından talep edilecektir. Bu işlem başarısız olabilir. Bu nedenle /init eyleminin ardından iki görünüm gelebilir:
- users sınıfı oturum açma bilgilerini içeren diziyi sağlayamadıysa erreurs.jsp görünümü
- aksi takdirde logins.jsp görünümü
- denetleyici bu iki görünümden birini görüntüleyecektir
- /init eyleminin istek-yanıt döngüsü tamamlanmıştır.
/infosLogin eylemi
<action
path="/infosLogin"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.InfosLoginAction"
>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
<forward name="afficherInfos" path="/vues/infos.jsp"/>
</action>
/ infosLogin eyleminin işleyişini açıklayalım:
- /infosLogin eylemi, kullanıcı logins.jsp görünümündeki [Chercher] düğmesine tıkladığında normal olarak gerçekleşir. Bunun üzerine, görünümdeki HTML <form> etiketiyle belirlenen bir istek sunucuya gönderilir:
<html:form name="formLogins" method="get" action="/infosLogin" type="org.apache.struts.action.DynaActionForm">
- Görüldüğü gibi, istek sunucuya GET yöntemi ile gönderilir. Dolayısıyla kullanıcı bunu elle girebilir:

- formsLogins nesnesi oluşturulur veya geri dönüştürülür. Bu nesne, scope özniteliğinin gerektirdiği şekilde oturumda geri alınır (geri dönüşüm) veya yerleştirilir (oluşturma).
- Reset yöntemi, istemciden gelen istek verilerinin ActionForm nesnesine kopyalanmasından hemen önce çağrılır. Bu yöntem normalde http://localhost:8080/strutsquiest2/infosLogin.do?cmbLogins=xx biçimindedir; burada xx, oturum açma adları listesinden seçilen bir oturum açma adıdır. Ancak kullanıcı, önceki URL nesnesini rastgele parametreler geçirerek kullanmışsa, bu değer herhangi bir şey olabilir. Aşağıdaki sayfa dizisini ele alalım:

- /infosLogin eylemi, cmbLogins=xx&tLogins=login1&tLogins=login2 parametre dizisiyle çağrılmıştır. Dolayısıyla, formLogins'in cmbLogins ve tLogins alanları sırasıyla "xx" ve {"login1","login2"} değerlerini alacaktır. /infosLogin eylemi, "xx" kullanıcı adıyla ilişkili bilgileri users iş sınıfından isteyecektir. users sınıfı, bu kullanıcı adının mevcut olmadığını yanıtlayacaktır. Bu nedenle yukarıda gösterilen görünüm ortaya çıkmaktadır. Şimdi, yukarıdaki [Retour au formulaire] bağlantısını kullanalım:

- [Retour au formulaire] bağlantısı tarafından tetiklenen eylem /retourLogins'tir. Bu eylem, herhangi bir ara işlem yapmadan sadece logins.jsp görünümünü görüntüler. Hatırlanacağı üzere, tLogins alanı, logins.jsp görünümündeki oturum açma bilgisi listesini doldurmak için kullanılır. Kullanıcı bu değeri {"login1","login2"} olarak değiştirdiği için, artık listede bu iki oturum açma bilgisi görünmektedir. Yine, bir uygulamanın işleyişinde, kullanıcı veya bir program tarafından belirlenen keyfi parametrelerin mutlaka dikkate alınması gerektiğinin altını çizmek zorundayız. Burada ortaya çıkan sorunun çözümü, [Retour au formulaire] bağlantısının /init eylemine yönlendirilmesi olacaktır. Böylelikle doğru oturum açma bilgisi listesini elde edeceğimizden emin oluruz.
- Şimdi, /infosLogin eylemine yönelik şu türden normal bir isteğe geri dönelim:
http://localhost:8080/strutsquiest2/infosLogin.do?cmbLogins=afterpak
- Struts denetleyicisi, ActionForm nesnesinin cmbLogins alanına bir değer atayacaktır. tLogins alanına ise bir değer atanmayacaktır (gönderilen istekte karşılık gelen bir alan bulunmamaktadır). Bu çalışma şekli bizim için uygundur. Dolayısıyla, formLogins için özel bir reset yöntemi yazmamız gerekmeyecek.
- formLogins'in sıfırlama yöntemi çağrıldığında, denetleyici istemcinin isteğindeki verileri formLogins'teki aynı adlı alanlara kopyalar. cmbLogins alanı, kullanıcı tarafından seçilen kullanıcı adı (afterpak) değerini alacaktır.
- Kontrolör daha sonra eylemin validate özniteliğine bakar. Burada bu özniteliğin değeri "false"dır. formLogins'in validate yöntemi çağrılmayacaktır.
- InfosLoginAction nesnesi oluşturulur veya önceden mevcutsa yeniden kullanılır ve execute yöntemi çalıştırılır. Bu nesnenin görevi, cmbLogins kullanıcı adıyla ilişkili bilgileri almaktır. Bu bilgiler, users iş sınıfından talep edilecektir. Bu işlem başarısız olabilir (örneğin, kullanıcı adı mevcut değilse). Bu nedenle /infosLogin eyleminin ardından iki görünüm gelebilir:
- users sınıfı istenen bilgileri sağlayamadıysa erreurs.jsp görünümü
- aksi takdirde infos.jsp görünümü
- denetleyici bu iki görünümden birini görüntüleyecektir
- /infosLogin eyleminin istek-yanıt döngüsü tamamlanır.
/retourLogins eylemi
<action
path="/retourLogins"
parameter="/vues/logins.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
- /retourLogins eylemi, erreurs.jsp ve infos.jsp görünümlerindeki [Retour au formulaire] bağlantısının etkinleştirilmesiyle tetiklenir.
- Burada eyleme bağlı bir form bulunmamaktadır. Dolayısıyla, doğrudan ForwardAction nesnesinin execute yönteminin yürütülmesine geçilir; bu yöntem, /vues/logins.jsp görünümüne işaret eden bir ActionForward nesnesi döndürür.
7.4.6. Uygulamanın mesaj dosyası
struts-config.xml dosyasının üçüncü bölümü, mesaj dosyasıdır:
ApplicationResources.properties dosyası, WEB-INF/classes/istia/st/struts/quiest dizininde yer almaktadır. İçeriği şöyledir:
errors.header=<ul>
errors.footer=</ul>
parametreManquant=<li>Le paramètre [{0}] n'a pas été initialisé</li>
usersException=<li>Erreur d'initialisation de l'application : {0}</li>
loginInconnu=<li>Le login [{0}] n'existe pas</li>
7.5. Görünüm kodları
Aşağıda sunulan görünüm kodlarını anlamayan okuyucuların, form yönetimi dersini tekrar gözden geçirmeleri önerilir.
7.5.1. logins.jsp görünümü
Bu görünümün iki durumda görüntülendiğini hatırlayalım:
- 1. istek-yanıt döngüsü sırasında /init eylemi çağrıldığında
- sonraki döngülerde /retourLogins eylemi çağrıldığında
logins.jsp görünümünün kodu şöyledir:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Quiest - formulaire</title>
</head>
<body background="<html:rewrite page="/images/standard.jpg"/>">
<center>
<h2>Application QuiEst</h2>
<hr>
<html:form name="formLogins" method="get" action="/infosLogin" type="org.apache.struts.action.DynaActionForm">
<table>
<tr>
<td>Login cherché</td>
<td>
<html:select name="formLogins" property="cmbLogins">
<html:options name="formLogins" property="tLogins"/>
</html:select>
</td>
<td>
<html:submit value="Chercher"/>
</td>
</tr>
</table>
</html:form>
</center>
</body>
</html>
7.5.2. infos.jsp görünümü
Bu görünüm, /infosLogin eylem çağrısının başarıyla gerçekleştirilmesi durumunda görüntülenir. Kodu şöyledir:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html>
<head>
<title><bean:write name="infosLoginBean" scope="request" property="titre"/></title>
</head>
<body background="<html:rewrite page="/images/standard.jpg"/>">
<h2><bean:write name="infosLoginBean" scope="request" property="titre"/></h2>
<hr>
<table border="1">
<tr>
<th>login</th><th>pwd</th><th>uid</th><th>gid</th><th>id</th><th>dir</th><th>shell</th>
</tr>
<tr>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[0]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[1]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[2]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[3]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[4]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[5]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[6]"/></td>
</tr>
</table>
<br>
<html:link page="/retourLogins.do">
Retour au formulaire
</html:link>
</body>
</html>
Bu görünüm, /infosLogin eylemi tarafından sorguya yerleştirilen infosLoginBean adlı bir nesneyi kullanır. Bu nesnenin iki alanı vardır:
String titre; // görünümde görüntülenecek başlık
String[] infosLogin; // görünümde görüntülenecek bilgi tablosu
InfosLoginAction sınıfının kodunu ele alırken bu sınıfı ayrıntılı olarak inceleyeceğiz.
7.5.3. erreurs.jsp görünümü
Bu görünüm, /init veya /infosLogin eylemleri bir hata ile sonuçlandığında görüntülenir. Kod şöyledir:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Application QuiEst - erreurs</title>
</head>
<body background="<html:rewrite page="/images/standard.jpg"/>">
<h2 align="center">Application QuiEst - Erreurs</h2>
<hr>
<h2>Les erreurs suivantes se sont produites</h2>
<html:errors/>
<html:link page="/retourLogins.do">
Retour au formulaire
</html:link>
</body>
</html>
7.6. Java sınıfları
web.xml dosyası bir Java sınıfına atıfta bulunur:
<web-app>
<servlet>
<servlet-name>strutsquiest2</servlet-name>
<servlet-class>istia.st.struts.quiest.Quiest2ActionServlet</servlet-class>
....
</servlet>
...
</web-app>
struts-config.xml yapılandırma dosyası ise iki Java sınıfına atıfta bulunmaktadır:
<action
path="/infosLogin"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.InfosLoginAction"
>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
<forward name="afficherInfos" path="/vues/infos.jsp"/>
</action>
<action
path="/init"
name="formLogins"
validate="false"
scope="session"
type="istia.st.struts.quiest.SetupLoginsAction"
>
<forward name="afficherLogins" path="/vues/logins.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
7.6.1. Quiest2ActionServlet sınıfı
Quiest2ActionServlet sınıfı, Struts denetleyicisi sınıfı olan ActionServlet sınıfından türetilmiştir. ActionServlet sınıfını, init yöntemini özelleştirmek için türetiriz. Nitekim, servletin ilk yüklenmesi sırasında yalnızca bir kez yürütülen bu yöntem, users türünde bir iş nesnesi oluşturmamızı sağlayacaktır. Bu nesnenin aslında yalnızca bir kez oluşturulması gerekir ve init yöntemi bu oluşturma işlemini gerçekleştirmek için uygun bir yerdir. users nesnesinin oluşturulabilmesi için passwd ve group adlı iki dosyaya ihtiyaç vardır. Bu iki dosyanın konumu, uygulamanın web.xml dosyasında servlet’e parametre olarak aktarılır:
<servlet>
<servlet-name>strutsquiest2</servlet-name>
<servlet-class>istia.st.struts.quiest.Quiest2ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>passwdFileName</param-name>
<param-value>data/passwd</param-value>
</init-param>
<init-param>
<param-name>groupFileName</param-name>
<param-value>data/group</param-value>
</init-param>
</servlet>
Servlet kodu şöyledir:
package istia.st.struts.quiest;
import java.util.*;
import javax.servlet.*;
import org.apache.struts.action.*;
import istia.st.users.*;
public class Quiest2ActionServlet
extends ActionServlet {
// servlet öznitelikleri
private users u = null;
private ActionErrors erreurs = new ActionErrors();
private String[] tLogins;
//başlatma
public void init() throws ServletException {
// üst sınıfı başlatmayı unutmayın
super.init();
// yerel değişkenler
final String[] initParams = {"passwdFileName", "groupFileName"};
Properties params = new Properties();
// servletin başlatma parametrelerini alıyoruz
ServletConfig config = getServletConfig();
String servletPath = config.getServletContext().getRealPath("/");
for (int i = 0; i < initParams.length; i++) {
String valeur = config.getInitParameter(initParams[i]);
if (valeur == null) {
erreurs.add(ActionErrors.GLOBAL_ERROR, new ActionError("parametreManquant", initParams[i]));
valeur = "";
}
// parametreyi saklıyoruz
params.setProperty(initParams[i], valeur);
} //for
// başlatma hatası varsa geri dön
if (erreurs.size() != 0) {
return;
}
// users nesnesi oluşturulur
try {
u = new users(servletPath + "/" + params.getProperty("passwdFileName"),
servletPath + "/" + params.getProperty("groupFileName"), null);
}
catch (Exception ex) {
erreurs.add(ActionErrors.GLOBAL_ERROR, new ActionError("usersException", ex.getMessage()));
return;
} //catch
// giriş bilgilerinin listesi alınır
tLogins = new String[u.getUsersByLogin().size()];
Enumeration eLogins = u.getUsersByLogin().keys();
for (int i = 0; i < tLogins.length; i++) {
tLogins[i] = (String) eLogins.nextElement();
}
// giriş bilgilerini sıralıyoruz
Arrays.sort(tLogins);
} //başlatma
// servletin özel bilgilerine erişim yöntemi
public Object[] getInfos() {
return new Object[] {erreurs, u, tLogins};
}
}
Özetle, init yönteminin işleyişi şu şekildedir:
- öncelikle, üst sınıfın (ActionServlet) init yöntemine çağrı yapılır, böylece bu sınıf doğru şekilde başlatılır
- ardından başlatma parametreleri okunur. Eksik parametre varsa, özel ActionErrors hatalar özniteliği doldurulur.
- Başlatma parametreleri mevcutsa, bir users nesnesi oluşturulur. Bu oluşturma işlemi bir istisna oluşturabilir. Bu durumda, ActionErrors hatalar özniteliği doldurulur.
- Oluşturma işlemi başarılı olursa, oluşturulan nesneden tüm oturum açma bilgilerinin listesi alınır ve bu liste bir diziye sıralanarak özel String[] tLogins özniteliğine yerleştirilir.
- Oluşturulan users nesnesi, özel users u özniteliğinde saklanır.
- getInfos adlı genel yöntem, üç özel özniteliği (u, hatalar, tLogins) bir nesne dizisi içinde elde etmeyi sağlar.
7.6.2. SetupLoginsAction sınıfı
Bu eylemin amacı, DynaActionForm formLogins nesnesini başlatmaktır. Oturuma yerleştirilen bu nesnenin daha sonra yeniden başlatılmasına gerek kalmayacaktır. Dolayısıyla SetupLoginsAction eylemi yalnızca bir kez gerçekleştirilir. Kod şöyledir:
package istia.st.struts.quiest;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class SetupLoginsAction
extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException {
// görüntülenecek formun hazırlanması
// kontrol servletinden bilgiler alınır
// bilgiler=(ActionErrors hatalar, kullanıcılar u, String[] tLogins)
Object[] infos = ( (Quiest2ActionServlet)this.getServlet()).getInfos();
// başlatma hataları oldu mu?
ActionErrors erreurs = (ActionErrors) infos[0];
if (!erreurs.isEmpty()) {
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// giriş bilgilerini forma giriyoruz
DynaActionForm formLogins=(DynaActionForm) form;
formLogins.set("tLogins",infos[2]);
return mapping.findForward("afficherLogins");
}
}
Tüm Struts eylemlerinde olduğu gibi, kod execute yönteminde bulunur. Bu yöntem:
- Struts denetleyicisinden, denetleyicinin init yöntemiyle depoladığı bilgileri alır. Bunu sağlayan, Action sınıfındaki getServlet() yöntemidir.
- Bunlar arasında ActionErrors denetleyici hataları özniteliği de bulunmaktadır. Bu hata listesi boş değilse, sorguya eklenir ve erreurs.jsp görünümünün görüntülenmesi istenir.
- Hata listesi boşsa, denetleyici tarafından başlangıçta oluşturulan oturum açma listesi, formLogins bean'inin tLogins alanına atanır. Ardından, oturum açma listesini gösterecek olan logins.jsp görünümünün görüntülenmesi istenir.
7.6.3. InfosLoginBean ve InfosLoginAction sınıfları
InfosLoginAction eyleminin amacı, kullanıcı tarafından seçilen oturum açma bilgileriyle ilgili verileri almak ve bunları kullanıcıya sunmaktır. Veriler, InfosLoginBean türünde bir nesne içinde toplanacaktır:
package istia.st.struts.quiest;
public class InfosLoginBean implements java.io.Serializable{
// bilgi sayfası için gerekli bilgileri içeren bean
private String titre;
private String[] infosLogin;
// oluşturucu
public InfosLoginBean(String titre, String[] infosLogin){
this.titre=titre;
this.infosLogin=infosLogin;
}
// alıcılar
public String getTitre(){
return this.titre;
}
public String[] getInfosLogin(){
return this.infosLogin;
}
public String getInfosLogin(int i){
return this.infosLogin[i];
}
}
Önceki sınıf, c.a.d adlı bir bean'dir. Bu, özel bir T unAttribut özniteliğinin otomatik olarak iki özel yönteme atandığı bir Java sınıfıdır:
- void setUnAttribut(T değer){unAttribut=değer;}
- T getUnAttribut(){ return unAttribut;}
get ve set yöntemlerinin özel sözdizimine dikkat edilmelidir. Öznitelik T[] unAttribut şeklinde bir dizi ise, dizinin elemanları için get ve set yöntemleri oluşturulabilir:
- void setUnAttribut(T değer, int i){unAttribut[i]=değer;}
- T getUnAttribut(int i){ return unAttribut[i];}
Daha iyi anlamak için, InfosLoginAction eyleminin ardından gönderilmesi gereken infos.jsp görünümünün kodunu tekrar inceleyelim:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html>
<head>
<title><bean:write name="infosLoginBean" scope="request" property="titre"/></title>
</head>
<body background="<html:rewrite page="/images/standard.jpg"/>">
<h2><bean:write name="infosLoginBean" scope="request" property="titre"/></h2>
<hr>
<table border="1">
<tr>
<th>login</th><th>pwd</th><th>uid</th><th>gid</th><th>id</th><th>dir</th><th>shell</th>
</tr>
<tr>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[0]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[1]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[2]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[3]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[4]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[5]"/></td>
<td><bean:write name="infosLoginBean" scope="request" property="infosLogin[6]"/></td>
</tr>
</table>
<br>
<html:link page="/retourLogins.do">
Retour au formulaire
</html:link>
</body>
</html>
Şu etiketi ele alalım:
Sorguya (scope) eklenen infosLoginBean (name) nesnesinin “title” (property) alanının değerini yazmasını ister. Yazılacak değer, request.getAttribute("infosLoginBean") komutuyla elde edilecektir.getTitre(). Dolayısıyla, InfosLoginBean sınıfında getTitre yöntemi bulunmalıdır. Durum böyledir. Etiket
etiketi, sorguya eklenen infosLoginBean nesnesinin infosLogin[0] öğesinin değerini yazmayı talep eder. Yazılacak değer, request.getAttribute("infosLoginBean").getInfosLogin(0) ile elde edilecektir. Bu nedenle, InfosLoginBean sınıfında getInfosLogin(int i) yöntemi bulunmalıdır. Bu durum geçerlidir.
InfosLoginAction sınıfının amacı, kullanıcı tarafından seçilen bir kullanıcı adı temelinde önceki InfosLoginBean nesnesini oluşturmaktır. Kod şöyledir:
package istia.st.struts.quiest;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import istia.st.users.*;
public class InfosLoginAction
extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException {
// bir oturum açma bilgisiyle ilgili bilgileri görüntülemelidir
// kontrol servletinden bilgileri alır
// bilgiler=(ActionErrors hatalar, kullanıcılar u, LoginBean[] tLogins)
Object[] infos = ( (Quiest2ActionServlet)this.getServlet()).getInfos();
// başlatma hataları oldu mu?
ActionErrors erreurs = (ActionErrors) infos[0];
if (!erreurs.isEmpty()) {
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// öncelikle bu oturum açma bilgilerini al
String login = (String) ( (DynaActionForm) form).get("cmbLogins");
// bir şey var mı?
if (login == null) {
// Bu normal değil – giriş bilgilerini içeren formu geri gönderiyoruz
DynaActionForm formLogins=(DynaActionForm) form;
formLogins.set("tLogins",infos[2]);
return mapping.findForward("afficherLogins");
}
// bir giriş bilgisi var - aranıyor
String[] infosLogin = (String[]) ( (users) infos[1]).getUsersByLogin().get(login);
// bulundumu?
if (infosLogin == null) {
// giriş bilgisi bulunamadı - hata sayfası görüntüleniyor
ActionErrors erreurs2=new ActionErrors();
erreurs2.add(ActionErrors.GLOBAL_ERROR, new ActionError("loginInconnu", login));
this.saveErrors(request, erreurs2);
return mapping.findForward("afficherErreurs");
}
// giriş bilgisi bulundu - bulunan bilgileri isteğe ekleniyor
String titre="Application QuiEst - login["+login+"]";
InfosLoginBean infosLoginBean= new InfosLoginBean(titre,infosLogin);
request.setAttribute("infosLoginBean",infosLoginBean);
return mapping.findForward("afficherInfos");
}
}
execute yönteminin işleyişi şu şekildedir:
- Struts denetleyicisi tarafından başlatma sırasında toplanan bilgiler alınır. Denetleyici herhangi bir hata kaydetmişse, işlem burada durur ve bu hataların görüntülenmesi istenir.
- Bir kullanıcı adı olup olmadığı kontrol edilir. Kullanıcı, kullanıcı adı seçim formunu kullanmışsa, kullanıcı adı mevcuttur. Ancak kullanıcı, herhangi bir parametre girmeden eylemin URL'sini doğrudan tarayıcısına girebilir. Kullanıcı adı yoksa, kullanıcı adları listesi yeniden görüntülenir.
- Kullanıcı adı varsa, users iş sınıfıyla ilişkili bilgiler istenir. Bu sınıf aranan kullanıcı adını bulamazsa, hata sayfası görüntülenir. Aksi takdirde, infos.jsp görünümünün ihtiyaç duyduğu bilgileri içermesi için bir InfosLoginBean nesnesi oluşturulur. Bu nesne isteğe eklenir ve infos.jsp sayfası görüntülenir.
7.7. Dağıtım
Uygulamanın dizin yapısı şu şekildedir:
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() |
7.8. Sonuç
Bir iş sınıfı kullanan gerçekçi bir uygulamada Struts'u kullandık. Ayrıca, bir istemci tarafından gönderilen isteğe özellikle dikkat edilmesi ve isteğin niteliği hakkında hiçbir varsayımda bulunulmaması gerektiğini gösterdik. Bir istek herhangi bir şekilde olabilir ve her uygulama öncelikle bu isteğin geçerliliğini doğrulamalıdır.











