Skip to content

9. مثال ۰۷ – تگ‌های فرم

ما قصد داریم فرم زیر را بسازیم و استفاده کنیم:

ما مفهوم تزریق پارامتر را، همان‌طور که برای یک فیلد ورودی متنی دیدیم، به سایر عناصر HTML در یک فرم گسترش خواهیم داد.

9.1. پروژه NetBeans

  • در [1]، نماهای پروژه در [Formx.JSP]
  • در [2]، فایل پیکربندی Struts و پیام‌های بین‌المللی‌شده
  • به [3]، اکشن‌ها از [Formx.java] و یک فایل پیکربندی Struts دیگر.

9.2. پیکربندی Struts

فایل [struts.xml] به شرح زیر است:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <constant name="struts.custom.i18n.resources" value="messages" />
  
  <include file="example/example.xml"/>

  <package name="default" namespace="/" extends="struts-default">
    <default-action-ref name="index" />
    <action name="index">
      <result type="redirectAction">
        <param name="actionName">Form</param>
        <param name="namespace">/example</param>
      </result>
    </action>
  </package>
</struts>
  • خط ۹: شامل یک فایل پیکربندی دیگر، [example.xml] است. این فایل اکشن‌ها را پیکربندی می‌کند.
  • خطوط ۱۱–۱۹: بسته default. یک آدرس هدایت برای URL/ تعریف می‌کند. این آدرس به URL/example/Form.action هدایت خواهد شد.

فایل [example.xml] که اقدامات را پیکربندی می‌کند به شرح زیر است:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <package name="example" namespace="/example" extends="struts-default">
    <action name="Form" class="example.Form">
      <result name="success">/example/Form.JSP</result>
    </action>
    <action name="Form1" class="example.Form1">
      <result name="success">/example/Form1.JSP</result>
    </action>
    <action name="Form2" class="example.Form2">
      <result name="success">/example/Form2.JSP</result>
    </action>
  </package>
</struts>
  • خطوط ۷–۱۷: عملیات /example/Form را تعریف می‌کنند، /example/Form1 و /example/Form2، که در آن /example فضای نام (خط ۷) و Formx عملیات هستند.
  • خطوط ۸–۱۰: اجرای اقدام Form منجر به نمایش نمای /example/Form.JSP خواهد شد.
  • خطوط ۱۱–۱۳: اجرای اقدام Form1 منجر به نمایش نمای /example/Form1.JSP خواهد شد.
  • خطوط ۱۴–۱۶: اجرای اقدام Form2 منجر به نمایش نمای /example/Form2.JSP خواهد شد.

9.3. فایل‌های پیام

ما در مورد بین‌المللی‌سازی پروژه زیاد وارد جزئیات نمی‌شویم. این موضوع را قبلاً در مثال ۰۱ پوشش داده‌ایم. محتوای فایل [messages.properties] را ارائه می‌دهیم تا خواننده بتواند نماهای بعدی را درک کند.


Form.francais=Fran\u00E7ais
Form.anglais=Anglais
Form.titre=Struts 2 - les tags de formulaire
Form.message=Struts 2 - les tags de formulaire
Form.langues=langues
Form.textfield=1-textfield
Form.password=2-password
Form.textarea=3-textarea
Form.select1=4-select (multiple=false, size=1)
Form.select1.header=<-- انتخاب1 -->
Form.select2=5-select (multiple=false, size=3)
Form.select3=6-select (multiple=true, size=3)
Form.radio=7-radio
Form.checkbox=8-checkbox
Form.checkboxlist=9-checkboxlist
Form.hidden=10-hidden
Form.submitText=Valider
Form.buttonRazText=Raz
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.textfield=1-textfield
Confirmation.password=2-password
Confirmation.textarea=3-textarea
Confirmation.select1=4-select (multiple=false, size=1)
Confirmation.select2=5-select (multiple=false, size=3)
Confirmation.select3=6-select (multiple=true, size=3)
Confirmation.radio=7-radio
Confirmation.checkbox=8-checkbox
Confirmation.checkboxlist=9-checkboxlist
Confirmation.hidden=10-hidden

9.4. نما [Form.JSP] – بخش ورود داده

شکل آن به این صورت است:

 

