9. العمل مع مصدر البيانات
نهدف هنا إلى إرساء الأساس للعمل مع قواعد البيانات داخل تطبيق Struts.
9.1. تطبيق Struts /listarticles
نريد عرض محتويات جدول يخزن خصائص العناصر التي تبيعها متجر.
![]() |
|
يحتوي الجدول على ما يلي:

سيعرض تطبيق listarticles نفس المعلومات (وإن كان ذلك بشكل أقل أناقة) على صفحة ويب:

9.2. تكوين تطبيق Struts /listarticles
ملف web.xml الخاص بالتطبيق قياسي:
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</web-app>
يقدم ملف struts-config.xml قسمًا جديدًا باسم <data-sources> يتيح لك تعريف مصادر البيانات وتكوينها:
struts-config.xml
<?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>
<data-sources>
<data-source key="dbarticles">
<set-property property="driverClass" value="com.mysql.jdbc.Driver"></set-property>
<set-property property="url" value="jdbc:mysql://localhost/dbarticles"></set-property>
<set-property property="user" value="admarticles"></set-property>
<set-property property="password" value="mdparticles"></set-property>
<set-property property="minCount" value="2"></set-property>
<set-property property="maxCount" value="5"></set-property>
</data-source>
</data-sources>
<action-mappings>
<action path="/liste" type="istia.st.struts.articles.ListeArticlesAction">
<forward name="afficherListeArticles" path="/vues/listarticles.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
</action-mappings>
<message-resources parameter="istia.st.struts.articles.ApplicationResources"
null="false" />
</struts-config>
9.2.1. مصادر البيانات
يُستخدم قسم <data-sources> لإعلان جميع مصادر بيانات التطبيق، ويتم وصف كل منها بواسطة قسم <data-source>. تدعم هذه العلامة عدة سمات:
يحدد مصدر البيانات عند وجود مصادر متعددة. | |
اسم الفئة التي سيتم إنشاء مثيل لها للوصول إلى قاعدة البيانات. توجد هذه الفئة عادةً في مكتبة فئات (.jar) مقدمة من مورد نظام إدارة قواعد البيانات (DBMS). تحتوي هذه المكتبة على برنامج تشغيل JDBC للوصول إلى قاعدة البيانات. تحدد خاصية driverClass برنامج التشغيل هذا. سيتم وضع ملف .jar الذي يحتوي على فئات الوصول إلى نظام إدارة قواعد البيانات (DBMS) في مجلد WEB-INF/lib الخاص بالتطبيق. | |
سلسلة الاتصال بقاعدة بيانات معينة. يتيح برنامج تشغيل JDBC الوصول إلى جميع قواعد البيانات التي يديرها نظام إدارة قواعد البيانات (DBMS). وتسمح لنا خاصية url بتحديد القاعدة التي سنستخدمها. | |
الوصول إلى قاعدة البيانات محمي. يدير نظام إدارة قواعد البيانات (DBMS) المستخدمين الذين يتم تحديدهم بواسطة اسم المستخدم وكلمة المرور. يتم تحديد هذين العنصرين في سمات user و password الخاصة بالعلامة. | |
تدير Struts مجموعة من الاتصالات بنظام إدارة قواعد البيانات (DBMS). يعد فتح اتصال بنظام إدارة قواعد البيانات (DBMS) عملية تستهلك الكثير من الموارد من حيث الوقت والذاكرة. بدلاً من فتح وإغلاق اتصال بنظام إدارة قواعد البيانات (DBMS) لكل طلب يتم إرساله إلى التطبيق، يدير التطبيق مجموعة من n اتصالاً، حيث n تقع في النطاق [minCount، maxCount]. إذا احتاج التطبيق إلى اتصال أثناء الطلب: - سيحاول الحصول على اتصال من مجموعة الاتصالات. إذا وجد اتصالاً متاحاً، فسيستخدمه. - إذا لم تكن هناك اتصالات متاحة في المجموعة وكان عدد الاتصالات في المجموعة أقل من maxCount، يتم فتح اتصال جديد وإضافته إلى المجموعة. ويمكن للاستعلام الحالي استخدامه. - إذا لم تكن هناك اتصالات متاحة ولا توجد طريقة لإنشاء اتصال جديد، يتم تعليق الطلب. عندما يغلق الطلب الحالي الاتصال، لا يتم إغلاقه فعليًا بل يتم إرجاعه إلى المجموعة. |
هنا، لدينا الخصائص التالية:
dbarticles - هذا هو الاسم الذي سيُعرف به مصدر البيانات في سياق التطبيق | |
com.mysql.jdbc.Driver. نحن نستخدم قاعدة بيانات MySQL. | |
jdbc:mysql://localhost/dbarticles. اسم قاعدة البيانات هو dbarticles وتقع على الجهاز المحلي. | |
admarticles، mdparticles. تم منح هذا المستخدم امتيازات كاملة على قاعدة البيانات dbarticles. | |
2، 5. الحد الأدنى لعدد الاتصالات في المجموعة هو 2، والحد الأقصى هو 5. |
9.2.2. الإجراءات
الإجراءات المعلنة في ملف تكوين Struts هي كما يلي:
<action-mappings>
<action path="/liste" type="istia.st.struts.articles.ListeArticlesAction">
<forward name="afficherListeArticles" path="/vues/listarticles.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
</action-mappings>
الإجراء الوحيد يسمى /list وهو مرتبط بالفئة istia.st.struts.articles.ListeArticlesAction. ينتهي هذا الإجراء بعرض:
- صفحة المقالات (/vues/listarticles.jsp)
- صفحة الخطأ (/views/errors.jsp)
9.2.3. ملف الرسائل
سيتم وضع ملف الرسائل ApplicationResources.properties في المجلد WEB-INF/classes/istia/st/struts/articles. وسيكون محتواه كما يلي:
# erreurs
errors.header=<ul>
errors.footer=</ul>
erreur.dbarticles=<li>Erreur d'accès à la base des articles ({0})</li>
يمكن أن يحدث خطأ واحد فقط: خطأ في الوصول إلى قاعدة البيانات. في الواقع، هناك عدة أنواع محتملة من الأخطاء، يتم تجميعها جميعًا تحت نفس رسالة الخطأ. ومع ذلك، سيتم تحديد السبب الدقيق للخطأ في المعلمة {0}.
9.3. طرق العرض
9.3.1. طريقة العرض errors.jsp
يجب أن تعرض هذه العرض قائمة بالأخطاء. وقد صادفناها عدة مرات بالفعل.
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Liste d'articles - erreurs</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<html:errors/>
</body>
</html>
تعرض هذه الطريقة ببساطة قائمة الأخطاء باستخدام العلامة <html:errors/>.
9.3.2. عرض listarticles.jsp
يجب أن تعرض هذه الطريقة محتويات جدول ARTICLES في قاعدة البيانات. وفيما يلي شفرتها:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%
// listarticles : ArrayList dans la requête
// listArticles(i) : tableau (String[5]) de 5 éléments
%>
<html>
<head>
<title>DataSource Struts</title>
</head>
<body>
<h3>Liste des articles</h3>
<hr>
<table border="1">
<logic:iterate id="ligne" name="listArticles">
<tr>
<logic:iterate id="colonne" name="ligne">
<td><bean:write name="colonne"/></td>
</logic:iterate>
</tr>
</logic:iterate>
</table>
</body>
</html>
ستقوم الإجراء /list بوضع محتويات جدول ARTICLES في كائن ArrayList يسمى listArticles في الطلب. كل عنصر من عناصر كائن listArticles هو مصفوفة من 5 سلاسل تمثل 5 معلومات (code, name, price, currentStock, minimumStock) مرتبطة بعنصر في الجدول. يجب أن تعرض طريقة العرض محتويات كائن listArticles في جدول HTML. للقيام بذلك، تستخدم العلامة <logic:iterate>:
<logic:iterate id="ligne" name="listArticles">
<tr>
<logic:iterate id="colonne" name="ligne">
<td><bean:write name="colonne"/></td>
</logic:iterate>
</tr>
</logic:iterate>
هناك تكراران هنا. الأول يتكرر على عناصر كائن ArrayList listArticles. يُسمى العنصر الحالي لـ listArticles هنا row. يمثل عنصر row كائن String[5] يتم تجاوزه باستخدام التكرار الثاني. يُسمى عنصر هذا التكرار الثاني column. وهو يمثل العنصر الحالي لمصفوفة من السلاسل، وبالتالي فهو سلسلة (code، name، price، currentStock، minimumStock). يتم عرض قيمته باستخدام العلامة <bean:write>.
تستخدم طريقة العرض علامات من مكتبات struts-logic و struts-bean. لذلك، يجب عليك الإعلان عن استخدامها:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
9.4. الإجراء /list
الغرض من الإجراء /list هو تضمين كائن ArrayList يمثل محتويات جدول ARTICLES في الطلب، بحيث يمكن للعرض استخدامه. وفيما يلي كوده:
package istia.st.struts.articles;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class ListeArticlesAction extends Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// reads the contents of a connection's items table
// performed at context init
// retrieve the dbarticles data source
DataSource dataSource = this.getDataSource(request, "dbarticles");
if (dataSource == null) {
// the data source could not be created
ActionErrors erreurs = new ActionErrors();
erreurs.add( "dbarticles",new ActionError("erreur.dbarticles","La source de données n'a pu être créée"));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// here the data source exists - we use it Conne ction connexion = null;
Statement st = null;
ResultSet rs = null;
String requête = null;
ArrayList alArticles = new ArrayList();
// error handling
try {
// get a connection
connexion = dataSource.getConnection();
// prepare query SQL
requête =
"select code, nom, prix, stockActuel, stockMinimum from articles order by nom";
// execute it
st = connexion.createStatement();
rs = st.executeQuery(requête);
// exploit results
while (rs.next()) {
// save current line
alArticles.add(
new String[] {
rs.getString("code"),
rs.getString("nom"),
rs.getString("prix"),
rs.getString("stockactuel"),
rs.getString("stockMinimum")});
// next line
} //while
// free up resources
rs.close();
st.close();
connexion.close();
} catch (Exception ex) {
// errors have occurred
ActionErrors erreurs = new ActionErrors();
erreurs.add("dbarticles",new ActionError("erreur.dbarticles", ex.getMessage()));
this.saveErrors(request, erreurs);
return mapping.findForward("afficherErreurs");
}
// it's good
request.setAttribute("listArticles", alArticles);
return mapping.findForward("afficherListeArticles");
} //execute
} //class
من المرجح أن يكون القارئ قادراً على فهم جوهر الكود أعلاه. سنركز فقط على العنصر الجديد الوحيد: استخدام كائن DataSource المقدم من إطار عمل Struts. يمثل كائن DataSource هذا مجموعة الاتصالات التي تم تكوينها بواسطة قسم <data-source key="dbarticles"> في ملف التكوين. بعد إنشائه، تم وضع كائن DataSource في سياق التطبيق بحيث يمكن لجميع الكائنات في ذلك السياق الوصول إليه. وبالتالي يتم استرجاعه على النحو التالي:
// retrieve the dbarticles data source
DataSource dataSource = this.getDataSource(request, "dbarticles");
هنا، نطلب مصدر البيانات المحدد بالمفتاح "dbarticles". إذا استردنا مؤشرًا فارغًا، فهذا يعني أنه لم يتم إنشاء مصدر البيانات أثناء تهيئة التطبيق. في هذه الحالة، نقوم بتسجيل الخطأ في كائن ActionErrors ونعيد التوجيه إلى صفحة الخطأ المحددة بالمفتاح "afficherErreurs" في ملف التكوين:
<action path="/liste" type="istia.st.struts.articles.ListeArticlesAction">
<forward name="afficherListeArticles" path="/vues/listarticles.jsp"/>
<forward name="afficherErreurs" path="/vues/erreurs.jsp"/>
</action>
</action-mappings>
بمجرد الحصول على مصدر البيانات، يصبح بإمكاننا الوصول إلى مجموعة الاتصالات. يتم الحصول على اتصال بقاعدة البيانات باستخدام الكود التالي:
هنا، سيوفر لنا المجمع اتصالاً معاد استخدامه أو اتصالاً تم إنشاؤه حديثاً إذا كانت هناك اتصالات متاحة.
9.5. النشر
يتم تعريف سياق التطبيق في ملف التكوين server.xml الخاص بـ Tomcat:
<Context path="/listarticles" reloadable="true" docBase="E:\data\serge\web\struts\articles\liste" />
هيكل دليل التطبيق كما يلي:
![]() ![]() | |||
![]() ![]() | |||
![]() | |||
لاحظ مكتبة mysql-connector-java-3.0.10-stable-bin.jar الموجودة في WEB-INF/lib. هذا هو الملف الذي يحتوي على برنامج تشغيل JDBC لقاعدة بيانات MySQL المستخدمة هنا.
9.6. الاختبار
نقوم بتشغيل Tomcat ونطلب عنوان URL http://localhost:8080/listarticles/liste.do:

