5. Bütünlük kısıtlamaları içeren dinamik formlar
Şimdi, strutspersonne1'deki gibi
- strutspersonne1'deki gibi dinamik bir form kullanacağız
- bu dinamik formun alanları tarafından doğrulanacak bütünlük kısıtlamalarını içeren bir bildirim dosyası
5.1. Bütünlük kısıtlamalarının tanımlanması
strutspersonne1 uygulamasında isim ve yaş değerlerini depolamak için kullanılan sınıf şu şekilde tanımlanmıştı:
<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>
Dinamik formdaki “ad” ve “yaş” değerlerinin geçerli olup olmadığını kontrol edebilecek bir doğrulama yöntemi oluşturmak için PersonneDynaForm sınıfını yazmak zorunda kaldık. Yapılması gereken doğrulamalar iki türdü:
- her iki alan da boş olmamalıydı
- "age" alanı, \s*\d+\s* maskesini (düzenli ifade) karşılamalıydı
Bu iki doğrulama, StrutsValidator ortamının gerçekleştirebileceği doğrulamalar arasında yer almaktadır. Bu ortam Struts ile birlikte gelir ve commons-validator.jar ile jakarta-oro.jar'te bulunan bir dizi sınıfı içerir. Belgenin başında açıklanan, Struts kütüphanelerini Tomcat içine kurma prosedürünü uyguladıysanız, bu kütüphaneler Tomcat'te zaten mevcuttur. Bunların JBuilder'da da mevcut olduğundan emin olun. Bu konu da belgenin başında açıklanmıştır.
struts-config.xml dosyasındaki yeni form bildirimi şu şekilde olur:
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
</form-beans>
Dolayısıyla çok az fark vardır. Dinamik formla ilişkili sınıf artık StrutsValidator'in önceden tanımlanmış bir sınıfıdır: org.apache.struts.validator.DynaValidatorForm. Geliştiricinin artık bir sınıf yazması gerekmiyor. Formun doğrulaması gereken bütünlük kısıtlamalarını ayrı bir XML dosyasında belirtir. Struts denetleyicisi bu dosyanın adını bilmelidir. Bunun için struts-config.xml dosyasında yeni bir yapılandırma bölümü ortaya çıkıyor:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
/>
</plug-in>
<plug-in> bölümü, Struts dışındaki bir sınıfı yüklemek için kullanılır. Ana özniteliği, örneklenecek sınıfın adını belirten classname'dir. Örneklenen nesnenin başlatılması gerekebilir. Bu, iki özniteliğe sahip set-property etiketleri aracılığıyla yapılır:
- property: başlatılacak özelliğin adı
- value: özelliğin değeri
Burada, DynaValidatorForm sınıfının iki bilgiye ihtiyacı vardır:
- XML dosyası; bu dosya, sınıfın doğrulayabildiği standart bütünlük kısıtlamalarını tanımlar.
- uygulamadaki çeşitli dinamik formların bütünlük kısıtlamalarını tanımlayan XML dosyası
Bu iki bilgi burada pathnames özelliği tarafından sağlanır. Bu özelliğin değeri, doğrulayıcının yükleyeceği XML dosyalarının bir listesidir:
- validator-rules.xml, standart bütünlük kısıtlamalarını tanımlayan dosyadır. Bu dosya Struts ile birlikte gelir. <struts>\lib dizininde, tanım dosyası olan DTD ile birlikte bulunur:
![]()
- validation.xml, uygulamanın çeşitli dinamik formlarının bütünlük kısıtlamalarını tanımlar. Bu dosya geliştirici tarafından oluşturulur. Adı serbesttir.
Bu iki dosya, WEB-INF dosyasının altındaki herhangi bir yere yerleştirilebilir. Örneğimizde, bu dosyalar doğrudan WEB-INF dosyasının altına yerleştirilecektir:

5.2. Dinamik formların bütünlük kısıtlamalarının yazılması
validation.xml dosyası, org.apache.struts.validator.DynaValidatorForm türündeki frmPersonne formunun isim ve yaş alanları için bütünlük kısıtlamalarımızı içerecektir. İçeriği şöyledir:
<form-validation>
<global>
<constant>
<constant-name>entierpositif</constant-name>
<constant-value>^\s*\d+\s*$</constant-value>
</constant>
</global>
<formset>
<form name="frmPersonne">
<field property="nom" depends="required">
<arg0 key="personne.nom"/>
</field>
<field property="age" depends="required,mask">
<arg0 key="personne.age"/>
<var>
<var-name>mask</var-name>
<var-value>${entierpositif}</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
Uyulması gereken yazım kuralları şunlardır:
- Tüm kurallar <form-validation> etiketinin içinde yer almaktadır.
- <global> etiketi, küresel kapsamda bilgiler tanımlamak için kullanılır, c.a.d. Birden fazla form varsa, bu bilgiler tüm formlar için geçerlidir. Burada <global> içine sabitler yerleştirilmiştir. Bir sabit, adı (<constant-name> etiketi) ve değeri (<constant-value> etiketi) ile tanımlanır. entierpositif sabitini, pozitif bir tamsayının karşılaması gereken düzenli ifadeyi değer olarak kullanarak tanımlıyoruz: ^\s*\d+\s*$ (önünde ve/veya sonunda boşluk bulunabilen bir rakam dizisi).
- <formset> etiketi, doğrulanması gereken bütünlük kısıtlamaları bulunan formların kümesini tanımlar
- <form name="unFormulaire"> etiketi, name özniteliğiyle adı belirtilen belirli bir formun bütünlük kısıtlamalarını tanımlamak için kullanılır. Bu ad, struts-config.xml içinde tanımlanan formlar listesinde mevcut olmalıdır. Burada kullanılan frmPersonne formu, struts-config.xml içinde aşağıdaki bölümle tanımlanmıştır:
<form-beans>
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
- Bir <form> etiketi, form için doğrulanacak bütünlük kısıtlamalarının sayısı kadar <field> etiketi içerir. Bir <field> etiketi aşağıdaki özniteliklere sahiptir:
- property: bütünlük kısıtlamalarının tanımlandığı form alanının adı
- depends: doğrulanacak bütünlük kısıtlamalarının listesi.
- Olası kısıtlamalar şunlardır: required (alan boş olmamalıdır), mask (alanın değeri mask değişkeni ile tanımlanan düzenli ifadeye uymalıdır), integer: alanın değeri tamsayı olmalıdır, byte (bayt), long (uzun tamsayı), float (tek hassasiyetli gerçek sayı), double (çift hassasiyetli gerçek sayı), short (kısa tamsayı), date (alanın değeri geçerli bir tarih olmalıdır), range (alanın değeri belirli bir aralıkta olmalıdır), email: (alanın değeri geçerli bir e-posta adresi olmalıdır), ...
- bütünlük kısıtlamaları, depends özniteliğindeki sıraya göre kontrol edilir. Bir kısıtlama doğrulanmazsa, sonraki kısıtlamalar test edilmez.
- Her kısıtlama, bir anahtarla tanımlanan bir hata mesajıyla ilişkilidir. İşte bunlardan bazıları kısıtlama (anahtar) biçiminde: required (errors.required), mask (errors.invalid), integer (errors.integer), byte (errors.byte), long (errors.long), ...
- Yukarıdaki anahtarlarla ilişkili hata mesajları validator-rules.xml dosyasında tanımlanmıştır:
# Struts Validator Hata Mesajları
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.
errors.float={0} must be a float.
errors.double={0} must be a double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address.
- Yukarıda mesajların İngilizce olduğunu görüyoruz. Ayrıca, bunlar dosyada yorum olarak yer almaktadır ve bu yorumlarda, mesajların uygulamanın mesaj dosyasına eklenmesi gerektiği belirtilmektedir. Bu dosyanın, struts-config.xml dosyasının bir bölümünde tanımlandığını hatırlayalım:
parameter özniteliği, uygulama mesajlarının şu dosyada bulunduğunu belirtir:
WEB-INF/classes/ressources/personneressources.properties dosyasındadır.
Dolayısıyla hata mesajları bu dosyaya yerleştirilmelidir. Bunlar, halihazırda mevcut olanlara eklenir:
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 est incorrect</li>
errors.header=<ul>
errors.footer=</ul>
# Struts Validator hata mesajları
# anahtar önceden tanımlanmıştır ve değiştirilmemelidir
# İlgili hata mesajı serbesttir
# Mesajda {0} ila {3} arasında en fazla 4 parametre olabilir
errors.required=<li>Le champ [{0}] doit être renseigné.</li>
errors.minlength=<li>Le champ [{0}] foit avoir au moins {1} caractère.</li>
errors.maxlength=<li>Le champ [{0}] ne peut avoir plus de {1} caractères.</li>
errors.invalid=<li>Le champ [{0}] est incorrect.</li>
errors.byte=<li>{0} doit être un octet.</li>
errors.short=<li>{0} doit être un entier court.</li>
errors.integer=<li>{0} doit être un entier.</li>
errors.long=<li>{0} doit être un entier long.</li>
errors.float=<li>{0} doit être un réel simple.</li>
errors.double=<li>{0} doit être un réel double.</li>
errors.date=<li>{0} n'est pas une date valide.</li>
errors.range=<li>{0} doit être dans l'intervalle {1} à {2}.</li>
errors.creditcard=<li>{0} n'est pas un numéro de carte valide.</li>
errors.email=<li>{0} n'est pas une adresse électronique valide.</li>
personne.nom=nom
personne.age=age
validation.xml dosyasının bütünlük kısıtlamalarını tek tek ele alalım ve açıklayalım:
<formset>
<form name="frmPersonne">
<field property="nom" depends="required">
<arg0 key="personne.nom"/>
</field>
...
</form>
</formset>
Bu bütünlük kısıtlamalarının, struts-config.xml'te tanımlanan dinamik bir formun "nom" ve "age" alanlarına uygulandığını hatırlatmak isteriz:
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="nom" type="java.lang.String" initial=""/>
<form-property name="age" type="java.lang.String" initial=""/>
</form-bean>
Her iki dosyada da formun ve formdaki alanların adlarının aynı olması önemlidir. "nom" alanı üzerindeki bütünlük kısıtlaması (property="nom"), alanın boş olmaması gerektiğini belirtir (depends="required"). Aksi takdirde, errors.required anahtarına sahip bir ActionError nesnesi oluşturulur. Bu anahtarla ilişkili mesaj, personne.ressources.properties dosyasında bulunur:
Bu mesajın {0} parametresini kullandığı görülmektedir. Bu parametrenin değeri, bütünlük kısıtlamasındaki <arg0> etiketiyle belirlenir:
Burada da arg0, mesaj dosyasında da bulunan bir anahtarla belirtilmiştir:
Tüm bunları bir araya getirirsek, nom alanı doldurulmadığında oluşturulan hata mesajı şöyledir:
Şimdi ikinci kısıtlamayı, yani "age" alanıyla ilgili olanı inceleyelim:
<global>
<constant>
<constant-name>entierpositif</constant-name>
<constant-value>^\s*\d+\s*$</constant-value>
</constant>
</global>
<formset>
<form name="frmPersonne">
...
<field property="age" depends="required,mask">
<arg0 key="personne.age"/>
<var>
<var-name>mask</var-name>
<var-value>${entierpositif}</var-value>
</var>
</field>
</form>
</formset>
"age" alanı için iki kısıtlama vardır: "required" ve "mask". "required" kısıtlaması için önceki açıklamayı tekrarlayabiliriz. Sonuç olarak, bu kısıtlamayla ilişkili hata mesajı şöyledir:
İkinci kısıtlama ise mask’tır. Bu, alan içeriğinin bir düzenli ifadeyle ifade edilen şablona uyması gerektiği anlamına gelir. Bu kısıtlamanın değeri, mask (<var-name>) adlı ve değeri ${entierpositif} (<var-value>) olan bir değişkeni tanımlayan <var> etiketinde belirlenir. entierpositif, dosyanın <global> bölümünde tanımlanan ve değeri ^\s*\d+\s*$ düzenli ifadesi olan bir sabittir. Dolayısıyla bütünlük kısıtlaması, yaşın, önünde veya arkasında boşluk bulunabilen bir veya daha fazla rakamdan oluşan bir dizi olması gerektiğidir. Bu kısıtlama doğrulanmazsa, errors.invalid anahtarına sahip bir ActionError nesnesi oluşturulur. Mesaj dosyasında, bu anahtar aşağıdaki mesajla ilişkilendirilmiştir:
Kısıtlama, {0} parametresi için bir değer tanımlamalıdır. Bunu <arg0> etiketiyle yapar:
Mesaj dosyasında, personne.age anahtarı aşağıdaki mesajla ilişkilendirilmiştir:
mask kısıtlaması doğrulanmazsa oluşturulacak hata mesajı şudur:
5.3. Uygulamanın sınıfları
Bir Struts uygulamasında yazılması gereken sınıflar, form sınıfları (ActionForm veya türevleri) ve eylem sınıflarıdır (Action veya türevleri). Yeni strutspersonne2 uygulamasında artık form sınıfı bulunmamaktadır. Formun içeriği struts-config.xml'te, ilgili bütünlük kısıtlamaları ise WEB-INF/validation.xml'te tanımlanmıştır. strutspersonne1 uygulamasında, form işleme sınıfı FormulaireAction şu şekildeydi:
package istia.st.struts.personne;
....
public class FormulaireAction
extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException {
// Form geçerlidir; aksi takdirde buraya gelemezdik
DynaActionForm formulaire=(DynaActionForm)form;
request.setAttribute("nom",formulaire.get("nom"));
request.setAttribute("age",formulaire.get("age"));
return mapping.findForward("reponse");
}//çalıştır
}
FormulaireAction sınıfı, DynaActionForm nesnesi biçiminde bir form almayı bekliyordu (çerçeveli kod). Ancak struts-config.xml dosyasında, form sınıfı şu şekilde tanımlanmıştır:
<form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
...
</form-bean>
Dolayısıyla form, DynaValidatorForm türünde bir nesneye yerleştirilecektir. Bu sınıfın, DynaActionForm sınıfından türetildiği görülmektedir. Dolayısıyla, FormulaireAction sınıfımızdaki execute yöntemi geçerliliğini korumaktadır. Bu yöntemin yeniden yazılmasına gerek yoktur.
5.4. strutspersonne2 uygulamasının dağıtımı ve testi
5.4.1. Bağlamın oluşturulması
Bu yeni uygulamaya strutspersonne2 adını verdik. Tomcat 4.x'in <tomcat>\conf\serveur.xml dosyasında 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/strutspersonne2/