به شرح زیر است:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title><s:text name="Form.titre"/></title>
    <s:head/>
  </head>

  <body background="<s:url value="/ressources/standard.jpg"/>">
    <h2><s:text name="Form.message"/></h2>
    <h3><s:text name="Form.langues"/></h3>
    <ul>
      <li>
        <s:url id="URL" action="Form">
          <s:param name="request_locale">en</s:param>
        </s:url>
        <s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
      </li>
      <li>
        <s:url id="URL" action="Form">
          <s:param name="request_locale">fr</s:param>
        </s:url>
        <s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
      </li>
    </ul>
    <s:form name="formulaire">
      <s:textfield name="textfield" key="Form.textfield" />
      <s:password name="password" key="Form.password"/>
      <s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
      <s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
      <s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
      <s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
      <s:radio name="radio" list="radioValues" key="Form.radio"/>
      <s:checkbox name="checkbox" key="Form.checkbox"/>
      <s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
      <s:hidden name="hidden" key="Form.hidden"/>
      <s:submit key="Form.submitText" name="submitText"/>
    </s:form>
    <hr/>
 ...
  </body>
</html>
  • فرم از خط ۲۶ شروع و در خط ۳۸ پایان می‌یابد. در خط ۲۶، ویژگی action وجود ندارد. این ویژگی اقدام (action) موردنظر برای ارسال داده‌های فرم را مشخص می‌کند. در صورت عدم وجود ویژگی action، داده‌ها به اکشنی ارسال می‌شوند که منجر به نمایش ویو شده است، که در این مورد اکشن [Form] است.
  • خط ۲۷: یک فیلد ورودی. ویژگی key برچسب آن را مشخص می‌کند. ویژگی name نام پارامتر ارسال‌شده است. رشته ارسال‌شده برای این فیلد به شکل زیر خواهد بود:
textfield=texte_saisi

نام پارامتر با یک فیلد در اکشن [Form] مطابقت دارد. مقدار فیلد ورودی texte_saisi در اینجا در فیلد textfield از اکشن [Form] درج خواهد شد. برعکس، اگر نما [Form.JSP] پس از اقدام [Form] نمایش داده شود، مقدار فیلد ورودی همان مقدار فیلد textfield در اقدام [Form] خواهد بود. بنابراین این فیلد هم برای خواندن و هم برای نوشتن استفاده می‌شود. کلاس [Form] باید برای این منظور متدهای getTextField و setTextField را داشته باشد.

این استدلال برای تمام تگ‌های ورودی بعدی نیز صدق می‌کند. آن را تکرار نخواهیم کرد.

  • خط ۲۸: ورود رمز عبور. رشته‌ای که به اقدام [Form] ارسال می‌شود به شکل زیر خواهد بود
password=mot_de_passe_saisi

یک فیلد با نام password، به همراه متدهای get و set آن، باید در اکشن [Form] وجود داشته باشد.

  • خط ۲۹: وارد کردن متن چندخطی در یک فیلد با ۵ سطر و ۴۰ ستون. رشته‌ای که به اکشن [Form] ارسال می‌شود به شکل زیر خواهد بود:
textarea=saisie

یک فیلد textarea، به همراه متدهای get/set آن، باید در اکشن [Form] وجود داشته باشد.

  • خط ۳۰: یک لیست کشویی تک‌انتخابی (size=1). تنها یک مقدار از لیست قابل انتخاب است. رشته ارسال‌شده به اکشن [Form] به شکل زیر خواهد بود:
select1=valeur_sélectionnée

یک فیلد select1، به همراه متدهای get/set آن، باید در اکشن [Form] وجود داشته باشد.

ویژگی key برچسب لیست است. ویژگی list فهرست مقادیری را که باید در لیست کشویی قرار گیرند، تعریف می‌کند. در اینجا، متد getSelect1Values از اکشن [Form] برای پر کردن لیست کشویی فراخوانی خواهد شد. این متد می‌تواند یک مجموعه، یک دیکشنری یا یک آرایه را بازگرداند. در اینجا، یک آرایه از رشته‌ها، [chaine1, chaine2, ...]، بازگردانده می‌شود که کد HTML زیر را تولید می‌کند:


<option value="chaine1">chaine1</option>
<option value="chaine2">chaine2</option>
...

متن بین تگ‌های <option>...</option> در لیست کشویی نمایش داده می‌شود. ویژگی value مقداری را که در صورت انتخاب گزینه توسط کاربر ارسال می‌شود، مشخص می‌کند. در اینجا، ویژگی value و متنی که در لیست کشویی نمایش داده می‌شود یکسان هستند. در اغلب موارد، اینطور نیست. اگر گزینه دوم انتخاب شود، رشته زیر به اکشن [Form] ارسال خواهد شد:

select1=chaine2

