Skip to content

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:

Image

  • 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:

Image

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:
    <message-resources 
      parameter="ressources.personneressources"
    null="false"
  />    

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:

   errors.required=<li>Le champ [{0}] doit être renseigné.</li>

Bu mesajın {0} parametresini kullandığı görülmektedir. Bu parametrenin değeri, bütünlük kısıtlamasındaki <arg0> etiketiyle belirlenir:

             <arg0 key="personne.nom"/>      

Burada da arg0, mesaj dosyasında da bulunan bir anahtarla belirtilmiştir:

   personne.nom=nom

Tüm bunları bir araya getirirsek, nom alanı doldurulmadığında oluşturulan hata mesajı şöyledir:

<li>Le champ [nom] doit être renseigné.</li>

Ş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:

<li>Le champ [age] doit être renseigné.</li>

İ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:

   errors.invalid=<li>Le champ [{0}] est incorrect.</li>

Kısıtlama, {0} parametresi için bir değer tanımlamalıdır. Bunu <arg0> etiketiyle yapar:

             <arg0 key="personne.age"/>      

Mesaj dosyasında, personne.age anahtarı aşağıdaki mesajla ilişkilendirilmiştir:

     personne.age=age

mask kısıtlaması doğrulanmazsa oluşturulacak hata mesajı şudur:

<li>Le champ [age] est incorrect.</li>

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:

                <Context path="/strutspersonne2" docBase="e:/data/serge/web/struts/personne2" />

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/

Image

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.

Image

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:

Image

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:

Image

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

Image

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

Image

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:

Image

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

Image

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

Image

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

Image

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

Image

Şu yanıtı alıyoruz:

Image

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.