4. Dinamik formların kullanımı
4.1. Dinamik formun tanımlanması
Struts'un, uygulamanın çeşitli servletleri tarafından işlenen HTML formlarının değerlerini depolamak için ActionForm nesnelerini kullandığını görmüştük. Uygulamamızdaki her form için, ActionForm sınıfından türetilmiş bir sınıf oluşturmamız gerekir. Bu işlem hızla oldukça zahmetli hale gelebilir; çünkü her xx alanı için setXx ve getXx adlı iki yöntem yazmamız gerekir. Struts bize,
- kullanma imkanı sunar; bu formların yapısı, Struts ortamı tarafından bildirilen yapıya göre <form-beans> bölümünde yer alan struts-config.xml dosyasında
- bölümünde tanımlanmış olan ve Struts ortamı tarafından belirtilen yapıya göre dinamik olarak oluşturulan formları kullanma imkânı sunar
Böylece, strutspersonne uygulamasının isim ve yaş değerlerini depolamak için kullanılan sınıf şu şekilde tanımlanabilir:
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.actions.DynaActionForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
Formun her bir alanı için, iki özniteliğe sahip bir <form-property> etiketi tanımlanır:
- name: alanın adı
- type: Java türü
Bir web istemcisi tarafından gönderilen form değerleri karakter dizileri olduğundan, en yaygın kullanılan türler tek değerli alanlar için java.lang.String ve çok değerli alanlar için (aynı ada sahip onay kutuları, çoklu seçim listeleri vb.) java.lang.String[]'dir. DynactionForm sınıfı da ActionForm sınıfı gibi hiçbir işlem yapmayan bir validate yöntemine sahiptir. Form parametrelerinin geçerliliğini kontrol etmesini sağlamak için bu sınıftan türetme yapmalı ve validate yöntemini kendiniz yazmalısınız. Dolayısıyla formun tanımlaması şu şekilde olacaktır:
<form-beans>
<form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
istia.st.struts.personne.PersonneDynaForm sınıfı tarafımızca yazılmalıdır.
4.2. Dinamik formla ilişkili DynaActionForm sınıfının yazılması
Yukarıda, istia.st.struts.personne.PersonneDynaForm sınıfını (ad, yaş) formuna bağladık. Şimdi bu sınıfı yazıyoruz:
package istia.st.struts.personne;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class PersonneDynaForm extends DynaActionForm {
// doğrulama
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// hata yönetimi
ActionErrors erreurs = new ActionErrors();
// ad alanı boş olmamalı
String nom = (String)this.get("nom");
if (nom == null || nom.trim().equals("")) {
erreurs.add("nomvide", new ActionError("personne.formulaire.nom.vide"));
}
// yaş alanı boş olmamalıdır
String age = (String)this.get("age");
if (age == null || age.trim().equals("")) {
erreurs.add("agevide", new ActionError("personne.formulaire.age.vide"));
}
else {
// yaş, pozitif bir tamsayı olmalıdır
if (!age.matches("^\\s*\\d+\\s*$")) {
erreurs.add("ageincorrect", new ActionError("personne.formulaire.age.incorrect", age));
// hata listesi döndürülür
}
} //if
// hata listesi döndürülür
return erreurs;
}
}//sınıf
Dikkat edilmesi gereken noktalar şunlardır:
- sınıf, DynaActionForm sınıfından türetilmiştir
- DynaActionForm sınıfının validate yöntemi yeniden yazılmıştır. Struts denetleyicisi tarafından çalıştırıldığında, PersonneDynaForm nesnesi oluşturulmuştur. Bu nesne, anahtarları formdaki "nom" ve "age" alanları, değerleri ise bu alanların değerleri olan bir sözlük içerir. DynaActionForm sınıfındaki yöntemler içinde bir alana erişmek için Object get(String nomDuChamp) yöntemi kullanılır. Bir alana değer atamak istendiğinde, void set(String nomDuChamp, Object değer) yöntemi kullanılabilir. Tam bir tanım için DynaActionForm sınıfının tanımına bakınız.
- Formun nom ve age alanlarının değerleri alındıktan sonra, validate yöntemi, formun bir ActionForm nesnesine bağlandığında yazılan yöntemden farklı değildir.
4.3. Yeni FormulaireAction sınıfı
Yapılandırma dosyası, aşağıdaki /main eylemini tanımlar:
...
<form-beans>
<form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
....
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
type="istia.st.struts.personne.FormulaireAction"
>
<forward name="reponse" path="/reponse.do"/>
</action>
Bu tanım, strutspersonne uygulamasındakiyle aynıdır. /main eylemi, FormulaireAction türünde bir nesne tarafından gerçekleştirilir. Bu nesne, frmPersonne formundaki değerleri FormulaireBean türünde bir nesne içinde alırdı. Artık bu değerleri PersonneDynaForm türündeki bir nesneye alıyor. Dolayısıyla sınıfı yeniden yazmak gerekiyor:
package istia.st.struts.personne;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import javax.servlet.ServletException;
import istia.st.struts.personne.PersonneDynaForm;
public class FormulaireAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException {
// Form geçerliyse, aksi takdirde bu noktaya gelemezdik
PersonneDynaForm formulaire=(PersonneDynaForm)form;
request.setAttribute("nom",formulaire.get("nom"));
request.setAttribute("age",formulaire.get("age"));
return mapping.findForward("reponse");
}//işleme
}
Dikkat edilmesi gereken noktalar şunlardır:
- Form verilerini içeren PersonneDynaForm sınıfını, tanımına erişebilmek için içe aktarmamız gerekir
- execute yöntemi, [DynaActionForm].get yöntemi ile form parametrelerinin değerlerini alır.
strutspersonne uygulamasındaki FormulaireAction sınıfına gelince, yalnızca form değerlerine erişim şekli değişmiştir.
4.4. strutspersonne1 uygulamasının dağıtımı ve testi
4.4.1. Bağlamın oluşturulması
Bu yeni uygulamaya strutspersonne1 adını verdik. Tomcat'in <tomcat>\conf\serveur.xml dosyasında 4.x için yeni bir tanım oluşturuyoruz:
Bu işlem tamamlandıktan sonra Tomcat'i yeniden başlatmak gerekiyor. URL dosyasını çağırarak bağlamın geçerliliğini kontrol edebiliriz:
http://localhost:8080/strutspersonne1/