میدان [Form].select1 سپس روی chaine2 تنظیم خواهد شد. برعکس، اگر هنگام نمایش فرم، این میدان روی chaine3 تنظیم شود، آنگاه از نظر بصری، عنصر سوم


<option value="chaine3">chaine3</option>

به‌صورت انتخاب‌شده در لیست کشویی ظاهر خواهد شد.

ویژگی headerValue متنی را که باید به عنوان اولین گزینه در لیست کشویی نمایش داده شود، تعیین می‌کند و headerKey مقداری را که در صورت انتخاب این گزینه توسط کاربر ارسال می‌شود، تعیین می‌کند.

  • خط ۳۱: اینجا دوباره یک لیست با اندازه ۳ (size=3): برخلاف لیست قبلی که تنها یک آیتم قابل مشاهده بود، در اینجا سه آیتم از لیست قابل مشاهده خواهند بود. روش انتخاب همان است. تنها یک آیتم می‌تواند انتخاب شود.
  • خط ۳۲: فهرست دیگری، اما این بار با انتخاب چندگانه (multiple=true). در این حالت، مقداری که به اقدام [Form] ارسال می‌شود به شکل زیر خواهد بود:
select3=chaine2&select3=chaine5

اگر گزینه‌های chaine2 و chaine5 انتخاب شده باشند. وقتی چندین مقدار برای یک پارامتر – در این مورد select3 – ارسال می‌شود، اکشن باید دارای یک فیلد با نام پارامتر باشد و از نوع tableau باشد. برای مثال، اکشن [Form] می‌تواند فیلدی مانند زیر داشته باشد:

String[] select3 ;

و متدهای get/set متناظر. آرایه select3 سپس آرایه رشته‌های [chaine2,chaine5] را دریافت خواهد کرد. برعکس، هنگامی که نما [Form.JSP] نمایش داده می‌شود، مقادیر فیلد [Form].select3 تعیین می‌کنند که کدام گزینه‌ها در لیست select3 به صورت انتخاب‌شده ظاهر شوند. این هنوز یک عملیات خواندن/نوشتن است.

  • خط ۳۳: یک گروه از دکمه‌های رادیویی. برچسب گروه توسط ویژگی key ارائه می‌شود. برچسب‌های دکمه‌های فردی توسط ویژگی list ارائه می‌شوند. مقدار این ویژگی نام متد اکشن [Form] است که باید یک مجموعه، یک دیکشنری یا یک آرایه را بازگرداند. در اینجا، متد [Form].getRadioValues یک آرایه از رشته‌ها [chaine1,chaine2,...] را بازمی‌گرداند که تگ‌های HTML زیر را تولید می‌کند:

<input type="radio" name="radio" ... value="chaine1"/>chaine1
<input type="radio" name="radio" ... value="chaine2"/>chaine2
...

اگر دکمه رادیویی chaine2 انتخاب شود، مقدار ارسال‌شده خواهد بود

radio=chaine2

و این مقدار در فیلد [Form].radio درج خواهد شد.

  • خط ۳۴: یک تیک‌باکس. اگر تیک خورده باشد، رشته پارامتر زیر به اکشن [Form] ارسال خواهد شد.
checkbox=true

اگر تیک خورده نباشد، هیچ رشته پارامتری ارسال نمی‌شود. Struts 2 دارای مکانیزم داخلی است که تضمین می‌کند همه چیز طوری اتفاق می‌افتد که گویی رشته

checkbox=false

ارسال شده باشد.»

  • خط ۳۵: فهرستی از کادرهای تیک. می‌توان چندین کادر را تیک زد. برچسب گروه توسط ویژگی key ارائه می‌شود. برچسب‌های مربوط به هر یک از چک‌باکس‌ها توسط ویژگی list ارائه می‌شوند. مقدار این ویژگی نام متد اکشن [Form] است که باید یک مجموعه، یک دیکشنری یا یک آرایه را بازگرداند. در اینجا، متد [Form].getCheckboxlistValues یک آرایه از رشته‌ها [chaine1,chaine2,...] را بازمی‌گرداند که برچسب‌های HTML زیر را تولید می‌کند:

<input type="checkbox" name="checkboxlist" ... value="chaine1"/>chaine1
<input type="checkbox" name="checkboxlist" ... value="chaine2"/>chaine2
...

اگر کاربر چک‌باکس‌های دارای برچسب chaine2 و chaine5 را انتخاب کند، رشته زیر به اکشن [Form] ارسال خواهد شد:

checkboxlist=chaine2&checkboxlist=chaine5

