Monday 23 July 2007

Struts Action .. DispatchAction .. LookupDispatchAction ..

Struts'ta servlet'lerimizi Action'a extend ederek execute metodu içinde tüm aksiyonumuzu alırız. Birçok işlem için aynı action'a geldiğimiz olur. Bu durumda execute içinden ilgili durumlarda ilgili metodlara yönlendirme yaparız.

Bu yönlendirmenin struts tarafından yapılmasını DispatchAction sayesinde sağlayabiliriz. Şöyle ki, müşteri bilgileri ekranımız olsun ve bu ekrandan müşterinin bilgilerini güncelleyebilelim, yeni müşteri ekleyebilelim ve ekranda görünen mevcut müşteriyi silebilelim. Bu aksiyonların her biri için bir action yazıp her bir action'a gidecek birer buton koyabiliriz. Ya da bir action yazıp execute içinden ilgili işlem için ilgili metodun çağrılmasını sağlayabiliriz. Ama bir parametre yollasak ve action bu işlem için yönlendirmeyi kendisi yapsa daha güzel olmaz mı? Burada yapmamız gereken ufak birkaç şey var. Action'ımızı DispatchAction'a extend edip struts-config'de tanımladığımız parametreyi, gitmesini istediğimiz metod ismine jsp tarafında set edeceğiz. Submit ediyorsak bu parametreyi hidden bir input değeri olarak action'a yollayacağız. Url ile ekranın location'ını set ediyorsak aynı parametre ismiyle URL sonuna bu değeri ekleyeceğiz.


struts-config içine:
<action path="/sample"
 parameter="methodToGo"
 type="SampleAction"
 name="sampleForm"
 scope="request"
 validate="false">
 ...
</action>

Buradaki parameter, DispatchAction'ın hangi metoda gideceğini bilmesini sağlayan parametredir. Parameter değeri, gidilecek metodun ismidir.
Ardından, jsp'de methodToGo isminde hidden bir değer tutmamız ve yapılacak işleme göre bu hidden alanın değerini set etmemiz yeterli olacaktır.
Bunun için, örneğin, ekranda güncelle butonuna basıldığında methodToGo değerini, javascript vasıtasıyla update'e set ederiz. Form submit edildiğinde methodToGo değerini update gönderdiğimiz için, action'ımızın direk update metodu çağrılacaktır.
Ekleme işlemi için de örneğin Ekle butonuna basıldığında javascript vasıtasıyla yine methodToGo alanının değerini add'e set ederiz. Böylece, action'ımızdaki add metodunun direk çağrılmasını sağlarız.

DispatchAction, execute metodu içindeki yığınla kontrolden ve kod karmaşasından bizi kurtarır. Ama genel bir yapı oluşturuyorsak ve bu yapıyı kullanacak makinelerin standart bir yapısı yoksa yani bizim uygulamamızı kullanacak olan kişilerin bilgisayar konfigürasyonlarına bir standart getiremiyorsak, o zaman bu kullanıcıların explorer'larında javascript'in enabled olup olmadığını da bilemeyiz. Eğer javascript enabled değilse dispatchAction için gerekli olan parametreyi de ekrandan alınmak istenen aksiyona göre değiştiremeyiz ve sistemimiz çalışmaz ya da yanlış çalışır. Kaldı ki, ilgili aksiyon için ilgili metodu otomatik olarak harekete geçiren bir yapıdan söz ederken hala jsp tarafında javascript vasıtasıyla manuel olarak parametre set edilmesi bu sistem içinde ufak da olsa bir ikilem oluşturuyor gibi görünüyor. Bu noktada, dispatch action'ı bir adım öteye götürerek LookupDispatchAction'ın kullanılmasını tavsiye ederim. Ben de bunun varlığını yeni öğrendim ve bir deneme yaptım.

LookupDispatchAction, ekrandaki butonun value kısmını dikkate alarak aksiyon alır. DispatchAction'daki parametre kullanılır yine ama bu parametre butonların property değerine set edilir.

struts-config içine:
<action path="/sample2"
 parameter="methodToGo"
 type="Sample2Action"
 name="sample2Form"
 scope="request"
 validate="false">
 ...
</action>

jsp icine de istediğimiz gibi butonları ekliyoruz.

<html:form action="/sample2">
<html:submit property="methodToGo">
<bean:message key="label.sample.insert"/>
</html:submit>
<html:submit property="methodToGo">
<bean:message key="label.sample.update"/>
</html:submit>
</html:form>

Burada gidilecek olan metodu belirleyen submit butonunun value'su yani message.resource içinde almış olduğumuz label.sample.insert ve label.sample.update değerleri.

Yapılması gereken başka bir değişiklik de, DispatchAction yerine LookupDispatchAction'a extend eden action'ımıza eklemek zorunda olduğumuz getKeyMethodMap metodu.

Bunun için de;
protected Map getKeyMethodMap(){
Map map = new HashMap();
map.put("label.sample.insert", "add");
map.put("label.sample.update", "update");
return map;
}

metodunu ekliyorum ve add ve update adında iki metod hazırlıyorum.

Unutmamam gereken birkaç nokta var. Onları da eklemeliyim. Öncelikle, message property dosyama label.sample.insert ve label.sample.update eklemeliyim. İkinci olarak da bu properties dosyasının struts-config'e eklenmiş olduğundan emin olmalıyım.

Çalıştırmaya çalışırken karşılaşılması olası genel bir hata var:
javax.servlet.ServletException: Action[/sample2] missing resource 'label.sample.insert' in key method map
at org.apache.struts.actions.LookupDispatchAction.getLookupMapName(LookupDispatchAction.java:240)
at org.apache.struts.actions.LookupDispatchAction.getMethodName(LookupDispatchAction.java:281)
...

Öncelikle message resource dosyasının doğru olduğunu kontrol etmek gerekiyor. Ve bu dosyanın kesinlikle struts-config içine eklenmiş olması gerekiyor:

<message-resources parameter="MessageResources"/>

getKeyMethodMap metodu içinde tanımladığımız hashMap'in içindeki değerlerin de doğru olduğundan emin olmak gerek. Resource dosyasında tanımladığımız buton isimlerinin sonunda boşluk olmadığından da emin olmalıyız.

Ayrıca, url'den lookupDispatchAction'a extend etmiş bir action'ı çağırırken parametreyi set edip erişmeye çalışıldığında da bu hatayı alabiliriz.

LookupDispatchAction kullanırken karşılaşılan bir sıkıntı var. Ona da değinmek lazım. Butonların property'lerini parametre ismine set ettiğimiz için javascript'le erişimde sıkıntı çekebiliriz. document.all("...") veya benzeri javascript çağırmaları çalışmayabilir. Tüm bu ayrıntılar göz önünde bulundurularak karar verilmelidir diye düşünüyorum. Nicazane görüşüm; ben şimdilik DispatchAction'dan memnunum ve sürekli onu kullanıyorum :)

1 comment:

hakdogan said...

Teşekkürler hocam, güzel paylaşım. Struts, JSF, Hibernate gibi konularda Türkçe kaynak sıkıntısını göz önüne alırsak bu tip paylaşımların değeri daha iyi anlaşılır...