10. المثال 08 - العلامات المرتبطة بالقوائم
يركز المثال التالي على العلامات التي تعرض قوائم. وقد سبق أن صادفناها في المثال السابق: القائمة المنسدلة، ومربعات الاختيار، وأزرار الاختيار. وسيكون نموذج الاختبار كما يلي:


10.1. مشروع NetBeans
مشروع NetBeans هو كما يلي:
![]() |
- [1] الإجراء و[2] العرض المرتبط به.
يقوم الملف [example/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>
</package>
</struts>
توضح السطور 8-9 أن استدعاء عنوان URL [/example/Form.action] يولد العرض [/example/Form.jsp]. وبالتالي، سيكون الإجراء [Form] مسؤولاً عن إنشاء النموذج للعرض [Form.jsp].
10.2. ملف الرسائل المُعَلَّمة دوليًا
فيما يلي ملف [messages.properties] الخاص بالرسائل المُترجمة:
Form.francais=Fran\u00E7ais
Form.anglais=Anglais
Form.titre=Struts 2 - les tags \u00E0 valeurs multiples
Form.message=Struts 2 - les tags \u00E0 valeurs multiples
Form.langues=langues
Form.select1=1-select1 (multiple=false, size=1)
Form.select2=2-select2 (multiple=true, size=3)
Form.select3=3-select3 (multiple=true, size=3)
Form.select4=4-select4 (multiple=true, size=3)
Form.select5=5-select5 (multiple=true, size=3)
Form.checkboxlist1=6-checkboxlist1
Form.checkboxlist2=7-checkboxlist2
Form.checkboxlist3=8-checkboxlist3
Form.radio1=9-radio1
Form.radio2=10-radio2
Form.radio3=11-radio3
Form.submitText=Valider
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.select1=1-select1 (multiple=false, size=1)
Confirmation.select2=2-select2 (multiple=false, size=3)
Confirmation.select3=3-select3 (multiple=true, size=3)
Confirmation.select4=4-select4 (multiple=true, size=3)
Confirmation.select5=5-select5 (multiple=true, size=3)
Confirmation.checkboxlist1=6-checkboxlist1
Confirmation.checkboxlist2=7-checkboxlist2
Confirmation.checkboxlist3=8-checkboxlist3
Confirmation.radio1=9-radio1
Confirmation.radio2=10-radio2
Confirmation.radio3=11-radio3
تستخدم طريقة العرض [Form.jsp] هذه الرسائل.
10.3. طريقة العرض [Form.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:select name="select1" list="{'vert','jaune','rouge'}" size="1" key="Form.select1"/>
<s:select name="select2" list="{'vert','jaune','rouge'}" size="3" key="Form.select2" multiple="true"/>
<s:select name="select3" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" size="3" key="Form.select3" multiple="true"/>
<s:select name="select4" list="dico" size="3" key="Form.select4" multiple="true"/>
<s:select name="select5" list="couleurs" listKey="id" listValue="nom" size="3" key="Form.select5" multiple="true" />
<s:checkboxlist name="checkboxlist1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.checkboxlist1"/>
<s:checkboxlist name="checkboxlist2" list="dico" key="Form.checkboxlist2"/>
<s:checkboxlist name="checkboxlist3" list="couleurs" listKey="id" listValue="nom" key="Form.checkboxlist3" />
<s:radio name="radio1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.radio1"/>
<s:radio name="radio2" list="dico" key="Form.radio2"/>
<s:radio name="radio3" list="couleurs" listKey="id" listValue="nom" key="Form.radio3" />
<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.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.select4"/></td>
<td><s:property value="select4SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.select5"/></td>
<td><s:property value="select5SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist1"/></td>
<td><s:property value="checkboxlist1SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist2"/></td>
<td><s:property value="checkboxlist2SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist3"/></td>
<td><s:property value="checkboxlist3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio1"/></td>
<td><s:property value="radio1"/>
</tr>
<tr>
<td><s:text name="Form.radio2"/></td>
<td><s:property value="radio2"/>
</tr>
<tr>
<td><s:text name="Form.radio3"/></td>
<td><s:property value="radio3"/>
</tr>
</table>
</body>
</html>
دعونا نفحص علامات الإدخال المختلفة في النموذج:
- السطر 27: علامة <s:select>:
<s:select name="select1" list="{'vert','jaune','rouge'}" size="1" key="Form.select1"/>
ستُنتج هذه العلامة كود HTML التالي:
قيمة سمة list هي مصفوفة من السلاسل المستخدمة لتوليد قيم وتسميات الخيارات. النموذج المرتبط هو حقل select1 في إجراء [Form] التالي:
private String select1 = "jaune";
يرتبط هذا الحقل بحق الوصول للقراءة والكتابة إلى العلامة المسماة select1. عند الكتابة، سيتم إدخال قيمة الخيار المحدد في حقل select1. عند القراءة، تُستخدم قيمة حقل select1 لتحديد الخيار المحدد. هنا، تُستخدم القيمة "yellow" في حقل select1 لتحديد الخيار في علامة select1 الذي له القيمة "yellow". ولهذا السبب، في السطر 3، يتم تحديد الخيار.
- السطر 28
<s:select name="select2" list="{'vert','jaune','rouge'}" size="3" key="Form.select2" multiple="true"/>
لا يوجد فرق جوهري عن العلامة الموجودة في السطر 27، باستثناء أن الاختيار هنا متعدد. لذلك، فإن القيمة المرسلة هي مصفوفة من القيم، وهي قيم الخيارات المحددة. حقل select2 الخاص بالإجراء المرتبط بالنموذج هو كما يلي:
private String[] select2 = new String[]{"vert", "rouge"};
إنه بالفعل مصفوفة. تُستخدم قيمته الأولية لاختيار الخيارات التي توجد قيمها في المصفوفة.
- السطر 29
<s:select name="select3" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" size="3" key="Form.select3" multiple="true"/>
هنا، قيمة سمة list هي قاموس تعمل مفاتيحه كقيم للخيارات، بينما تعمل القيم المرتبطة بها كعناوين للخيارات. رمز HTML الذي تم إنشاؤه هو كما يلي:
الحقل المرتبط في الإجراء هو كما يلي:
private String[] select3 = new String[]{"01", "03"};
لدينا مرة أخرى مصفوفة من القيم لأن العلامة المرتبطة بها هي حقل متعدد الخيارات. توضح القيم الأولية للمصفوفة سبب تحديد الخيارات في السطرين 2 و 4 مسبقًا.
- السطر 30
<s:select name="select4" list="dico" size="3" key="Form.select4" multiple="true"/>
هنا، سيتم توفير خيارات القائمة بواسطة نموذج العرض، والذي يعد في هذه الحالة جزءًا من إجراء [Form]:
private HashMap<String, String> dico = new HashMap<String, String>();
ستكون مفاتيح قاموس dico هي قيم الخيارات. وستكون قيم قاموس dico هي تسميات الخيارات. ويكون حقل select4 الخاص بالإجراء كما يلي:
private String[] select4 = new String[]{"1", "3"};
هذه مجموعة من القيم التي ستستقبل القيم التي تنشرها علامة select4.
- السطر 31
<s:select name="select5" list="couleurs" listKey="id" listValue="nom" size="3" key="Form.select5" multiple="true" />
يتم إنشاء قائمة الخيارات بواسطة حقل الألوان المحدد بواسطة سمة القائمة. يتم تعريف حقل الألوان الخاص بعملية [Form] على النحو التالي:
private Couleur[] couleurs;
يتم تعريف فئة [Color] على النحو التالي:
package example;
public class Couleur {
// fields
private String id;
private String nom;
// manufacturer
public Couleur(){
}
// getters and setters
...
}
يحتوي على حقلين باسم id و name. في علامة select5، لدينا listKey="id" و listValue="name". هذا يعني أن حقل id سيكون بمثابة القيمة لخيار ما، وأن حقل name سيكون بمثابة التسمية. تذكر أن قيم الخيارات هي التي يتم إرسالها. سيتم إرسالها إلى حقل select5 التالي:
private String[] select5 = new String[]{"1", "3"};
- السطر 32
<s:checkboxlist name="checkboxlist1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.checkboxlist1"/>
ستنشئ هذه العلامة كود HTML التالي:
جميع مربعات الاختيار تحمل الاسم checkboxlist1. ونظرًا لأنه يمكن تحديد كل منها، فقد يتم إرسال عدة معلمات checkboxlist1. ولذلك، يجب أن يكون حقل checkboxlist1 في النموذج من النوع array. السمة list في السطر 22 عبارة عن قاموس تُنشئ مفاتيحه سمات القيمة لمربعات الاختيار، وتُنشئ قيمه التسميات لتلك المربعات نفسها. حقل checkboxlist1 في الإجراء [Form] هو كما يلي:
private String[] checkboxlist1 = new String[]{"01", "03"};
- السطر 33
<s:checkboxlist name="checkboxlist2" list="dico" key="Form.checkboxlist2"/>
تعمل هذه العلامة مثل علامة select4 التي تمت مناقشتها سابقًا. الحقل المرتبط في الإجراء هو كما يلي:
private String[] checkboxlist2 = new String[]{"1", "3"};
- السطر 34
<s:checkboxlist name="checkboxlist3" list="couleurs" listKey="id" listValue="nom" key="Form.checkboxlist3" />
تعمل هذه العلامة مثل علامة select5 التي تمت مناقشتها سابقًا. ويكون حقل checkboxlist3 المرتبط في الإجراء كما يلي:
private String[] checkboxlist3 = new String[]{"1", "3"};
- السطر 35
<s:radio name="radio1" list="#{'01':'vert(01)','02':'jaune(02)','03':'rouge(03)','04':'blanc(04)','05':'noir(05)'}" key="Form.radio1"/>
تعمل هذه العلامة بنفس طريقة عمل علامة select3 التي رأيناها سابقًا. رمز HTML الذي تم إنشاؤه هو كما يلي:
تحمل جميع أزرار الاختيار نفس الاسم، radio1. لا يمكن تحديد سوى زر اختيار واحد. وبالتالي، يتم إرسال قيمة واحدة فقط: وهي قيمة زر الاختيار المحدد. تُستخدم المفاتيح الموجودة في قاموس القائمة لإنشاء سمات القيمة لأزرار الاختيار، بينما تُستخدم القيم الموجودة في القاموس لإنشاء التسميات المرتبطة بهذه الأزرار. ويكون الحقل radio1 المرتبط في الإجراء كما يلي:
private String radio1="01";
- السطر 36
<s:radio name="radio2" list="dico" key="Form.radio2"/>
تعمل هذه العلامة من حيث المبدأ مثل علامة select4. ويكون حقل radio2 المرتبط بها في الإجراء كما يلي:
private String radio2="1";
- السطر 37
<s:radio name="radio3" list="couleurs" listKey="id" listValue="nom" key="Form.radio3" />
تعمل هذه العلامة بنفس طريقة عمل علامة select5. ويكون حقل radio3 المرتبط بها في الإجراء كما يلي:
private String radio3="1";
وهذا يغطي جزء إدخال البيانات في النموذج. هناك أيضًا قسم للتأكيد مشابه لتلك الموجودة في المثال السابق: حيث يؤكد القيم التي تم إرسالها. سنعلق فقط على الأسطر التالية:
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2SelectedValues"/>
</tr>
وهو ما يوازي بصريًا ما يلي:
![]()
يأتي النص الموجود في الخلية اليسرى من ملف [messages.properties]:
Form.select2=2-select2 (multiple=true, size=3)
تم إنشاء النص الموجود في الخلية اليمنى بواسطة طريقة getSelect2SelectedValues الخاصة بعملية [Form]:
// valeurs sélectionnées dans listes déroulantes
public String getSelect2SelectedValues() {
return getArrayValue(select2);
}
// méthodes utilitaires
public String getArrayValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
تُرجع طريقة getSelect2SelectedValues القيم من القائمة المنسدلة select2 كسلسلة.
10.4. إجراء [Form]
عند مناقشة عرض [Form.jsp]، قدمنا حقول الإجراء [Form] المرتبط. فيما يلي كود الإجراء [Form]:
package example;
import com.opensymphony.xwork2.ActionSupport;
import java.util.HashMap;
public class Form extends ActionSupport {
// form fields
private String select1 = "jaune";
private String[] select2 = new String[]{"vert", "rouge"};
private String[] select3 = new String[]{"01", "03"};
private String[] select4 = new String[]{"1", "3"};
private String[] select5 = new String[]{"1", "3"};
private HashMap<String, String> dico = new HashMap<String, String>();
private Couleur[] couleurs;
private String[] checkboxlist1 = new String[]{"01", "03"};
private String[] checkboxlist2 = new String[]{"1", "3"};
private String[] checkboxlist3 = new String[]{"1", "3"};
private String radio1="01";
private String radio2="1";
private String radio3="1";
private String submitText;
// constructor without parameters
public Form() {
// init color dictionary
dico.put("1", "vert(1)");
dico.put("2", "jaune(2)");
dico.put("3", "bleu(3)");
dico.put("4", "rouge(4)");
dico.put("5", "blanc(5)");
// init array of objects Color
couleurs = new Couleur[dico.size()];
int i = 0;
for (String key : dico.keySet()) {
couleurs[i] = new Couleur();
couleurs[i].setId(key);
couleurs[i].setNom(dico.get(key));
i++;
}
}
// values selected from drop-down lists
public String getSelect2SelectedValues() {
return getArrayValue(select2);
}
public String getSelect3SelectedValues() {
return getArrayValue(select3);
}
public String getSelect4SelectedValues() {
return getArrayValue(select4);
}
public String getSelect5SelectedValues() {
return getArrayValue(select5);
}
public String getCheckboxlist1SelectedValues() {
return getArrayValue(checkboxlist1);
}
public String getCheckboxlist2SelectedValues() {
return getArrayValue(checkboxlist2);
}
public String getCheckboxlist3SelectedValues() {
return getArrayValue(checkboxlist3);
}
// utility methods
public String getArrayValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// getters and setters
...
}
لا توجد طريقة execute في هذا الإجراء. لذلك، يتم تنفيذ طريقة execute الخاصة بالفئة الأصلية ActionSupport. لا تقوم هذه الطريقة بأي شيء وتقوم ببساطة بإرجاع مفتاح التنقل SUCCESS.
10.5. الاختبارات
ندعو القراء إلى اختبار تطبيق [example-08].