آرایه [chaine2, chaine5] به فیلد [Form].checkboxlist اختصاص داده خواهد شد، که بنابراین باید از نوع آرایه رشته‌ای باشد، همان‌طور که در لیست‌های چندگزینه‌ای معمول است. برعکس، هنگامی که نما [Form.JSP] نمایش داده می‌شود، مقادیر موجود در فیلد [Form].checkboxlist تعیین می‌کنند که کدام کادرهای تیک‌دار تیک خواهند خورد.

  • خط ۳۶: یک فیلد مخفی. فیلد مخفی فیلدی است که بدون وارد شدن توسط کاربر ارسال می‌شود. مقدار آن توسط برنامه‌نویس تعیین می‌شود. در اینجا، فیلد مخفی مقدار خود را از فیلد [Form].hidden خواهد گرفت. همین مقدار در فرم ارسال خواهد شد:
hidden=qqchose

و دوباره به فیلد [Form].hidden اختصاص داده می‌شود.

  • خط ۳۷: یک دکمه از نوع submit. کلیک بر این دکمه تمام مقادیر فرم را به اکشن [Form] ارسال می‌کند. رشته پارامترهای ارسال‌شده به این شکل خواهد بود:
textfield=texte&password=&textarea=ligne1%0D%0Aligne2%0D%0A&select1=z%C3%A9ro&select2=trois&select3=z%C3%A9ro&select3=deux&__multiselect_select3=&radio=bleu&checkbox=true&__checkbox_checkbox=true&checkboxlist=v%C3%A9lo&checkboxlist=bus&__multiselect_checkboxlist=&hidden=initial&submitText=Valider 

9.5. عمل [Form] – بخش ورود داده

کد آن به شرح زیر است:


package example;

import com.opensymphony.xwork2.ActionSupport;

public class Form extends ActionSupport {

  // سازنده بدون پارامتر
  public Form() {
  }
  // fields of form
  private String textfield = "texte";
  private String password = "secret";
  private String textarea = "ligne1\nligne2\n";
  private String select1 = "zéro";
  private String[] select1Values = new String[]{"zéro", "un", "deux"};
  private String select2 = "trois";
  private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String[] select3 = new String[]{"zéro", "deux"};
  private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String radio = "bleu";
  private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
  private Boolean checkbox = false;
  private String[] checkboxlist = new String[]{"vélo", "bus"};
  private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
  private String hidden = "initial";
  private String submitText;

  //مقادیر انتخاب‌شده در فیلد select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  //مقادیر انتخاب‌شده در فیلد checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // متد ابزار
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
  }

// متدهای getter و setter برای فیلدها
  ....
}
  • خط ۱: فیلدی که با تگ textfield در فرم مرتبط است. این فیلد برای مقداردهی اولیه و بازیابی مقدار آن استفاده می‌شود. در زمان فراخوانی POST، مقداری را که در این فیلد وارد شده است دریافت می‌کند.
  • خط ۲: فیلدی که با تگ password در فرم مرتبط است. در زمان رویداد POST، مقدار واردشده در این فیلد را دریافت می‌کند.
  • خط ۱۳: مرتبط با تگ textarea در فرم. در زمان POST، متنی را که در این فیلد وارد شده است دریافت می‌کند.
  • خط 14: مرتبط با برچسب select1 در فرم، یک لیست تک‌انتخابی. مقدار اولیه آن یک مورد را از لیست کشویی انتخاب می‌کند. موردی که ویژگی value آن روی این مقدار تنظیم شده باشد، انتخاب خواهد شد. در زمان POST، آن ویژگی value گزینه‌ای را که در لیست کشویی انتخاب شده است دریافت می‌کند.
  • خط ۱۵: رشته‌های کاراکتری که لیست کشویی select1 را پر خواهند کرد.
  • خطوط ۱۶ و ۱۷: مشابه select1
  • خط ۱۸: مربوط به تگ select1 فرم، یک لیست کشویی. مقادیر اولیه در آرایه، موارد متناظر را از لیست انتخاب می‌کنند. مواردی که ویژگی value آن‌ها با یکی از این مقادیر مطابقت داشته باشد، انتخاب خواهند شد. در زمان POST، آن ویژگی‌های value گزینه‌های مختلف انتخاب‌شده از لیست کشویی را دریافت می‌کند.
  • خط ۱۹: رشته‌های کاراکتری که لیست select3 را پر خواهند کرد
  • خط ۲۰: مرتبط با تگ radio در فرم است. مقدار آن برای انتخاب یکی از دکمه‌های رادیویی، یعنی دکمه‌ای که ویژگی value آن برابر با این مقدار است، استفاده می‌شود. در زمان POST، مقدار دکمهٔ رادیویی انتخاب‌شده را دریافت می‌کند.
  • خط ۲۱: برچسب‌ها و مقادیر مختلف دکمه‌های رادیویی.
  • خط ۲۲: مرتبط با تگ checkbox در فرم. مقدار اولیه آن برای تیک‌زدن یا برداشتن تیک چک‌باکس استفاده می‌شود. در زمان POST، اگر تیک چک‌باکس خورده باشد مقدار true و در غیر این صورت مقدار false را دریافت می‌کند.
  • خط ۲۳: مرتبط با تگ checkboxlist در فرم. مقادیر اولیه در آرایه، جعبه‌های تیک متناظر را انتخاب می‌کنند. جعبه‌های تیکی که ویژگی value آن‌ها برابر با یکی از این مقادیر اولیه باشد، تیک خواهند خورد. در زمان POST، آن ویژگی‌های value جعبه‌های مختلف تیک‌خورده را دریافت می‌کند.
  • خط 24: رشته‌های متنی که برچسب‌های چک‌باکس‌ها را در checkboxlist پر می‌کنند.
  • خط ۲۵: مرتبط با فیلد مخفی hidden. مقدار اولیهٔ آن مقدار فیلد مخفی را تعیین می‌کند. در زمان POST، همان مقدار دریافت می‌شود زیرا کاربر قادر به تغییر آن نیست.
  • خط ۲۶: مرتبط با تگ submit. هنگامی که POST اجرا می‌شود، برچسب دکمه را دریافت می‌کند. این فیلد اختیاری است.
  • متدهای موجود در خطوط ۲۹، ۳۴ و ۳۹ بعداً به طور مفصل‌تر مورد بحث قرار خواهند گرفت.