9.7. مصدر بيانات ثانٍ
نستخدم الآن مصدر بيانات ثانٍ موجود في قاعدة بيانات Postgres. هنا أيضًا، توجد البيانات في جدول ARTICLES الذي يحتوي على نفس الأعمدة السابقة. ومحتوياته كما يلي:

يتم الإعلان عن مصدر البيانات الجديد هذا في ملف تكوين Struts:
<data-sources>
<data-source key="dbarticles" >
<set-property property="driverClass" value="com.mysql.jdbc.Driver"></set-property>
<set-property property="url" value="jdbc:mysql://localhost/dbarticles"></set-property>
<set-property property="user" value="admarticles"></set-property>
<set-property property="password" value="mdparticles"></set-property>
<set-property property="minCount" value="2"></set-property>
<set-property property="maxCount" value="5"></set-property>
</data-source>
<data-source key="pgdbarticles" type="org.apache.commons.dbcp.BasicDataSource">
<set-property property="driverClassName" value="org.postgresql.Driver" />
<set-property property="url" value="jdbc:postgresql://localhost/dbarticles" />
<set-property property="username" value="serge" />
<set-property property="password" value="serge" />
<set-property property="maxActive" value="10" />
<set-property property="maxWait" value="5000" />
<set-property property="defaultAutoCommit" value="false" />
<set-property property="defaultReadOnly" value="false" />
</data-source>
</data-sources>
سيكون لمصدر البيانات الجديد المعرف (المفتاح) pgdbarticles. تأتي الميزة الجديدة من الفئة التي تنفذ واجهة javax.sql.DataSource. الفئة الافتراضية هي org.apache.struts.util.GenericDataSource، المحددة في مكتبة struts.jar. سيتم إهمال هذه الفئة في الإصدارات المستقبلية من Struts، وبالنسبة للإصدار 1.1، يوصى باستخدام فئة org.apache.commons.dbcp.BasicDataSource الموجودة في مكتبة commons-dbcp-1.1.jar. لا يتم تضمين هذه المكتبة بالضرورة مع حزمة Struts. يمكن العثور عليها على عنوان URL http://jakarta.apache.org/commons/index.html، وتحديدًا في http://jakarta.apache.org/site/binindex.cgi. يجب عليك تنزيل المنتج المسمى Commons DBCP. بالنسبة لنظام Windows، يمكنك تنزيل ملف .zip. يحتوي هذا الملف على كود مصدر المكتبة بالإضافة إلى ملف .jar المقابل. يجب عليك استخراج هذا الملف من أرشيف .zip ووضعه في مجلد WEB-INF/lib الخاص بالتطبيق. يجب عليك أيضًا وضع برنامج التشغيل الخاص بنظام إدارة قواعد البيانات المستخدم في نفس المجلد:

لاستخدام مصدر البيانات هذا، نقوم بتغيير عبارة في كود الإجراء /list:
هذه المرة، نطلب مصدر البيانات المسمى pgdbarticles، أي مصدر بيانات Postgres.
كل ما تبقى هو ترجمة كل شيء، وتشغيل Tomcat، وطلب عنوان URL http://localhost:8080/listarticles/liste.do:

9.8. خاتمة
لقد أوضحنا كيفية استخدام تجمع الاتصالات للوصول إلى قاعدة البيانات. لاحظ أننا لم نتبع بنية MVC هنا. في الواقع، يقوم الإجراء /list نفسه بتنفيذ استعلامات SQL للوصول إلى البيانات. كان من الأفضل أن يستدعي فئة أعمال وسيطة تخفي حقيقة أن البيانات يتم استردادها من نظام إدارة قاعدة البيانات. ومن المرجح أن تقوم فئة الأعمال بعد ذلك بإنشاء تجمع الاتصالات، ولن تكون هناك حاجة لإعلانه في ملف تكوين Struts. وإليك تلميحًا: قد يشير وجود قسم <data-sources> في ملف التكوين إلى أن تطبيقنا لا يتبع بنية MVC.





