يحتوي Apache Commons على العديد من الأدوات المفتوحة المصدر لحل المشكلات التي يتم مواجهتها غالبًا في البرمجة وتقليل العمالة المتكررة. فيما يلي مقدمة موجزة للأدوات التي استخدمتها خلال عملية التطوير في السنوات القليلة الماضية.
| عناصر | مقدمة وظيفية |
| الفاصوليت | يوفر مختلف العمليات ، والكائنات الاستنساخ ، والخصائص ، وما إلى ذلك ل javabeans. |
| Betwixt | تحويل كائنات XML و Java إلى بعضها البعض. |
| برنامج الترميز | الأدوات التي تتعامل مع طرق الترميز شائعة الاستخدام مثل DES و SHA1 و MD5 و BASE64 ، إلخ. |
| مجموعات | Java Collection Framework Operation. |
| ضغط | يوفر Java مكتبة فئة ضغط ملفات الملفات. |
| إعدادات | مكتبة فئة إدارة التكوين لتطبيقات Java. |
| DBCP | توفير خدمات تجميع اتصالات قاعدة البيانات. |
| dbutils | يوفر تشغيل عملية JDBC لتبسيط عمليات الاستعلام عن البيانات والتسجيل عمليات القراءة. |
| بريد إلكتروني | يرسل Java البريد إلى تغليف Javamail. |
| fileUpload | يوفر وظيفة تحميل الملف. |
| httpclient | يوفر عمليات اتصال مختلفة بين عملاء HTTP والخوادم. لقد تم تغييره الآن إلى httpcomponents |
| IO | تغليف أدوات IO. |
| لانغ | حزم فئة الأدوات لطرق كائن Java Basic مثل: StringUtils ، ArrayUtils ، إلخ. |
| قطع الأشجار | يوفر واجهة تسجيل Java. |
| المدقق | يوفر إطار التحقق من البيانات لجانب العميل والخادم. |
1. BeanUtils يوفر عمليات مختلفة ل javabeans ، مثل الكائن ، نسخ السمات ، إلخ.
// 1. استنساخ كائن // قم بإنشاء فول Java عادي جديد لاستخدامه كشخص فئة عامة مستنسخة {private string name = "" java.util.map ؛ استيراد org.apache.commons.beanutils.beanutils ؛ استيراد org.apache.commons.beanutils.convertutils ؛ اختبار الطبقة العامة {/** * param args */public static void main (string) {// clone person 2 = (person) BeanUtils.cloneBean (person) ؛ system.out.println (person2.getName ()+">>"+person.getage ()) ؛} catch (elepricalaccessexception e) {E.PrintStackTrace () ؛ {E.PrintStackTrace () ؛} catch (nosuchmethodexception e) { // 2. قم بتحويل كائن خريطة إلى حبة // يجب أن يتوافق مفتاح كائن الخريطة هذا مع خصائص الفاصوليا. MAP MAP = NEWHHMAP () ؛ map.put ("name" ، "tom") ؛ map.put ("البريد الإلكتروني" ، "tom@") ؛ map.put ("Age" ، "21") ؛ // تحويل الخريطة إلى شخص شخص شخص ما = شخص جديد () // تحويل الفول إلى كائن خريطة ، على النحو التالي: خريطة الخريطة = beanutils.describe (شخص)2. يتم تحويل كائنات XML وجافا.
// 1. تحويل Javabean إلى محتوى XML // إنشاء شخص جديد من الفئة العامة {اسم السلسلة الخاصة ؛ العصر الخاص ؛/** تحتاج إلى إنشاء الفول عن طريق الانعكاس*/public personbean () {} public personbean (اسم السلسلة ، int age) {this.name = this.age ؛ "'، Age ='" + Age + "''] ؛}} // إنشاء فئة WriteApp: استيراد java.io.stringWriter ؛ import org.apache.commons.betwixt.io.beanwriter ؛ public class writeapp {/*** إنشاء مثال على الفول وتحويله إلى xml. *//public static static void main (string [] args) يرمي الاستثناء {// إنشاء سلسلة stringWriter أولاً ، سنكتبه كأسلوب stringwriter outputWriter = new StringWriter () ؛ // betwixt هنا فقط يكتب الفاصوليا كجزء // or exml efure exml ‘exting- ' ؟>/n ") ؛ // إنشاء كاتب الفول ، والتي سيتم كتابتها إلى الدفق الذي أعددناه. BeanWriter BeanWriter = new BeanWriter (OutputWriter) ؛ // تكوين betwixt // لمزيد من التفاصيل ، يرجى الرجوع إلى مستندات Java أو أحدث مستند BeanWriter.getxMlinTrospector (). getConfiguration (). إذا لم يمر هذا المكان في اسم عقدة الجذر لـ XML ، فسيخمن Betwixt ما هو عليه // ولكن دعنا نستخدم اسم الفاصوليا على سبيل المثال كحبة BeanWriter.write ("الشخص" ، new newbean ("John Smith" ، 21)) ؛ // ولكن هنا مجرد مثال ولن تفعل المزيد ، بحيث يمكنك إيقاف تشغيل OutputWriter.close () ؛}} // 2. قم بتحويل XML إلى Javabean Import Java.io.stringReader ؛ import org.apache.commons.betwixt.io.beanreader ؛ الطبقة العامة readapp {public static void main (string args []) recors {// إنشاء xml أولاً. نظرًا لأن هذا مثال فقط ، فقد قمنا بتصلب قطعة من محتوى XML StringReader XmlReader = جديد StringReader ("<؟ BeanReader.getxMlinTrospector (). getConfiguration (). الشخص الشخصي = (personbean) BeanReader.Parse (XmlReader) ؛ // نتائج الإخراج system.out.println (person) ؛}}3. يوفر برنامج الترميز بعض تطبيقات الترميز العامة ، مثل BASE64 و HEX و MD5 و PHONETAL وعنوان URL ، إلخ.
. "+str) ؛ return str ؛} decodeTest private static void (String str) {base64 base64 = new base64 () ؛ // str = arrays.toString (base64.decodeBase64 (str)) ؛ STR = سلسلة جديدة (BASE64.DECODEBASE64 (STR)) ؛ system.out.println ("base64 decoded:"+str) ؛}4. مجموعات تمتد java.util وتعالج البيانات مرنة للغاية.
org.apache.commons.collections مجموعات Commons مجموعة مخصصة من الواجهات الشائعة وفئات الأدوات
org.apache.commons.collections.bag مجموعة من الفئات التي تنفذ واجهة الحقيبة
org.apache.commons.collections.bidimap مجموعة من الفئات التي تنفذ واجهات سلسلة BIDIMAP
org.apache.commons.collections.buffer مجموعة من الفئات التي تنفذ واجهة المخزن المؤقت
org.apache.commons.collections.callection مجموعة من الفئات التي تنفذ واجهة java.util.collection
org.apache.commons.collections.com Garators مجموعة من الفئات التي تنفذ واجهة java.util.comparator
org.apache.commons.collections.functors مجموعات المشاع مجموعة مخصصة من الفئات الوظيفية
org.apache.commons.collections.iterators مجموعة من الفئات التي تنفذ واجهة java.util.iterator
org.apache.commons.collections.KeyValue تنفذ مجموعة من الفئات المتعلقة بالتجميع ورسم خرائط المفتاح/القيمة
org.apache.commons.collections.list مجموعة من الفئات التي تنفذ واجهة java.util.list
org.apache.commons.collections.map مجموعة من الفئات التي تنفذ واجهات سلسلة الخريطة
org.apache.commons.collections.set مجموعة من الفئات التي تنفذ واجهات SET Series
/** * احصل على مفتاح معين بعد المخزّن في المجموعة */ordermap Map = new LinkedMap () ؛ map.put ("Five" ، "5") ؛ map.put ("Six" ، "6") ؛ map.put ("Seven" ، "7") ؛ map.firstkey () ؛ إرجاع "Seven"/** * احصل على قيمة من خلال مفتاح * احصل على مفتاح من خلال مفتاح التبديل * القيمة في الخريطة */BIDIMAP BIDI = NEW TREEBIDIMAP () ؛ BIDI.PUT ("Six" ، "6") ؛ Bidi.get ("Six") ؛ // Returns "6") // يزيل التعيين العكسي bidiMap = bidi.inverseversidiMap () ؛ // إرجاع خريطة مع مفاتيح وقيم switced system.out.println (عكس) ؛/*** احصل على نفس العنصر في المجموعتين*/list <string> list1 = جديد ArrayList <String> () ؛ list1.add ("1") ؛ list1.add ("2") ؛ list1.add ("3") ؛ قائمة <string> list2 = new ArrayList <string> () ؛ list2.add ("2") list2) ؛ system.out.println (c) ؛5. ضغط العموم المكتبات المعبأة والضغط.
// إنشاء إدخال ziparchiveentry كائن مضغوط = جديد ziparchiveentry ("compressTest") ؛ // الملف المراد ضغطه f = ملف جديد ("e: //test.pdf") ملف ("e: //test.zip")) ؛ zipoutput.putarchiveentry (إدخال) ؛ int i = 0 ، j ؛6. يتم استخدام التكوين للمساعدة في معالجة ملفات التكوين ودعم العديد من طرق التخزين.
1. خصائص ملفات
2. وثائق XML
3. ملفات قائمة الخصائص (.Plist)
4. Jndi
5. JDBC DataSource
6. خصائص النظام
7. معلمات التطبيق
8. معلمات servlet
// إعطاء مثال بسيط للخصائص #usergui.properties colors.background = #fffff colors.Foreground = #000080 window.width = 500 window.height = 300 propertiesConfiguration config = new propertiesConfiguration ("Usergui.Properties") ؛ config.save ("usergui.backup.properties) ؛ // حفظ نسخة integer integer = config.getInteger (" window.width ") ؛7. DBCP (تجمع اتصال قاعدة البيانات) هو تجمع اتصال قاعدة بيانات يعتمد على آلية تجمع كائن Jakarta Commons-Pool. يستخدم مصدر بيانات Tomcat DBCP.
استيراد javax.sql.dataSource ؛ استيراد java.sql.connection ؛ استيراد java.sql.statement ؛ استيراد java.sql.resultset ؛ استيراد java.sql.sqlexception ؛ import org.apache.commons.pool.objectpool ؛ importpool ؛ org.apache.commons.dbcp.connectionfactory ؛ import org.apache.commons.dbcp.poolingdatasource ؛ import org.apache.commons.dbcp.poolableConnectory ؛ static void main (string [] args) {system.out.println ("load jdbc driver") ؛ حاول {class.forname ("oracle.jdbc.driver.oracledriver") ؛} catch (classNotFoundException e) { المصدر ") ؛ dataSource dataSource = setupDataSource (" jdbc: oracle: thin:@localhost: 1521: test ") ؛ system.out.println (" done. datasource.getConnection () ؛ system.out.println ("إنشاء بيان.") ؛ stmt = conn.createstatement () ؛ system.out.println ("تنفيذ بيان.") rset.getMetAdata (). getColumnCount () ؛ بينما (rset.next ()) {for (int i = 0 ؛ i <= numCols ؛ i ++) {system.out.print ("/t"+rset.getString (i)) ؛ {try {if (rset! = null) rset.close () ؛} catch (استثناء e) {} جرب {if (stmt! = null) stmt.close () ؛} catch (استثناء e) {} try {if (conn! connecturi) {// قم بتعيين عنوان الاتصال connectionFactory connectionFactory = جديد drivermanagerConnectionFactory (connecturi ، null) ؛ // إنشاء connectory poolableConnectionFactory poolableConnectory = new PoolableConnectionFactory (connectionFactory) ؛ poolableConnectionFactory) ؛ // إنشاء تجمع poolingdatasource dataSource = جديد poolingDataSource (connectionPool) ؛ return datasource ؛}}8. مكتبة فئة أدوات JDBC المورد المقدمة من مؤسسة DBUTILSAPACHE. إنه تغليف بسيط لـ JDBC ، التغليف الثانوي لفئات قاعدة بيانات التشغيل التقليدية ، ويمكنه تحويل النتيجة المحددة إلى قائمة. ، ولا يؤثر على أداء البرنامج.
فئة DBUTILS: فئة بدء التشغيل
نتائج النتائج: واجهة نوع التحويل
فئة Maplisthandler: فئة التنفيذ ، تحويل السجلات إلى قائمة
فئة Beanlisthandler: تنفذ الفصل ، ويحول السجلات إلى قائمة ، ويجعل السجلات في كائن نوع Javabean
فئة QRERYRUNNER: الفصل الذي ينفذ عبارات SQL
استيراد org.apache.commons.dbutils.dbutils ؛ استيراد org.apache.commons.dbutils.queryrunner ؛ استيراد org.apache.commons.dbutils.handlers.beanlisthandler ؛ استيراد java.sql.connection ؛ استيراد java.sql.drivermanager ؛ java.util.list ؛ // تحويل إلى قائمة الفاصولياء الفئة العامة {public static void main (string [] args) {connection conn = null ؛ String url = "jdbc: mysql: // localhost: 3306/ptest" "ptest" ؛ dbutils.loadDriver (jdbcdriver) ؛ حاول {conn = drivermanager.getConnection (url ، المستخدم ، كلمة المرور) ؛ QueryRunner qr = new QueryRunner () النتائج. size () ؛ معرف ؛ اسم السلسلة الخاصة ؛ // مجموعة set ، get method} import org.apache.commons.dbutils.dbutils ؛ import org.apache.commons.dbutils.queryrunner ؛ import org.apache.commons.dbutils.handlers.maplistthandler ؛ import java.sql.connection ؛ java.sql.sqlexception ؛ استيراد java.util.list ؛ استيراد java.util.map ؛ "com.mysql.jdbc.driver" ؛ string user = "root" ؛ string password = "ptest" ؛ dbutils.loadDriver (jdbcdriver) ؛ try {conn = drivermanager.getConnection (url ، user ، password) ؛ queryrunner qr = new queryrunner () maplisthandler ()) ؛ لـ (int i = 0 ؛ i <results.size () ؛ i ++) {map map = (map) results.get (i) ؛ system.out.println ("id:" + map.get ("id") + "، الاسم:" + map.get ("name")) ؛ {dbutils.closequietly (conn) ؛}}}9. واجهة برمجة تطبيقات مفتوحة المصدر التي توفرها البريد الإلكتروني هي تغليف من Javamail.
// إرسال رسائل بريد إلكتروني باستخدام Commons Email Public Static Void Main (String args []) {email email = new simpleemail () ؛ eLam.SethostName ("smtp.googlemail.com") ؛ email.setsmtpport (465) ؛ email.setauthenticator (defaultauthenticator (username "، username ، "كلمة المرور"))) ؛ البريد الإلكتروني. setsslonconnect (true) ؛ email.setFrom ("[email protected]") ؛ email.setsubject ("testmail") ؛ email.setmsg ("هذا بريد اختبار ... :-)")10. FileUpload Java Web File File Compload.
// مثال رسمي: //* تحقق من أن لدينا طلب تحميل ملفات iSmultipart = servletFilePload.ismultipartContent (طلب) ؛ // الآن لدينا قائمة بالعناصر // إذا كان تطبيقك قريبًا من أبسط الحالات ، فإن المعالجة أعلاه كافية. لكن في بعض الأحيان ما زلنا بحاجة إلى مزيد من السيطرة. . servletfileupload (مصنع) ؛ // قم بتعيين الحد الأقصى لتحميل حجم التحميل. setsizezemax (yourmaxRequestSize) ؛ // تحليل جميع الطلبات/ * fileItem */items = upload.parserequest (request) ؛ yourtempdirectory) ؛ // بمجرد الانتهاء من التحليل ، تحتاج إلى معالجة قائمة العناصر. // معالجة العناصر التي تم تحميلها iterator iter = items.iterator () ؛ بينما (iter.hasnext ()) {fileItem item = (fileItem) iter.next () ؛ if (item.isformfield ()) {processformfield (item) ؛} else {processUploadedFile (item) ؛}} // التمييز بين ما إذا كانت البيانات بسيطة بيانات النماذج ، إذا كانت بيانات بسيطة: // processFormField (item.isformfield ()) {string. // processUploadedFile if (! item.isformfield ()) {String fieldName = item.getFieldName () ؛ string filename = item.getName () ؛ string contentType = item.getContentType () اكتبها إلى ملف ، أو تحويلها إلى دفق // معالجة ملف تحميل إذا (writeTofile) {file eploadedfile = new file (...) ؛ item.write (exploadedfile) ؛} آخر {inputStream uploadedStream = item.getInputStream () ؛ // ... تم حذف الخطوات المحملة التحميل في الذاكرة بايت [] data = item.get () ؛ // ... الخطوات المحذوفة // إذا كان هذا الملف كبيرًا حقًا ، فقد ترغب في الإبلاغ عن المستخدم إلى أي مدى تم نقله إلى الخادم ، حتى يتمكن المستخدم من فهم عملية التحميل // إنشاء ProgontLister Progressener = New Progresser () {system.out.println ("نحن نقرأ حاليًا العنصر" + pitems) ؛ if (pcontentLength == -1) {system.out.println ("حتى الآن ،" + pbytesread + "لقد تمت قراءة البايت.") اقرأ. ") ؛}}} ؛ Upload.SetProgressRistener (ProgressListener) ؛11. httpclien هو عميل HTTP متوافق مع HTTP/1.1 تم تنفيذه على أساس HTTPCORE. يوفر سلسلة من مصادقة العميل القابلة لإعادة الاستخدام ، وصيانة حالة HTTP ، ووحدات إدارة اتصال HTTP.
// احصل على طريقة استيراد java.io.ioException ؛ استيراد org.apache.commons.httpclient.*؛ استيراد org.apache.commons.httpclient.methods.getMethod ؛ public org.apache.commons.httpclient.httpmmethodparam ؛ قم بإنشاء مثيل لـ httpclient httpclient httpclient = new httpclient () ؛ // إنشاء مثيل get getMethod getMethod = new getMethod ("http://www.ibm.com") ؛ // استخدم سياسة الاسترداد الافتراضية التي توفرها النظام إلى النظام إلى النظام getMethod.getParams (). setParameter (httpmethodparams.retry_handler ، defaulthttpmethodretryhandler ()) ؛ حاول {// تنفيذ getMethod int statusCode = httpclient.executemethod (getMethod) ؛ if (statusCode! = httpstatus.sc_ok) {system.err.println ("فشل الطريقة:" + getMethod.getStatusLine ()) ؛} // قراءة المحتوى بايت [] استجابة = getMethod.getResponseBonse () ؛ // التعامل مع المحتوى. حدث ، والذي قد يكون أن البروتوكول غير صحيح أو أن المحتوى الذي تم إرجاعه هو نظام إشكالي. getMethod.ReleAseconnection () ؛}}}} // طريقة ما بعد استيراد java.io.ioException ؛ استيراد org.apache.commons.httpclient.*؛ postsample {public static void main (string [] args) {// إنشاء مثيل httpclient httpclient httpclient = new httpclient () ؛ // إنشاء مثيل من طريقة post url = "http://www.oracle.com/" ؛ postmethod postmethoD = new the the the earl ؛ namevaluepair [] data = {new namevaluepair ("id" ، "youusername") ، new namevaluepair ("passwd" ، "yourpwd") لا يمكن لـ httpclient التعامل تلقائيًا مع التوجيه للطلبات التي تتطلب خدمات لاحقة مثل post and put // 301 أو 302 if (statusCode == httpstatus.sc_moved_permanywally || stationCode == httpStatus.sc_moved_temporialy) postmethod.getResponseHeader ("location") ؛ string location = null ؛ if (locationheader! = null) {location = locationHeader.getValue () ؛ system.out.println ("تم إعادة توجيه الصفحة إلى:12. IO مريحة للغاية لـ Java.io لتوسيع ملف التشغيل.
// 1. اقرأ Dream // الكود القياسي: inputStream في = url جديد ("http://jakarta.apache.org") .OpenStream () ؛ حاول {inputStreamReader inr = new inputStreamReader (in) ؛ bufferedReader buf = new bufferreader (inr) ؛ {system.out.println (line) ؛}} أخيرًا {in.close () ؛} // استخدم ioutils inputStream في = url new url ("http://jakarta.apache.org") .OpenStream () ؛ try {ioutils.closequietly (in) ؛} // 2. اقرأ ملف ملف الملف = ملف جديد ("/commons/io/project.properties") ؛ List Lines = FileUtils.Readlines (ملف ، "UTF-8") ؛ // 3. عرض المساحة المتبقية الطويلة freeSpace = fileSystemUtils.freespace ("C:/") ؛13. لانج هي أساسا مجموعة من الأدوات العامة ، مثل العمليات على الشخصيات ، والصفائف ، إلخ.
// 1 دمج صفيفتين: org.apache.commons.lang. ArrayUtils // في بعض الأحيان نحتاج إلى الجمع بين صفيفتين في صفيف ، وهو مناسب جدًا لاستخدام المصفوفات. المثال هو كما يلي: private static void testarr () {string [] s1 = new string [] {"1" ، "2" ، "3"} ؛ string [] s2 = new string [] {"a" ، "b" ، "c"} ؛ string [] s = (string []) {system.out.println (s [i]) ؛} string str = arrayutils.toString (s) ؛ str = str.substring (1 ، str.length () - 1) ؛ system.out.println (str + ">>" + str.length ()) ؛ ما إذا كانت السلسلة تتكون من أرقام (0 ~ 9). إذا كان الأمر كذلك ، فالتراجع صحيحًا ، لكن هذه الطريقة لا تتعرف على النقاط العشرية ويرجى ملاحظة أن stringUtils.isnumeric ("454534") ؛ // إرجاع TRUE // 4. احصل على اسم الفصل system.out.println (classUtils.getShortClassName (test.class)) ؛ // احصل على اسم الحزمة system.out.println (classUtils.getPackageName (test.class)) ؛ //5.numberutils system.out.println (numberUtils.StringToint ("6")) ؛ // 6. أحرف وأرقام عشوائية مكونة من خمسة أرقام. //7. ")) ؛ // افصل المحتويات في الصفيف بواسطة system.out.println (stringUtils.join (test ،" ، "،") System.out.println (stringUtils.Capitalize ("ABC")) ؛ // يحذف جميع المساحات البيضاء من سلسلة حذف جميع المساحات system.out.println (stringutils.deletewhitespace ("abc")) ؛ "ba")) ؛ // يشير إلى الحرفين على النظام الأيسر.14. يوفر التسجيل واجهة تسجيل Java ، والتي تأخذ في الاعتبار كلاً من الوزن الخفيف ولا تعتمد على أدوات تنفيذ سجل محددة.
استيراد org.apache.commons.logging.log ؛ import org.apache.commons.logging.logfactory ؛ فئة عامة commonlogtest {private static log = logfactory.getlog (commonlogtest.class) ؛ {log.error ("error") ؛ log.debug ("debug") ؛ log.warn ("warn") ؛ log.info ("info") ؛ log.trace ("trace") 15. المدقق هو نظام التحقق العام ، والذي يوفر إطارًا للتحقق من البيانات لجانب العميل والخادم.
تاريخ التحقق
// الحصول على تاريخ التحقق من Datevalidator Validator = datevalidator.getInstance () ؛ // التحقق/تحويل تاريخ التاريخ foodate = validator.validate (foostring ، "dd/mm/yyyy") ؛ if (
التحقق من التعبير
// قم بتعيين المعلمة boolean cases حساس = خطأ ؛ regex1 = "^([az]*) (؟: //-) ([az]*)*$" regex2 = "^([az]*) $" regexvalidator (regexs ، الحالات الحساسة) ؛ // تحقق من الإرجاع المنطقي الصالح = Valitator.isvalid ("ABC-DEF") ؛استخدم التحقق في ملفات التكوين
<form-valaction> <loblal> <validator name = "requiret" className = "org.apache.commons.validator.testvalidator" method = "acedaterequired" methodParams = "java.lang.object ، org.apache.commons.validator.field"/>/global> <form-valaction> <loblal> <validator name = "requiret" className = "org.apache.commons.validator.testvalidator" method = "exalaterequired" methodparams = "java.lang.object ، org.apache.commons.validator.field"/>/global> يعتمد = "مطلوب"> <arg0 key = "nameform.firstName.disPlayName"/> </field> <field property = "lastName" يعتمد = "مطلوب"> <arg0 key = "nameform.lastname.displayName"/> </formset> </form-validation>
فئة التحقق
تتفوق من org.apache.commons.validator.requirednametest // تحميل ملف تكوين التحقق في = this.getclass (). لقد حذفت اسم الاسم = new name () ؛ التحقق من التحقق = مصلحة جديدة (الموارد ، "nameform") ؛ // قم بتعيين المعلمة Valitator.setParameter (adadator.bean_param ، name) ؛ نتائج الخريطة = null ؛ ((integer) results.get ("FirstName")). Intvalue () ؛}لخص
ما سبق هو كل التفسير التفصيلي لرمز مجموعة أدوات Apache Commons في هذه المقالة ، وآمل أن يكون مفيدًا للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى الموضوعات الأخرى ذات الصلة على هذا الموقع. إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها. شكرا لك يا أصدقائك لدعمكم لهذا الموقع!