9.6. نما [Form.JSP] – بخش تأیید

ویوی [Form.JSP] دارای بخشی به نام «تأیید ورودی‌ها» است که هنوز پوشش داده نشده است:

 

کد آن به شرح زیر است:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
...
    <hr/>
    <h2><s:text name="Confirmation.message"/></h2>
    <table border="1">
      <tr>
        <th><s:text name="Confirmation.champ"/></th>
        <th><s:text name="Confirmation.valeur"/></th>
      </tr>
      <tr>
        <td><s:text name="Form.textfield"/></td>
        <td><s:property value="textfield"/>
      </tr>
      <tr>
        <td><s:text name="Form.password"/></td>
        <td><s:property value="password"/>
      </tr>
      <tr>
        <td><s:text name="Form.textarea"/></td>
        <td><s:property value="textarea"/>
      </tr>
      <tr>
        <td><s:text name="Form.select1"/></td>
        <td><s:property value="select1"/>
      </tr>
      <tr>
        <td><s:text name="Form.select2"/></td>
        <td><s:property value="select2"/>
      </tr>
      <tr>
        <td><s:text name="Form.select3"/></td>
        <td><s:property value="select3SelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.radio"/></td>
        <td><s:property value="radio"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkbox"/></td>
        <td><s:property value="checkbox"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkboxlist"/></td>
        <td><s:property value="checkboxlistSelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.hidden"/></td>
        <td><s:property value="hidden"/>
      </tr>
    </table>
  </body>
</html>
  • خط ۱۳: مقدار فیلد [Form].textfield را نمایش می‌دهد
  • خط ۱۷: مقدار فیلد [Form].password را نمایش می‌دهد
  • خط ۲۱: مقدار فیلد [Form].textarea را نمایش می‌دهد
  • خط 25: مقدار فیلد [Form].select1 را نمایش می‌دهد
  • خط ۲۹: مقدار فیلد [Form].select2 را نمایش می‌دهد
  • خط ۳۳: مقادیر آرایه [Form].select3 را نمایش می‌دهد. برای این کار، از متد [Form].getSelect3SelectedValues استفاده کنید.
  • خط ۳۷: مقدار فیلد [Form].radio را نمایش می‌دهد
  • خط ۴۱: مقدار فیلد [Form].checkbox را نمایش می‌دهد.
  • خط ۴۵: مقادیر آرایه [Form].checkboxlist را نمایش می‌دهد. برای انجام این کار، از متد [Form].getCheckboxlistSelectedValues استفاده کنید.
  • خط ۴۹: مقدار فیلد [Form].hidden را نمایش می‌دهد

9.7. عمل [Form] – بخش تأیید