4.4.2. Görünümler
strutspersonne uygulamasının "vues" klasörünü strutspersonne1 uygulamasının klasörüne kopyalayacağız. Zira görünümlerde herhangi bir değişiklik olmamıştır.

4.4.3. Sınıfların derlenmesi
Oluşturmamız gereken iki sınıf var: PersonneDynaForm ve FormulaireAction; ikincisi, birincisini kullanıyor. Bunları bir JBuilder projesi yardımıyla oluşturabilir ve derleyebiliriz:

4.4.4. WEB-INF klasörü
strutspersonne uygulamasındaki WEB-INF klasörünü strutspersonne1 uygulamasının klasörüne kopyalayacağız. Bazı dosyalar değişecek:

struts-config.xml yapılandırma dosyası şu şekilde değişir:
<?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="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
<action-mappings>
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/erreurs.do"
type="istia.st.struts.personne.FormulaireAction"
>
<forward name="reponse" path="/reponse.do"/>
</action>
<action
path="/erreurs"
parameter="/vues/erreurs.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/reponse"
parameter="/vues/reponse.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/formulaire"
parameter="/vues/formulaire.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
</action-mappings>
<message-resources parameter="ressources.personneressources"/>
</struts-config>
Bu dosya, formun dinamik tanımı (çerçeveli kısım) dışında strutspersonne uygulamasındaki dosyayla aynıdır.
WEB-INF/classes klasörüne, JBuilder tarafından derlenen sınıflar yerleştirilecektir:

WEB-INF\classes\ressources klasörüne mesaj dosyası yerleştirilir. Bu dosya değişmemiştir.
personne.formulaire.nom.vide=<li>Vous devez indiquer un nom</li>
personne.formulaire.age.vide=<li>Vous devez indiquer un age</li>
personne.formulaire.age.incorrect=<li>L'âge [{0}] est incorrect</li>
errors.header=<ul>
errors.footer=</ul>

4.5. Testler
Testlere hazırız. Aşağıda, okuyucunun taklit etmesi istenen birkaç ekran görüntüsü bulunmaktadır.
URL http://localhost:8080/strutspersonne1/formulaire.do adresi isteniyor:

Alanları doldurmadan [Envoyer] düğmesini kullanıyoruz:

"age" alanında bir hata oluşacak şekilde işlemi tekrar yapalım:

Aşağıdaki yanıtı alıyoruz:

Bu sefer doğru değerleri girerek tekrar deniyoruz:

Şu yanıtı alıyoruz:

4.6. Sonuç
Dinamik formların kullanılması, form değerlerini depolamaktan sorumlu ActionForm türü sınıfların yazılmasını kolaylaştırır. Form yönetimini basitleştirme konusunda biraz daha ileri gidebiliriz. strutspersonne1 uygulamasında, formdaki değerlerin (ad, yaş) geçerliliğini kontrol etmek için PersonneDynaForm sınıfını oluşturduk. Uygulamada, bazı kontroller sık sık tekrarlanır: alanın boş olmaması, belirli bir düzenli ifadeyi kontrol eden alan, tamsayı alanı, tarih alanı vb. Bu tür standart doğrulamalar, struts-config.html yapılandırma dosyasında talep edilebilir. Yapılması gereken tüm doğrulamalar "standart" ise, form için ayrı bir sınıf yazmaya gerek kalmaz. Şimdi bunu inceleyeceğiz.