5.4.2. Görünümler
strutspersonne1 uygulamasının “vues” klasörünü strutspersonne2 uygulamasının klasörüne kopyalayacağız. Zira görünümlerde herhangi bir değişiklik olmamıştır.

5.4.3. WEB-INF klasörü
strutspersonne1 uygulamasının WEB-INF klasörünü strutspersonne2 uygulamasının klasörüne kopyalayacağız. Bazı dosyalar değişmiştir:

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="org.apache.struts.validator.DynaValidatorForm">
<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"
validate="true"
input="/erreurs.do"
scope="session"
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"
null="false"
/>
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
/>
</plug-in>
</struts-config>
Bu dosya, formun dinamik tanımı ve doğrulama eklentisinin eklenmesi (çerçeveli kısımlar) dışında strutspersonne1 uygulamasındaki dosyayla aynıdır.
WEB-INF dosyasına aşağıdaki validation.xml doğrulama dosyası eklenir:
<form-validation>
<global>
<constant>
<constant-name>entierpositif</constant-name>
<constant-value>^\s*\d+\s*$</constant-value>
</constant>
</global>
<formset>
<form name="frmPersonne">
<field property="nom" depends="required">
<arg0 key="personne.nom"/>
</field>
<field property="age" depends="required,mask">
<arg0 key="personne.age"/>
<var>
<var-name>mask</var-name>
<var-value>${entierpositif}</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
<struts>\lib dizininde bulunan validator-rules.xml ve validator-rules_1_1.dtd dosyalarını WEB-INF dosyasına ekliyoruz:

WEB-INF/classes klasöründe artık tek bir sınıf kalmıştır:

WEB-INF\classes\ressources klasöründe şu personneressources.properties mesaj dosyası bulunur:
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 est incorrect</li>
errors.header=<ul>
errors.footer=</ul>
# Struts Validator hata mesajları
# anahtar önceden tanımlanmıştır ve değiştirilmemelidir
# İlgili hata mesajı serbesttir
# Mesajda {0} ila {3} arasında en fazla 4 parametre olabilir
errors.required=<li>Le champ [{0}] doit être renseigné.</li>
errors.minlength=<li>Le champ [{0}] foit avoir au moins {1} caractère.</li>
errors.maxlength=<li>Le champ [{0}] ne peut avoir plus de {1} caractères.</li>
errors.invalid=<li>Le champ [{0}] est incorrect.</li>
errors.byte=<li>{0} doit être un octet.</li>
errors.short=<li>{0} doit être un entier court.</li>
errors.integer=<li>{0} doit être un entier.</li>
errors.long=<li>{0} doit être un entier long.</li>
errors.float=<li>{0} doit être un réel simple.</li>
errors.double=<li>{0} doit être un réel double.</li>
errors.date=<li>{0} n'est pas une date valide.</li>
errors.range=<li>{0} doit être dans l'intervalle {1} à {2}.</li>
errors.creditcard=<li>{0} n'est pas un numéro de carte valide.</li>
errors.email=<li>{0} n'est pas une adresse électronique valide.</li>
personne.nom=nom
personne.age=age

5.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/strutspersonne2/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:

5.6. Sonuç
Bütünlük kısıtlamalarının "standart" olduğu dinamik formların kullanılmasıyla, bunları temsil etmek için sınıflar oluşturmaya gerek kalmadığını gösterdik. Bütünlük kısıtlamaları standartların dışına çıkarsa, bu yeni kısıtlamaları doğrulamak için yine sınıflar oluşturmak zorunda kalırız.