متدهای getSelect3SelectedValues و getCheckboxlistSelectedValues که در بالا ذکر شدند، در کلاس [Form] تعریف شده‌اند:


  //مقادیر انتخاب‌شده در فیلد select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  //مقادیر انتخاب‌شده در فیلد چک‌باکس‌لیست
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // متد ابزار
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
}

آنها صرفاً عناصر آرایه‌هایی را که برای نمایش نیاز دارند، به هم متصل می‌کنند.

9.8. آزمایش

وقتی پروژه NetBeans اجرا می‌شود، صفحهٔ اولیهٔ زیر نمایش داده می‌شود:

مقادیر نمایش‌داده‌شده در [1] و [2] از مقادیر اولیه فیلدهای اکشن [Form] استخراج شده‌اند. بیایید چند مثال را بررسی کنیم:


private String textarea = "ligne1\nligne2\n";

مقدار فیلد textarea نمایش‌های [1A] و [2A] را توضیح می‌دهد.


private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};

مقدار فیلد select3Values محتویات لیست در [1B] را توضیح می‌دهد. مقدار فیلد select3 موارد انتخاب‌شده در [1B] را توضیح می‌دهد و در [2B] نمایش داده می‌شود.

اگر مقادیر بیشتری را در فرم وارد کرده و آن را ارسال کنیم، مقادیر واردشده در اقدام [Form] به فیلدهای مربوطه ارسال خواهند شد. سپس نمای [Form.JSP] مجدداً نمایش داده می‌شود. بنابراین ما در همان وضعیت قبلی هستیم، با این تفاوت که مقادیر اولیه با مقادیر ارسال‌شده جایگزین شده‌اند. در اینجا یک مثال:

9.9. اقدام [Form1] و نما [Form1.JSP]

فایل پیکربندی [example.xml] اقدام زیر را پیکربندی می‌کند: [Form1]:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <package name="example" namespace="/example" extends="struts-default">
    <action name="Form" class="example.Form">
      <result name="success">/example/Form.JSP</result>
    </action>
    <action name="Form1" class="example.Form1">
      <result name="success">/example/Form1.JSP</result>
    </action>
    <action name="Form2" class="example.Form2">
      <result name="success">/example/Form2.JSP</result>
    </action>
  </package>
</struts>

خطوط ۱۱–۱۳: فراخوانی اکشن [Form1] نما [Form1.JSP] را تولید می‌کند.

عمل [Form1] به شرح زیر است:


package example;

import com.opensymphony.xwork2.ActionSupport;

public class Form1 extends ActionSupport{

  // سازنده بدون پارامتر
  public Form1() {
  }
  // fields of the form
  private Data data=new Data();

  /**
   * @return the data
   */
  public Data getData() {
    return data;
  }

  /**
   * @param data the data to set
   */
  public void setData(Data data) {
    this.data = data;
  }
}

عمل [Form1] با عمل [Form] یکسان است، با این تفاوت که بخش قالب آن به کلاس جداگانه‌ای به نام [Data]، خط ۱۱ منتقل شده است. کلاس [Data] به شرح زیر است:


package example;

public class Data {

  // سازنده بدون پارامتر
  public Data() {
  }
  
// fields of the form
  private String textfield = "texte";
  private String password = "secret";
  private String textarea = "ligne1\nligne2\n";
  private String select1 = "zéro";
  private String[] select1Values = new String[]{"zéro", "un", "deux"};
  private String select2 = "trois";
  private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String[] select3 = new String[]{"zéro", "deux"};
  private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
  private String radio="bleu";
  private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
  private Boolean checkbox = false;
  private String[] checkboxlist = new String[]{"vélo", "bus"};
  private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
  private String hidden = "initial";
  private String submitText;

  // مقادیر انتخاب‌شده در فیلد select3
  public String getSelect3SelectedValues() {
    return getValue(select3);
  }

  //مقادیر انتخاب‌شده در فیلد checkboxlist
  public String getCheckboxlistSelectedValues() {
    return getValue(checkboxlist);
  }

  // متد ابزار
  public String getValue(String[] values) {
    String result = "";
    for (String value : values) {
      result += " " + value;
    }
    return result;
  }

  // getters و setters
....

}

فیلدهای اعلام‌شده در بالا را می‌توان در اکشن [Form] یافت.

منطقی است که ویو [Form1.JSP] مشابه ویو [Form.JSP] است:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title><s:text name="Form.titre"/></title>
    <s:head/>
  </head>

  <body background="<s:url value="/ressources/standard.jpg"/>">
    <h2><s:text name="Form.message"/></h2>
    <h3><s:text name="Form.langues"/></h3>
    <ul>
      <li>
        <s:url id="URL" action="Form">
          <s:param name="request_locale">en</s:param>
        </s:url>
        <s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
      </li>
      <li>
        <s:url id="URL" action="Form">
          <s:param name="request_locale">fr</s:param>
        </s:url>
        <s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
      </li>
    </ul>
    <s:form name="formulaire">
      <s:textfield name="data.textfield" key="Form.textfield" />
      <s:password name="data.password" key="Form.password"/>
      <s:textarea name="data.textarea" key="Form.textarea" cols="40" rows="5"/>
      <s:select name="data.select1" list="data.select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
      <s:select name="data.select2" size="3" list="data.select2Values" key="Form.select2"/>
      <s:select name="data.select3" size="3" list="data.select3Values" key="Form.select3" multiple="true"/>
      <s:radio name="data.radio" list="data.radioValues" key="Form.radio"/>
      <s:checkbox name="data.checkbox" key="Form.checkbox"/>
      <s:checkboxlist name="data.checkboxlist" list="data.checkboxlistValues" key="Form.checkboxlist"/>
      <s:hidden name="data.hidden" key="Form.hidden"/>
      <s:submit key="Form.submitText" name="data.submitText"/>
    </s:form>
    <hr/>
    <h2><s:text name="Confirmation.message"/></h2>
    <table border="1">
      <tr>
        <th><s:text name="Confirmation.champ"/></th>
        <th><s:text name="Confirmation.valeur"/></th>
      </tr>
      <tr>
        <td><s:text name="Form.textfield"/></td>
        <td><s:property value="data.textfield"/>
      </tr>
      <tr>
        <td><s:text name="Form.password"/></td>
        <td><s:property value="data.password"/>
      </tr>
      <tr>
        <td><s:text name="Form.textarea"/></td>
        <td><s:property value="data.textarea"/>
      </tr>
      <tr>
        <td><s:text name="Form.select1"/></td>
        <td><s:property value="data.select1"/>
      </tr>
      <tr>
        <td><s:text name="Form.select2"/></td>
        <td><s:property value="data.select2"/>
      </tr>
      <tr>
        <td><s:text name="Form.select3"/></td>
        <td><s:property value="data.select3SelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.radio"/></td>
        <td><s:property value="data.radio"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkbox"/></td>
        <td><s:property value="data.checkbox"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkboxlist"/></td>
        <td><s:property value="data.checkboxlistSelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.hidden"/></td>
        <td><s:property value="data.hidden"/>
      </tr>
    </table>
  </body>
</html>

تفاوت بین ویو [Form] و [Form1] را می‌توان با خط ۲۷ که در زیر بازتولید شده است نشان داد:


<s:textfield name="data.textfield" key="Form.textfield" />

این فیلد ورودی، هم برای خواندن و هم برای نوشتن، به فیلد data.textfield از اکشن [Form1] متصل است. توجه باید به این نکته جلب شود که پس از اجرا، ویژگی‌های اکشن [Form1] برای ویو قابل دسترسی هستند. بنابراین، ویژگی پیشین name به صورت [Form1].getData().getTextField(). ارزیابی خواهد شد. بنابراین، دو متد پیشین get باید وجود داشته باشند.

9.10. اقدام [Form2] و نما [Form2.JSP]

فایل پیکربندی [example.xml] اقدام زیر [Form2] را پیکربندی می‌کند:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <package name="example" namespace="/example" extends="struts-default">
    <action name="Form" class="example.Form">
      <result name="success">/example/Form.JSP</result>
    </action>
    <action name="Form1" class="example.Form1">
      <result name="success">/example/Form1.JSP</result>
    </action>
    <action name="Form2" class="example.Form2">
      <result name="success">/example/Form2.JSP</result>
    </action>
  </package>
</struts>

خطوط 14–16: فراخوانی اکشن [Form2] نمای [Form2.JSP] را تولید می‌کند.

عمل [Form2] به شرح زیر است:


package example;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class Form2 extends ActionSupport implements ModelDriven {

  // سازنده بدون پارامتر
  public Form2() {
  }
  // مدل عملی
  public Object getModel() {
    return new Data();
  }
}
  • خط ۶: اکشن [Form2] رابط [ModelDriven] را پیاده‌سازی می‌کند. فقط یک متد برای پیاده‌سازی وجود دارد: متد getModel در خط ۱۲. این متد یک نمونه از کلاس [Data] را که قبلاً مورد بحث قرار گرفت، بازمی‌گرداند.

اینکه اکشن [Form2] رابط [ModelDriven] را پیاده‌سازی می‌کند، نتیجه زیر را در پی دارد: نما (view) نمایش‌داده‌شده پس از اقدام [Form2] به ویژگی‌های مدل اقدام [Form2]، که توسط متد getModel() بازگردانده می‌شود، دسترسی مستقیم دارد. در نتیجه، نما [Form2.JSP] به وضعیت خود در عمل اولیه [Form] بازمی‌گردد:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title><s:text name="Form.titre"/></title>
    <s:head/>
  </head>

  <body background="<s:url value="/ressources/standard.jpg"/>">
    <h2><s:text name="Form.message"/></h2>
    <h3><s:text name="Form.langues"/></h3>
    <ul>
      <li>
        <s:url id="URL" action="Form">
          <s:param name="request_locale">en</s:param>
        </s:url>
        <s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
      </li>
      <li>
        <s:url id="URL" action="Form">
          <s:param name="request_locale">fr</s:param>
        </s:url>
        <s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
      </li>
    </ul>
    <s:form name="formulaire">
      <s:textfield name="textfield" key="Form.textfield" />
      <s:password name="password" key="Form.password"/>
      <s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
      <s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
      <s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
      <s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
      <s:radio name="radio" list="radioValues" key="Form.radio"/>
      <s:checkbox name="checkbox" key="Form.checkbox"/>
      <s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
      <s:hidden name="hidden" key="Form.hidden"/>
      <s:submit key="Form.submitText" name="submitText"/>
    </s:form>
    <hr/>
    <h2><s:text name="Confirmation.message"/></h2>
    <table border="1">
      <tr>
        <th><s:text name="Confirmation.champ"/></th>
        <th><s:text name="Confirmation.valeur"/></th>
      </tr>
      <tr>
        <td><s:text name="Form.textfield"/></td>
        <td><s:property value="textfield"/>
      </tr>
      <tr>
        <td><s:text name="Form.password"/></td>
        <td><s:property value="password"/>
      </tr>
      <tr>
        <td><s:text name="Form.textarea"/></td>
        <td><s:property value="textarea"/>
      </tr>
      <tr>
        <td><s:text name="Form.select1"/></td>
        <td><s:property value="select1"/>
      </tr>
      <tr>
        <td><s:text name="Form.select2"/></td>
        <td><s:property value="select2"/>
      </tr>
      <tr>
        <td><s:text name="Form.select3"/></td>
        <td><s:property value="select3SelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.radio"/></td>
        <td><s:property value="radio"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkbox"/></td>
        <td><s:property value="checkbox"/>
      </tr>
      <tr>
        <td><s:text name="Form.checkboxlist"/></td>
        <td><s:property value="checkboxlistSelectedValues"/>
      </tr>
      <tr>
        <td><s:text name="Form.hidden"/></td>
        <td><s:property value="hidden"/>
      </tr>
    </table>
  </body>
</html>

بنابراین، خط ۲۷ که قبلاً بود:


<s:textfield name="data.textfield" key="Form.textfield" />

به حالت زیر بازگردانده می‌شود:


<s:textfield name="textfield" key="Form.textfield" />

مزیت قرار دادن مدل خارج از نما این است که این معماری به وضوح بیشتری قابلیت‌های هر عنصر را در معماری MVC مشخص می‌کند. مدل M به‌وضوح توسط یک کلاس شناسایی می‌شود. علاوه بر این، مدل ممکن است پیش از اکشن‌ها وجود داشته باشد. بنابراین، اگر یک برنامه وب یک پایگاه داده از افراد را مدیریت کند، احتمالاً کلاس Personne وجود دارد. اگر یک اکشن یک فرم ورودی برای ایجاد یک شخص جدید ارائه دهد، مدل برای آن اکشن واضح است: آن کلاس Personne است.

ما دیدیم که تغییر از اکشن [Form] به اکشن [Form2] چقدر ساده بود:

  • مدل Mِ نما V در یک کلاس جداگانه بسته‌بندی شده است
  • اقدامی که این نما را با استفاده از این مدل تولید می‌کند، رابط ModelDriven را با متد getModel پیاده‌سازی می‌کند که یک نمونه از مدل M را برمی‌گرداند. بنابراین، این اقدام را می‌توان به عنوان گسترشی از کنترل‌کننده C در Struts 2، یعنی کلاس FilterDispatcher، در نظر گرفت.

خواننده می‌تواند این رویکرد را به هر اکشن که در ادامه توصیف شده است، اعمال کند.