Learn Java
Learn Java
لغة جافا
لغة جافا ظهرت في عام ) 1995أي قبل أكثر من عشرين عاماا( وهي لغة متعددة اﻷغراض ومتعددة المنصات تصلح
لعدد كبير من التطبيقات .ومترجم جافا يقوم بإنتاج ملفات في شكل Byte codeوهو يختلف عن الملفات
التفيذية التي تنتج عن لغات البرمجة اﻷخرى مثل سي وباسكال .وتحتاج البرامج المكتوبة بلغة جافا إلى منصة
في أنظمة التشغيل المختلفة لتتمكن برامجها من العمل في هذه اﻷنظمة .وهذه المنصة يتسمة آلة جافا اﻹفتراضية
Java Virtual Machineأو إختصاراا بـ JVMأو .Java Run-time
jre8u51windowsx64.exe
وهو ييمثل نسخة جافا 1.8أو ماييسمى جافا 8وهي آخر نسخة من الجافا متوفرة لحظة إعادة تحرير هذا الكتاب.
واسم الملف التالي ييمثل حزمة تحتوي على اللة اﻹفتراضية لجافا 8لنظام أوبونتو :
openjdk8jre
وتختلف معماريتها حسب معمارية نظام أوبونتو ،فإذا كان النظام هو 32بت تكون حزمة جافا 32بت ،وإذا كان 64
بت تكون حزمة جافا 64بت .لكن يمكن تثبيت جافا 32بت في نظام أوبونتو 64بت -كذلك في نظام وندوز-
وذلك ﻷن بعض البرامج تتطلب جافا 32بت ،لكن ل يمكن تثبيت جافا 64بت في نظام تشغيل 32بت.
توجد أدوات تطوير أخرى مشهورة و هي Eclipseوهي مستخدمة من قبل مبرمجين يكثر ،و أخرى تسمى IntelliJ
والتي يبنيت عليها بيئة تطوير أندرويد.
جميع بيئات التطوير هذه تحتاج إلى تثبيت Java SDKأولا قبل تثبيتها
ترخيص الكتاب
هذا الكتاب مجاني تحت ترخيص
creative commons
CC BY-SA 3.0
ملحوظة
ل ييفُضضلّ نسخ ثم اللصق في بيئة NetBeansمن هذا الكتاب لنه يتم أحيان ا ا نقلّ أحرف غير مرئية تتسب في تعثر ترجمة البرامج .لذلك من
الفضلّ كتابة المثلة يدوياا.
ثم بعد ذلك في الشاشة التالية لبد من التأكد من اختيار جافا :SDK
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package hello;
/*
*
* @author motaz
*/
public class Hello {
/*
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
}
}
كماNetBeans بواسطة شاشة المشروع التي تظهر يسار شاشةhello.java فإذا لم يظهر الكود نقوم بفتح الملف
:في الشكل التالي
/**
*
* @author motaz
*/
public class Hello {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
System.out.print("Hello Java world\n");
}
}
لتشغيل البرنامج الناتج خارج بيئة التطوير ،نقوم أولا ببناء الملف التفنيذي بواسطة Buildوذلك بالضغط على
المفاتيح . Shift + F11بعدها نبحث عن الدليل الذي يحتوي على برامج NetBeansويكون اسمه في الغالب
NetBeansProjectsثم داخل الدليل helloنجد دليل اسمه distيحتوي على الملف التنفيذي .في هذه الحالة
يكون اسمه hello.jar
ييمكن تنفيذ هذا البرنامج في سطر اﻷوامر في نظام التشغيل بواسطة كتابة اﻷمر التالي:
java jar hello.jar
ييمكن نقل هذا الملف التنفيذي من نوع Byte codeإلى أي نظام تشغيل آخر يحتوي على آلة جافا اﻹفتراضية ثم
تنفيذه بهذه الطريقة .وينلحظ أن حجم الملف التنفيذي صغير نسبياا )حوالي كيلو ونصف( وذلك ﻷننا لم نستخدم
مكتبات إضافية.
بعد ذلك نقوم بتغيير الكود إلى التالي:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package hello;
import java.util.Date;
/*
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
int num = 9;
}
}
: وهذا هو ناتج تشغيل البرنامج
9 * 2 = 18
Today is: Fri Jul 31 11:59:46 EAT 2015
والناتج هو:
Today is: 31.07.2015 12:03
ويمكن تغيير النسق بتغيير موضع الرموز التي ترمز لمكونات التاريخ وهي:
ddييمثل اليوم
MMييمثل رقم الشهر
yyyyييمثل السنة كاملة ،يمكن اختصارها في yyلتصبح رقمين فقط ،مثلا 15والتي تعني 2015
:HHالساعة بنسق 24ساعة
:mmالدقائق
:ssالثواني
في المثال التالي يقمنا بتغيير لون جزء من النص بالطريقة التالية:
لكتابة أول برنامج ذو واجهة رسومية في جافا باستخدام NetBeansنختار File/New Project
ثم نختار Java/Java Application
ونقوم بتسميته مثلا .mygui
في شاشة Projectsنختار الحزمة myguiثم بالزر اليمين للماوس نختار New/JFrame Form
نسمى هذا الفورم MainFormفيتم إضافته للمشروع ويظهر بالشكل التالي:
يظهر الفورم الرئيسي المسمى MainForm.javaفي وسط الشاشة .وفي اليمين نلحظ وجود عدد من المكونات
في صفحة الـ .Paletteنقوم بإدراج زر Buttonفي وسط الفورم الرئيسي ،ثم نقوم بتغيير عنوانه إلى ،Hello
وذلك إما بالضغط على زر F2ثم تغيير العنوان ،أو بالنقر على الزر اليمين في الماوس في هذا الزر ثم نختار
نرجع مرة أخرى للخصائص لنضيف حدث عند الضغط على الزر .هذه المرة نختار Eventsثم في الخيار
actionPerformedنختار الحدث jButton1ActionPerformedبعدها يظهر هذا الكود في شاشة الـ :Source
نلحظ أننا يقمنا بتعريفا المتغير msgمن النوع المقطعي Stringثم يقمنا بإسناد قيمة إبتدائية له“ :السلم عليكم”
بعد ذلك نرجع للحزمة الرئيسية Mygui.javaثم نكتب الكود التالي في اﻹجراء :main
نرجع مرة أخرى للفورم في شاشة التصميم ) (Designونقوم بإدراج المكون TextFieldليندخل فيه إسم
المستخدم ،ثم مكون من نوع Labelنكتب فيه كلمة )اﻹسم( ثم مكون آخر من نوع Labelنقوم بتغير إسمه إلى
jlNameوذلك في فورم الخصائص في صفحة Codeفي
قيمة Variable Name
ثم يندرج زر نكتب فيه كلمة )ترحيب( كما في الشكل التالي:
في الحدث ActionPerfomedلهذا الزر الجديد )ترحيب( نكتب الكود التالي لكتابة إسم المستخدم في المكون
jLabel2
الفورم الثاني
ﻹضافة وإظهار فورم ثاني في نفس البرنامج ،نتبع الخطوات في المثال التالي:
نقوم بإضافة JFrame Formونسميه SecondFromونضع فيه Labelنكتب فيه عبارة "”Second Form
ونزريد حجم الخط في هذا العنوان بواسطة .Properties/Font
في خصائص هذا الفورم الجديد نقوم بتغيير الخاصية defaultCloseOperationإلى Disposeبدلا من
EXIT_ON_CLOSEﻷننا إذا تركناها في الخيار اﻷخير يتم إغلق البرنامج عندما نغلق الفورم الثاني .وجرت
العادة أن يتم إغلق أي برنامج عند إغلق شاشته الرئيسة .إغلق الشاشات الفرعية يفترض به أن يقودنا إلى
الشاشات الرئيسة.
نضيف زر في الفورم الرئيسي MainFormونكتب الكود التالي في الحدث ActionPerformedفي هذا الزر
الجديد ﻹظهار الفورم الثاني ،أو يمكن كتابة هذا الكود في زر الترحيب.
;)(SecondForm second = new SecondForm
في المثال التالي سوف نقوم باختبار وجود الملف myfle.txtوإذا لم يكن موجود سوف يقوم البرنامج بإنشاء
ملف جديد بهذا اﻹسم:
نلحظ أننا استخدمنا عبارة throws IOExceptionفي نهاية الدالة الرئيسية mainوذلك لحتمال حدوث خطأ
أثناء إنشاء الملف ،مث ا
ل قد يكون المسار المحدد هو للقراءة فقط ،أو ليس للمستخدم الحالي صلحية لكتابة ملف
في هذا المسار ،أو ربما يكون المسار غير موجود في اﻷساس.
كذلك استخدمنا النوع Fileوقمنا بتعريف كائن منها هو fleوذلك لغرض ربط البرنامج بالملف الخارجي على
القرص .ويمكن عمل عدة عمليات للملف مثل الحذف fle.deleteاو اﻹنشاء fle.createNewFileأو التأكد من
وجود الملف fle.exists
هذا المثال تمت كتابته في بيئة لينكس ،يمكن تغيير المسار بما يناسب نظام التشغيل ،مثلا في وندوز يمكن أن
يكون c:\directory\myfle.txt
بدلا من استخدام عبارة throws IOExceptionكان من الممكن عمل معالجة للخطاء وذلك بالطريقة التالية:
try {
File file = new File("/home/motaz/myfile.txt");
if (file.exists()) {
System.out.println("File exists");
}
else {
System.out.println("File does not exist");
file.createNewFile();
}
}
catch (Exception ex){
System.err.println("Unable to create file: " +
ex.toString());
}
}
وهي طريقة أفضل ﻹظهار المشكلة كما.catch يتم تحويل التنفيذ إلى جزءtry فإذا حدث أي خطأ بعد عبارة
. بدلا من ترك المترجم يكتب رسالة الخطأ مباشرة للمستخدم،يريدها المبرمج للمستخدم
:هذه هي طريقة حماية أي جزء من الكود والذي يمكن أن يكون عرضة للخطاء أثناء التشغيل
try{
// الكود المعرض لخطاء التشغيل
return (true);
}
catch (Exception e)
{
System.err.println("Error: " + e.getMessage());
return (false); // fail
}
}
نلحظ أننا يقمنا بتعريف يمدخلين لهذا اﻹجراء وهما aFileNameوهو من النوع النصي ليستقبل إسم الملف المراد
كتابته ،والخر textوهو من النوع النصي أيضاا والذي ييمثل المحتويات اليمراد كتابتها في الملف.
ثم نقوم بكتابة الكود التالي داخل هذا اﻹجراء:
;)"writer.write(text + "\n
;)(writer.close
return (true); // success
}
)catch (Exception e
{
;))(System.err.println("Error: " + e.getMessage
return (false); // fail
}
}
بالنسبة لتعريف الملف وتعريف طريقة الكتابة عليه يقمنا بكتابة هذين السطرين:
في العبارة اﻷولى يقمنا بتعريف الكائن fleمن نوع الفئة Fileوهو كائن للربط مع الملف الخارجي .وقد أعطيناه
إسم الملف في المدخلت .وفي العبارة الثانية يقمنا بتعريف الكائن writerمن النوع FileWriterالمتخصص في
الكتابة النصية كما سبق ذكره ،ويمدخلته هو الكائن fleالذي تم ربطه بالملف الفعلي في القرص.
بعد ذلك يقمنا بكتابة النص اليمرسل داخل الملف باستخدام الكائن writerبالطريقة التالية:
;)"writer.write(text + "\n
في النهاية قمنا بإغلق الملف باستخدام عبارة writer.closeوهي من اﻷهمية بمكان بحيث أنه يمنع برنامج آخر
بالكتابة على هذا الملف الذي لم يتم إغلقه ،وكذلك فإن الملف غير المغلق يمكن أن يتسبب في إهدار للموارد،
حيث أن نظام التشغيل يسمح بفتح عدد معين من الملفات في آن واحد ،فتكرار عملية فتح الملف دون أن يكون
هناك إغلق له يمكن أن يمنع فتح ملفات جديدة أثناء تشغيل البرنامج.
وييمكن تحديد المسار أو الدليل الذي ينريد كتابة الملف عليه كما فعلنا في المثال التالي لنداء هذا اﻹجراء .وقد يقمنا
بإضافة التاريخ والوقت الذي تمت فيه كتابة الملف:
وقد يقمنا بفحص قيمة المتغير resultلعرض رسالة يتفيد بأن العلمية نجحت ،أو فشلت في حالة أن قيمته .false
و العبارة الشرطية هي if
)if (result
معناها أن قيمة resultإذا كانت تحمل القيمة trueقم بتنفيذ العبارة التالية ،أما إذا لم تكن تحمل تلك القيمة
فقم بتنفيذ اﻹجراء بعد الكلمة else
لتنفيذ هذا البرنامج نحتاج ﻹضافة المكتبات التالية ،والتي تساعد أداة التطوير في إضافتها تلقائياا:
;import java.io.File
;import java.io.FileWriter
;import java.util.Date
بد ا
ل من حذف محتويات الملف في كل مرة ،يمكن اﻹضافة فقط في النهاية بما يعرف بمصطلح appendوهو
يعني اﻹضافة في نهاية الملف .لعمل ذلك نقوم بتغيير طريقة تهيئة الكائن writerوذلك بإضافة اليمدخل true
كالتالي:
فعند تشغيله أكثر من مرة ،نلحظ أن المحتويات القديمة موجودة وأن اﻹضافة تتم في النهاية.
}
)catch (Exception e
{
;))(System.err.println("Error: " + e.getMessage
return (false); // fail
}
}
نلحظ أننا استخدمنا سلسلة من النوع charوهو يقوم بتخزين رمز ،والنصوص هي مجموعة من الرموز.
لقراءة كل محتويات الملف ،لبد من قراءة جميع اﻷحرف ،في كل مرة نقوم بقراءة 10أحرف على اﻷكثر إلى أن
تنتهي محتويات الملف .استخدمنا العبارة التالية لقراءة جزء من الملف ثم نقوم باختبار هل وصل الملف إلى
نهايته أم ل:
بعد ذلك قمنا بتحويل سلسلة اﻷحرف إلى مقطع لسهولة التعامل معه وكتابته في الشاشة:
في معظم اﻷحوال فإن طول السلسة bufهو 10بايت ،لكن ربما قرأ البرنامج عدداا أقل من اﻷحرف في نهاية
الملف ،لذلك نقوم بنسخ الجزء الذي تمت قراءته فعلياا لذلك قمنا بتحديد المقطع المراد قرائته بواسطة اليمدخلت
numread ,0حتى ل تتم أحرف أو كلمات إضافية من القراءة السابقة ،ﻷننا استخدمنا المصفوفة bufعدة مرات
فكل مرة يكون فيه أحرف من قراءة سابقة.
نفرض أن الملف يحتوي على 25رمز اا ،فتكون القراءة كالتالي :في الدورة اﻷولى تتم قراءة 10رموز ،ثم في الدورة
الثانية 10رموز ثم 5رموز .هذه الرموز يتمثل أحرف و رمز السطر الجديد المعروف بالـ new line/line feedفي
وندوز يتم استخدام رمزين للدللة على نهاية السطر ،أما في نظام لينكس فيتم استخدام رمز واحد فقط وهو
.new lineقمنا بكتابة رمز السطر الجديد في المثال السابق )الكتابة في ملف نصي( وذلك باستخدام
\n
لهذا السبب استخدمنا printبدلا من printlnوذلك ﻷن النص المقروء من الملف يحتوي على رمز السطر الجديد
بعد نهاية كل سطر ،أما إذا استخدمنا printlnفسوف يتم اﻹنتقال إلى سطر جديد بعد كتابة كل 10أحرف
فتصبح اليجمل مقطعة كالتالي:
This file
has been w
ritten usi
ng Java
Fr
i Aug 28 0
9:20:47 EA
T 2015
ييمكن تحويل كود القراءة في هذا اﻹجراء بأن تتم قراءة محتويات الملف سطراا سطراا بدلا من قراءة عدد من
String line;
}
catch (Exception ex)
{
System.err.println("Error in readTextFile: " + ex.getMessage());
return (false); // fail
}
استعراض الملفات
ويمكن أن يحتوي هذا المسار على ملفات ومسارات،احيان اا نحتاج ﻷن نستعرض الملفات الموجودة في مسار معين
.فرعية أخرى
}
catch (Exception ex){
. أو نقلها إلى مسار آخر، مثل قراءة محتويتها،بعد الحصول على أسماء الملفات يمكن إدخالها في عمليات أخرى
.كذلك يمكن عمل برنامج ﻹدارة الملفات مثلا
;File source
;)source = new File(sourceFileName
;File target
;)target = new File(targetFileName
;FileInputStream input
;)input = new FileInputStream(source
;FileOutputStream output
;)output = new FileOutputStream(target
في هذه العبارات يقمنا بتعرف كائن sourceو targetمن نوع الفئة Fileالمسؤولة عن كتابة أو قراءة الملف من
القرص:
;File source
;)source = new File(sourceFileName
ثم في العبارات التي تليها قمنا بتعريف الكائنات inputو outputمن نوع FileInputStreamو
FileOutputStreamعلى التوالي ،وهي مسؤولة عن قراءة وكتابة مصفوفة من نوع بايت:
;FileInputStream input
;)input = new FileInputStream(source
;FileOutputStream output
;)output = new FileOutputStream(target
بعد ذلك قمنا بتعريف مصفوفة البايت بإسم packetحجمها كيلو بايت ،ثم أدخلناها في حلقة قراءة من المصدر
وكتابة في الملف المراد نسخة إلى نهاية القراءة من المصدر ،ونتعرف على نهاية القراءة عندما إرجاع القيمة -1
لعدد البايت التي تمت قرائتها:
حيث أن هذه العبارة سوف تقوم بكتابة كامل المصفوفة )كيلوبايت( في الملف المنسوخ ،فإذا كان حجم الملف هو
كيلوبايت ونصف الكيلو فإن الكتابة بتلك الطريقة سوف تكتب 2كيلو في الملف الهدف ،وسوف يحتوى الكيلو
الثاني على زيادة هي عبارة عن باقي محتويات القراءة اﻷولى .لذلك قمنا بكتابة الجزء المقروء فقط من
المصفوفة ،فلو تم قراءة 100بايت في أي دورة تتم كتابة 100بايت فقط ،وإذا تمت قراءة كيلو بايت كامل تتم
كتابة كيلوبايت:
;)output.write(bucket, 0, numread
واليمدخل ) (0يعني الكتابة من بداية المصفوفة ،و numreadهو المكان الذي سوف تتوقف الكتابة قبله ،أي
الموقع 1023في حال أن numreadبها القيمة ،1024و المصفوفة ذات الـ 1024بايت تبدأ في البايت 0وتنتهي
عن البايت .1023
output.close();
input.close();
و الناتج هو ملف منسوخ مماثل في،بهذه الطريقة يمكن نسخ أي نوع من الملفات بغض النظر عن محتوياتها
.المحتويات للملف اﻷصلي
:نقوم بنداء إجراء نسخ الملفات كالتالي
copyFiles("/home/motaz/fish.jpg", "/home/motaz/fishcopy.jpg");
output وinput وربط الملف مباشرة أثناء تهيئةsource, target يمكن الستغناء عن كائنات التعامل مع الملف
:ليصبح البرنامج مختصراا كالتالي
FileInputStream input;
input = new FileInputStream(sourceFileName);
FileOutputStream output;
output = new FileOutputStream(targetFileName);
// Reading
;))"System.out.println(myproperty.getProperty("Name
;))"System.out.println(myproperty.getProperty("Age
;))(System.out.println(myproperty.toString
نكتب أولا إسم القيمة مثل Nameثم قيمتها Mohammed Aliباستخدام الدالة setPropertyوينلحظ أن
هناك فرق في اﻹسم بين الحرف الكبير الصغير ،case sensitiveكذلك أننا يقمنا بوضع القيمة 30تحت اﻹسم
Ageثم قمنا بإعادة وضع القيمة ،32في هذه الحالة يتم تغيير قيمة Ageبالقيمة اﻷخيرة ول يتم تكرار اﻷسماء
وهذه ميزة مهمة حيث ل يتم وضع متغيرين بنفس اﻹسم لهما قيم مختلفة.
بعد ذلك قمنا بقراءة القيم باستخدام .getPropertyكذلك يمكن إضافة قيمة افتراضية في حال عدم وجود
ولعمل هذا نقوم باستخدام ملف من نوع،ينقص كائن الخصائص هذا التخزين في ملف حتى ل تضيع معلوماته
: بإضافة الكود التاليFileOutputStream اوFileWriter
// Writing
myproperty.setProperty("Name", "Mohammed Ali");
myproperty.setProperty("Age", "30");
myproperty.setProperty("Address", "Sudan,Khartoum");
// Reading
System.out.println(myproperty.getProperty("Name"));
System.out.println(myproperty.getProperty("Age"));
System.out.println(myproperty.getProperty("Address", "Sudan"));
في الغالب فإننا نحتاج فقط قراءة القيم الموجودة في ملف اﻹعدادات حيث أن الكتابة غالباا تتم خارجياا بواسطة
مباشرة في الملف باستخدامname=value حيث يقوم بكتابة القيم في شكل،المبرمج أو المسؤول عن النظام
وهذا إجراء قمنا بكتابته لقراءة أي قيمة من. ليقوم برنامج جافا بقراءة تلك القيم واستخدامها،أي محرر نصوص
:أي ملف
;int[] arr
;int []arr2
;][int arr3
بهذا نكون قد حجزنا خمس خانات في المصفوفة تبدأ من 0وتنتهي بـ ،4ويمكن وضع قيم فيها بالطريقة التالية:
وتوجد طريقة مختصرة لحلقة forبالنسبة للمصفوفات والسلسل عموماا في لغة جافا ،حيث يمكن تحويلها إلى
الطريقة التالية:
حيث تقوم الحلقة باسناد قيم المصفوفة بالتتالي للمتغير xلستخدامه لحقاا داخل الحلقة إلى أن تتنهي عناصرها.
ونوع المتغير أو العنصر الواحد في السلسلة هو مقطع ،Stringوتتم تهيئتها بالطريقة التالية:
;)(><nameList = new ArrayList
قديم اا في النسخة السادسة من الجافا كان لبد من كتابة نوع العنصر مرة أخرى كالتالي:
;)(>nameList = new ArrayList<String
لكن منذ جافا 7تم اختصار نوع العنصر بما ييسمى بعلمة الماسة <> Diamond
فنجد أن المترجم أعطى خطأ أمام التهيئة بواسطة >< وعند تحويلها إلى > <Stringيعتبرها صحيحة.
طريقة تحويل مصدر برنامج جافا إلى ينسخة أقدم من جافا يتم استخدامها احياناا حينما نريد تشغيل برنامج جافا
في آلة افتراضية قديمة في مخدم مثلا .حيث أن بعض المخدمات يصعب تحديثها إلى ينسخة جديدة من جافا.
عند تشغيل البرنامج لبد من وضع المؤشر في الجزء اﻷسفل من الشاشة حتى نتمكن من إدخال اﻷسماء بالطريقة
التالية:
;Date today
;)(today = new Date
هذه المرة في العبارة اﻷولى يقمنا بتعريف الكائن todayمن نوع الفئة .Dateلكن إلى الن ل ييمكننا استخدام
الكائن todayفلم يتم حجز موقع له في الذاكرة.
أما في العبارة الثانية فقد يقمنا بحجز موقع له في الذاكرة بإستخدام الكلمة newثم تهيئة اللكائن بإستخدام
اﻹجراء
;)(Date
والذي بدوره يقوم بقراءة التاريخ والوقت الحالي ﻹسناده للكائن الجديد .todayوهذا اﻹجراء ييسمى في
البرمجة الكائنية .constructor
في هذا المثال Dateهي عبارة عن فئة لكائن أو يتسمى classفي البرمجة الكائنية .و المتغير todayييسمى كائن
objectأو instanceوييمكن تعريف أكثر من كائن instanceمن نفس الفئة لستخدامها .وتعريف كائن جديد من
فئة ما وتهيئتها يتسمى object instantiationفي البرمجة الكائنية.
بعد الفراغ من استخدام الكائن يمكننا تحريره من الذاكرة وذلك باستخدام الدالة التالية:
;today = null
توجد في لغة جافا ما ييعرف بال garbage collectorوهي آلية لحذف الكائنات الغير مستخدمة من الذاكرة
تلقائي اا عندما ينتهي تنفيذ اﻹجراء .يتم فقط حذف الكائنات المعرفة في نطاق هذا اﻹجراء .في معظم اﻷحيان ل
نحتاج لستخدام هذه العبارة ،فإذا تم اﻹنتهاء من استخدام المتغير الذي يؤشر لهذا الكائن يتم تحريره تلقائياا.
مفهوم – غير مستخدم -يعني أنه ل يوجد مؤشر له من المتغيرات ،حيث يمكن أن يكون لكائن ما عدد من
المؤشرات تؤشر له ،فعندما تنتهي جميع هذه المؤشرات ويصبح عدد المتغيرات التي تؤشر لهذا الكائن في الذاكرة
صفراا يقوم الـ garbage collectorبحذفه من الذاكرة بعد مدة معينة .أما لغات البرمجة اﻷخرى مثل سي
نهاية المتغير يكون بنهاية تنفيذ الحيز الموجود فيه وهو المحاط بالقوسين }{
نجد أن المتغير yourNameمعرف داخل اﻹجراء mainلذلك ل ينتهي إل بانتهاء هذا اﻹجراء ،أي عند السطر
رقم .10
أما المتغير myNameوالمعرف في نطاق أضيق ،فينتهي عند السطر رقم ،7فإذا أردنا أن نجعله ذو عمر أطول
يمكن تعريفه خارج هذا النطاق الضيق:
بهذه الطريقة يصبح عمر المتغير myNameمرتبط بنهاية اﻹجراء ،mainونلحظ أننا قمنا فقط بنقل التعريف
إلى الخارج ،لكن التهيئة فمازالت داخل ذلك الحيز ،لكن هذا لم يؤثر على قيمته أو نطاق تعريفه.
يمكن تهيئة كائن جديد بواسطة إسناد مؤشر كائن قديم له ،في هذه الحالة يكون كل المتغيرين يؤشران لنفس
;Date today
;Date today2
;)(today = new Date
;today2 = today
;today = null
;)"System.out.print("Today is: " + today2.toString() + "\n
نلحظ أننا لم نقم بتهيئة المتغير today2لكن بدلا من ذلك جعلناه يؤشر لنفس الكائن todayالذي تمت تهيئته
من قبل.
بعد ذلك يقمنا بتحرير المتغير ،todayإل أن ذلك لم يؤثر على الكائن ،حيث أن الكائن مايزال مرتبط بالمتغير
.today2ول تقوم آلية garage collectorبتحرير الكائن من الذاكرة إل عندما تصبح عدد المتغيرات التي تؤشر
له صفراا .فإذا يقمنا بتحرير المتغير today2أيضاا تحدث مشكلة عند تنفيذ السطر اﻷخير ،وذلك ﻷن الكائن تم
تحريره من الذاكرة ومحاولة الوصول إليه بالقراءة أو الكتابة ينتج عنها خطأ.
ولمعرفة ماهو الخطأ الذي ينتج يقمنا بإحاطة الكود بعبارة try catchكما في المثال التالي:
{ try
;Date today
;Date today2
;)(today = new Date
;today2 = today
;today = null
;today2 = null
;)"System.out.print("Today is: " + today2.toString() + "\n
{ )} catch (Exception e
;)"System.out.print("Error: " + e.toString() + "\n
}
والخطأ الذي تحصلنا عليه هو:
java.lang.NullPointerException
ملحظة:
في لغة جافا ياصطلح على تسمية الفئات classesبطريقة أن يكون الحرف اﻷول كبير capitalمثل Date,
,Stringحتى الفئات التي يقوم المبرمج بكتابتها .أما الكائنات objects/instancesفتبدأ بحرف صغير وذلك
للتفرقة بين الفئة والكائن ،مثل .today, today2, myName
لعمل هذا البرنامج نفتح مشروع جديد بواسطة .Java/Java Applicationنسمي هذا المشروع openfle
بعد ذلك نكتب هذا الكود في اﻹجراء mainفي ملف البرنامج الرئيسي Openfle.javaﻹظهار الفورم فور
تشغيل البرنامج:
String line;
textArea.setText("");
fstream.close();
return (true); // success
}
catch (Exception e)
{
textArea.append("Error in readTextFile: " + e.getMessage() + "\n");
return (false); // fail
}
: في الزر نكتب الكود التاليActionPerformed وفي الحدث
هل قام المستخدم باختيار: ويقوم بإرجاع النتيجة.ثم قمنا بإظهاره ليختار المستخدم الملف في السطر التالي
:ملف أم ضغط إلغاء
في هذا المثال سوف نقوم بإضافة فئة classجديدة يندخل لها جملة نصية ﻹرجاع الكلمة اﻷولى واﻷخيرة من
الجملة.
ثم يقمنا بإدراج Text Fieldو Buttonو Text Areaبهذا الشكل في الفورم الرئيسي:
ول ننسى تعريف الفورم وتهيئته ﻹظهاره مع تشغيل البرنامج في اﻹجراء الرئيسي في الملف :Newclass.java
*/
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
;package newclass
*/
*
}
وفي داخل كود الفئة -بين القوسين المعكوفين }{ -قمنا بإضافة متغير مقطعي اسميناه mySentenceلنحفظ
فيه الجملة التي يتم إرسالها لتكون محتفظة بقيمة الجملة طوال فترة حياة الكائن.
ثم أضفنا اﻹجراء الذي ييستخدم في تهيئة الكائن ،ولبد أن يكون اسمه مطابق ﻹسم الفئة:
;String mySentence
نلحظ أنه في هذا اﻹجراء تم إسناد قيمة اليمدخل atextإلى المتغير mySentenceاليمعرف على نطاق الكائن.
حيث أن المتغير atextنطاقه فقط اﻹجراء Sentenceوعند اﻹنتهاء من نداء هذا اﻹجراء يصبح غير معروف.
لذلك إحتفظنا بالجملة اليمدخلة في متغير في نطاق أعلى لتكون حياته أطول ،حيث ييمكن استخدامه مادام الكائن
لم يتم حذفه من الذاكرة.
بعد ذلك يقمنا بإضافة إجراء جديد في نفس فئة الكائن اسمه getFirstوهو يقوم بإرجاع الكلمة اﻷولى من
الجملة:
;)return (first
}
نلحظ اننا استخدمنا اﻹجراء indexOfفي المتغير أو الكائن المقطعي mySentenceويقمنا بإرسال مقطع
يحتوي على مسافة .وهذا اﻹجراء أو الدالة مفترض به في هذه الحالة أن يقوم بإرجاع موقع أول مسافة في
الجملة ،وبهذه الطريقة نعرف الكلمة اﻷولى ،حيث أنها تقع بين الحرف اﻷول وأول مسافة.
أما إذا لم تكن يهناك مسافة موجودة في الجملة فتكون نتيجة الدالة indexOfيساوي 1-وهذا يعني أن الجملة
تتكون من كلمة واحدة فقط ،في هذه الحالة نقوم بإرجاع الجملة كاملة )الجملة = كلمة واحدة(.
وهو يقوم بإرجاع آخر كلمة فيgetLast هوSentence الدالة أو اﻹجراء الخر الذي يقمنا بإضافته في الفئة
:الجملة
if (lastSpaceIndex == 1){
last = mySentence;
}
else {
last = mySentence.substring(lastSpaceIndex + 1, mySentence.length());
}
return (last);
}
( إلىlastIndexOf ) ويختلف في أنه يقوم بالنسخة من آخر مسافة موجودة في الجملة،وهو مشابه للدالة اﻷخرى
mySentence.length نهاية الجملة
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package newclass;
/*
*
* @author motaz
*/
public class Sentence {
String mySentence;
super();
mySentence = atext;
}
String first;
int firstSpaceIndex;
if (firstSpaceIndex == 1){
first = mySentence;
}
else {
first = mySentence.substring(0, firstSpaceIndex);
}
return (first);
}
String last;
int lastSpaceIndex;
lastSpaceIndex = mySentence.lastIndexOf(" ");
if (lastSpaceIndex == 1){
last = mySentence;
}
else {
last = mySentence.substring(lastSpaceIndex + 1, mySentence.length());
}
return (last);
}
}
واستقبلنا، قمنا بتعريف وتهيئة ثم استخدام هذا الكائنMainForm.java في كود الفورم الرئيسي للبرنامج
: وهذا هو الكود الذي يتم تنفيذه عند الضغط على الزر.Text Field الجملة في مربع النص
الموجود فيgetText بواسطة اﻹجراءjTextField1 واليجملة اليمدخلة أثناء التهيئة تحصلنا عليها من مربع النص
.هذا الكائن
لكن ييمكن استخدام إجراءات في فئات دون تعريف كائنات منها بتحويلها إلى إجراءات ساكنة
.static methods
وهذا مثال لطريقة تعريف متغيرات وإجراءات ساكنة في لغة جافا:
;MyClass.x = 10
;))(System.out.println(MyClass.getX
وبهذه الطريقة ييمكن أن يكون المتغير xمشترك اا في القيمة بين الكائنات المختلفة .لكن يجب الحذر والتقليل من
استخدام متغيرات مشتركة Global variablesحيث يصعب تتبع قيمتها ويصعب معرفة القيمة الحالية لها عند
مراجعة الكود .واﻷفضل من ذلك هو استخدام إجراءات ثابتة يتم إرسال المتغيرات لها في شكل يمدخلت كما في
المثال التالي والذي هو إجراء لتحويل اﻷحرف اﻷولى من الكلمات في جملة باللغة اللتينية إلى حرف كبير
.Capital letterوقد يقمنا بتسميتها هذه الفئة :Cap
{ public class Cap
;)(input = input.toLowerCase
;)(char[] chars = input.toCharArray
;)]chars[i] = Character.toUpperCase(chars[i
}
}
;)String result = new String(chars
ييمكن اﻹستفادة من اﻹجراءات الساكنة لكتابة مكتبة إجراءات مساععدة عامة ييمكن استخدامها في عدد من
البرامج .مثل إجراء لكتابة اﻷخطاء التي تحدث في ملف نصي والمعروف بالـ .log fleأو تحويل التاريخ إلى
شكل معين ييستخدم في نوعية معينة من البرامج ،او غيرها من اﻹجراءات التي يتستخدم بكثرة لتوفير وقت
للمبرمج.
يمكن الحصول على المكتبة الخاصة بها وبرنامج ﻹنشاء قواعد بيانات SQLiteوالتعامل مع بياناتها من هذا
الرابط:
http://sqlite.org/download.html
ﻹستخدامها في نظام وندوز نبحث عن ملف يبدأ باﻹسم ،sqlite-shellأما في نظام لينكس يمكننا تثبيت تلك
المكتبة وأدواتها بواسطة مثبت الحزم .فقط نبحث عن الحزمة sqlite3
بعد ذلك نقوم باﻹنتقال إلى شاشة الطرفية terminalلتشغيل البرنامج وهو من نوع برامج سطر اﻷوامر ،ثم
نختار دليل معين ﻹنشاء قاعدة البيانات ثم نكتب هذا اﻷمر:
sqlite3 library.db
SQLite version 3.7.9 20111101 00:52:41
Enter ".help" for instructions
";" Enter SQL statements terminated with a
>sqlite
بهذه الطريقة نكون قد أنشأنا قاعدة بيانات في ملف إسمه library.db
والن مازلنا نستخدم هذه اﻷداة للتعامل مع قاعدة البيانات .ثم يقمنا بإضافة جدول جديد اسمه booksبهذه
الطريقة:
sqlitejdbc
https://bitbucket.org/xerial/sqlite-jdbc/downloads
sqlitejdbc3.8.11.2.jar
وهذه المكتبة هي يكل مانحتاجه للتعامل مع قاعدة البيانات SQLiteفي برامج جافا ،فهي لتحتاج لمخدم لتثبيته
حتى تعمل قاعدة البيانات كما يقلنا سابقاا.
قمنا بفتح مشروع جديد أسميناه sqlitebrowserلعرض قاعدة البيانات Libraryالتي يقمنا بإنشائها سابقاا.
في شاشة المشروع يوجد فرع أسمه Librariesنقف عليه ثم نختار بالزر اليمين للماوس Add JAR/Folderثم
نختار الملف sqlite-jdbc-3.7.2.jarالذي يقمنا بتحميله من اﻹنترنت سابقاا.
قمنا بتعريف الكائن dbConnectionمن نوع Connectionداخل كود فئة الكائن SqliteClientلتعريف مسار
قاعدة البيانات واﻹتصال بها للستخدام لحقاا في باقي إجراءات الكائن .SqliteClient
ثم قمنا بكتابة الكود ﻹستقبال إسم قاعدة البيانات ثم اﻹتصال بها في اﻹجراء الرئيسي constructorلهذا الكائن:
// Constructor
{ )public SqliteClient (String aDatabaseName
;)(super
{ try
;)"Class.forName("org.sqlite.JDBC
(dbConnection = DriverManager.getConnection
;)"jdbc:sqlite:" + aDatabaseName
}
{)catch (Exception e
;))(System.out.println("Error while connecting: " + e.toString
}
}
نلحظ أننا يقمنا بحماية الكود بواسطة try .. catchوذلك ﻷنه من المتوقع أن تحدث مشكلة أثناء التشغيل ،مثلا
أن تكون قاعدة البيانات اليمدخلة غير موجودة ،أو أن مكتبة SQLiteغير موجودة.
اﻹجراء اﻷول) (Class.forNameيقوم بتحميل مكتبة SQLiteلنتمكن من نداء اﻹجراءات الخاصة بهذه القاعدة
في السطر التالي قمنا بتهيئة الكائن dbConnectionوإعطائه إسم الملف التي تم إرساله عند تهيئة الكائن
SqliteClient
بعد ذلك يقمنا بإضافة اﻹجراء showTableإلى فئة الكائن SqliteClientلعرض محتويات الجدول المرسل لهذا
اﻹجراء في مربع النص:
{ try
;)(myQuery = dbConnection.createStatement
;)myRecords = myQuery.executeQuery("SELECT * from " + aTable
// Read records
))(while (myRecords.next
{
" " textArea.append(myRecords.getString(1) +
;)"+ myRecords.getString(2) + "\n
}
{)catch (Exception e
;)"textArea.append("Error while reading table: " + e.toString() + "\n
;)return (false
}
}
قمنا في هذا اﻹجراء بتعريف كائن من نوع Statementأسميناه myQueryيسمح لنا بكتابة queryبلغة SQL
على
قاعدة البيانات.
وعند إضافة المكتبة المحتوية على الكائن Statementلبد من أن ننتبه ﻹختيار المكتبة java.sql.Statement
ول نختار الخيار اﻷول الذي يظهر عند اﻹضافة التلقائية java.beans.Statementالتي تتسبب في أخطاء أثناء
الترجمة.
;)(myQuery = dbConnection.createStatement
ثم قمنا بنداء اﻹجراء executeQueryفي الكائن myQueryوأعطيناه مقطع SQLوالذي به أمر عرض
محتويات الجدول .هذا اﻹجراء ييرجع كائن جديد من هو عبارة عن حزمة البيانات .ResultSetاستقبلناه في
الكائن myRecordsوالذي هو من نوع فئة الكائن ResultSetوالذي يقمنا بتعريفه في بداية اﻹجراء دون تهيئته.
بعد هذه اﻹجراءات يقمنا بالمرور على كل السجلت في هذا الجدول وعرضنا بعض الحقول في مربع النص الذي
تم إرساله يكمدخل للجراء :showTable
داخل الحلقة قرأنا الحقل اﻷول والثاني من الجدول اليمرسل بواسطة الدالة getStringوأعطيناها رقم الحقل
Field/Columnوهي يترجع البيانات في شكل مقطع ،وييمكن استخدامها حتى مع اﻷنواع اﻷخرى مثل اﻷعداد
الصحيحة مثلا أو التاريخ ،فكلها ييمكن تمثيلها في شكل مقاطع.
في اﻹجراء التابع للزر Openفي الفورم الرئيسي MainFormقمنا بكتابة هذا الكود لعرض سجلت الجدول
booksالموجود في قاعدة البيانات library.db
jTextArea1.setText("");
sql.showTable("books", jTextArea1);
}
ثم تهيئتها بإرسال إسمSqliteClient من نوع الفئة التي قمنا بإنشائهاsql في السطر اﻷول قمنا بتعريف الكائن
. وهذا المثال لبرنامج في بيئة لينكس.ملف قاعدة البيانات
فيshowTable ثم في السطر الثالث إستدعينا اﻹجراء.ثم في السطر الثاني قمنا بحذف محتويات مربع النص
: وكانت النتيجة كالتاليbooks هذا الكائن لعرض محتويات الجدول
أولا نقوم بإضافة إجراء جديد نسميه مثلاtables ﻹضافة كتاب جديد في قاعدة البيانات في الجدول
وهذا هو الكود الذي كتبناه ﻹضافة كتاب.showTable بعد اﻹجراءSqliteClient في فئة الكائنinsertBook
:جديد
try {
PreparedStatement insertRecord = dbConnection.prepareStatement(
"insert into books (BookID, BookName) values (?, ?)");
insertRecord.setInt(1, bookID);
في العبارة اﻷولى لهذا اﻹجراء قمنا بتعريف الكائن insertRecordمن نوع الفئة PreparedStatementوهي
يتستخدم لتنفيذ إجراء على البيانات DMLمثل إضافة سجل ،حذف سجل أو تعديل .ونلحظ أننا وضعنا علمة
إستفهام في مكان القيم التي ينريد إضافتها في الجزء .valuesوهذه يتسمى مدخلت .parametersسوف يتم
تعبئتها لحقاا.
في العبارة الثانية وضعنا رقم الكتاب في اليمدخل اﻷول بواسطة ،setIntثم في العبارة الثالثة وضعنا إسم الكتاب
في اليمدخل الثاني بواسطة ،setStringثم قمنا بتنفيذ هذا اﻹجراء بواسطة executeوالتي تقوم بإرسال طلب
اﻹضافة هذا إلى مكتبة SQLiteوالتي بدورها تقوم بتنفيذه في ملف قاعدة البيانات library.db
بعد ذلك نضيف فورم ثاني من نوع JFrame Formونسميه AddFormنضع فيه المكونات jLabelو jTextField
بالشكل التالي:
مؤخرا.
المتغير bookIDمن نوع العدد الصحيح. في السطر الثاني قمنا بتعريف
getTextفي شكل مقطع .Stringونحن نريده أن الحقل jTextField1ييرجع محتوياته بواسطة اﻹجراء
يستقبل رقم
الكتاب وهو من النوع الصحيح والمقطع يمكن أن يحتوي على عدد صحيح .فقمنا بتحويل المقطع إلى عدد
صحيح
بعد حذف أي مسافة غير مرغوب فيها -إن وجدت -بواسطة الدالة trimالموجودة في الكائن ،Stringوذلك ﻷن
أخرى أو مسافة فإن التحويل إلى رقم بواسطة اﻹجراء parseIntسوف
العدد إذا كان يحتوي على حروف أو رموز
ينتج عنها خطأ .والدالة trimتقوم بإرجاع مقطع محذوفة فيه المسافة من بداية ونهاية النص ،لكنها لتؤثر على
الكائن الذي تم تنفيذها فيه .مثلا الكائن jTextField1ليتم حذف المسافة منه .لتوضيح ذلك انظر المثال التالي:
;)(myText = aText.trim
الكائن aTextليتثأر بالدالة trimأما الكائن myTextفتيم تخزين مقطع فيه من المقطع aTextبدون مسافة.
insertBookفي الكائن queryوأعطيناه رقم الكتاب في المدخل اﻷول في السطر الرابع قمنا بإستدعاء اﻹجراء
ثم
setVisibleوأعطيناها القيمة اسم الكتاب في المدخل الثاني .ثم قمنا بإغلق الفورم في السطر اﻷخير بواسطة
.false
ولبد أن نضعه في هذا الدليل داخل الدليل الذي نضع فيه البرنامج
• library.dbوهو ملف قاعدة البيانات .وكان من اﻷفضل جعل مسار قاعدة البيانات خارج كود البرنامج ،مثلا
portableو ليعتمد على ثوابت في نظام معين .وهي بهذه الطريقة يكون البرنامج أكثر حرية في النقل
طريقة جيدة
في تطوير البرامج تزيد من إمكانية إستخدامه ،خصوصا عند إختيار لغة برمجة متعددة المنصات مثل جافا.
import java.io.File;
try {
File file = new File(filename);
file.createNewFile();
return true;
}
catch (Exception ex){
System.out.println("Unable to create file: " + ex.toString());
return false;
}
;return fileNames
}
}
ثم قمنا بتعريف وتهيئة ثم استخدام كائن من هذه الفئة في البرنامج الرئيسي كالتالي:
{ ))"if (! manager.checkExistence("/home/motaz/testing/first.txt
;)"manager.createFile("/home/motaz/testing/first.txt
}
;)"String files[] = manager.listFiles("/home/motaz/testing
نلحظ أن هذه الفئة عامة في التعامل مع الملفات ،حيث أن أي نوع ملف يمكن أن نتأكد من وجوده أو من عدم
وجوده ،كذلك إنشاءه وحذفه واستعراض أسماء ملفات في دليل معين ايضاا هي ميزة مشتركة بين أنواع الملفات
المختلفة ،حيث تشترك فيها كل أنواع الملفات سوااء كانت نصية ،أو ملفات صوتية أو صور أو فيديو أو حتى
ملفات تنفيذية .هذا ما ينسمية بالتجريد بأن تكون هذه الفئة عامة الستخدام وغير مخصصة لنوع معين من
الملفات ،فإذا قمنا بإدخال إجراء مثلا لقراءة ملف نصي داخل نفس الفئة فنكون قد كسرنا التجرد الذي يتمثله هذه
الفئة ،حيث ل يمكن استعراض ملف صورة مثلا بهذه اﻹجراء الجديد ،فاصبح يهناك إستثناءات في اجراءات هذه
try {
try {
ونلحظ أنه يمكننا نداء إجراءات الفئة اﻷساسية،في اﻹجراء الرئيسي قمنا بإنشاء كائن من الفئة الجديدة
: باﻹضافة ﻹجراءات الفئة الجديدةFileManager
if (! manager.checkExistence("/home/motaz/testing/first.txt")) {
manager.createFile("/home/motaz/testing/first.txt");
}
String files[] = manager.listFiles("/home/motaz/testing");
// List files
for (String filename: files){
System.out.println(filename);
}
manager.writeIntoTextFile("/home/motaz/testing/second.txt",
"This is a test file\n written using inheritance\n");
manager.readTextFile("/home/motaz/testing/second.txt");
}
لكن عملنا إضافات خاصة في فئتنا الجديدةFileManager بهذه الطريقة لم ينعدل على الفئة
يمكن كذلك عمل فئات متخصصة في أي نوعية أخرى من. المتخصصة في الملفات النصيةTextFileManager
.FileManager الملفات بعد الوراثة من الفئة الرئيسة
حيث يكون،نكون كذلك قد حققنا إعادة استخدام الكود بدلا من تكراره كل مرة مع الفئات المتخصصة الجديدة
. و كل هذا ييعتبر من الطرق المثلى لكتابة البرامج.هناك دائماا إجراءات مشتركة
لكن قمنا بتغير هذا التعريف لنستخدم الوراثة التي ذكرناها سابقاا ،وذلك بدلا من كتابة فئة كائن جديد من الصفر
نستخدم فئة لديها خصائص مشابهة ثم نزيد فيها .وفئة هذا الكائن اسمها .TimerTaskنقوم بوراثته بهذه
الطريقة:
ثم نقوم بتعريف كائن myLabelبداخله حتى نقوم بعرض التاريخ والوقت فيه ،ثم قمنا بكتابة إجراء التهيئة:
;JLabel myLabel
وفي هذا اﻹجراء نستقبل الكائن alabelثم نقوم بحفظ نسخة منه في الكائن .myLabel
بعد ذلك نقوم بكتابة اﻹجراء الذي سوف يتم إستدعائه كل فترة وأسمه runبهذه الطريقة:
@Override
{ )(public void run
;)(Date today = new Date
;))(myLabel.setText(today.toString
}
ويمكن إضافة تعريف هذا اﻹجراء تلقائياا بواسطة implement all abstract methodsوالتي تظهر في سطر
تعريف الكائن MyTimerبالطريقة التالية:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package timer;
import java.util.Date;
import java.util.TimerTask;
import javax.swing.JLabel;
/*
*
* @author motaz
*/
public class MyTimer extends TimerTask{
JLabel myLabel;
public MyTimer(JLabel alabel){
super();
myLabel = alabel;
}
@Override
public void run() {
Date today = new Date();
myLabel.setText(today.toString());
: ونزيد حجم الخط فيه ليكون بالشكل التاليMainForm في الفورم الرئيسيjLabel نضع
{ )(public MainForm
;)(initComponents
;java.util.Timer generalTimer = null
قمنا بتعريف الكائن generalTimerمن النوع .Timerوهذا الكائن لديه خاصية تكرار الحدث بفترة زمنية
محددة.
ثم قمنا بتعريف الكائن timerObjمن الفئة MyTimerوالتي قمنا بكتابتها ﻹظهار التاريخ والوقت.
ثم قمنا بتهيئة الكائن .generalTimerوفي السطر اﻷخير قمنا بتشغيل اليمؤقت sheduleوأرسلنا له الكائن
timerObjليقوم بنتفيذ اﻹجراء runكل فترة معينة .والرقم اﻷول 2000هو بداية التشغيل أول مرة ،وهو بالملي
ثانية ،أي يقوم باﻹنتظار ثانيتين ثم التشغيل أول مرة.
الرقم الثاني 1000هو التكرار بالملي ثانية أيضاا .حيث يقوم بإظهار التاريخ والوقت كل ثانية.
بعد ذلك نقوم بفك الملف في مكان معروف ،ثم نقوم بإضافة مخدم جديد عن طريق الزر Add Serverثم نختار
رقم نسخة Tomcatالتي قمنا بتثبيتها ثم يندخل الدليل الذي توجد فيه كما في هذا المثال:
ثم نقوم بإدخال إسم المستخدم والذي سوف نستخدمه لحقاا لرفع البرامج وإدارة مخدم الويب.
أما في نظام لينكس فيمكن تثبيته عن طريق مدير الحزم ،في نظام اوبونتو أو انظمة ديبيان عموماا نكتب:
sudo apt-get install tomcat7 tomcat7-admin
ويمكن استبدالها بـ tomcat8أو tomcat9حسب إصدارة لينكس المستخدمة.
كذلك يمكن تثبيت ينسخة تعمل مع جميع أنظمة لينكس بتحميلها من موقع tomcatواختيار الملف الذي ينتهي
باﻹمتداد zip.
بعد ذلك نبحث عن الملف tomcat-users.xmlفي دليل اﻹعدادات حسب نظام التشغيل ،وحسب نسخة الـ
tomcatمثلا في بيئة لينكس يكون في هذا المسار:
/etc/tomcat7/tomcatusers.xml
:نقوم بإضافة هذا السطر لمستخدم جديد أو تعديل مستخدم موجود ﻹعطائه الصلحيات الكافية
<!DOCTYPE html>
<!
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF8">
<meta name="viewport" content="width=devicewidth, initialscale=1.0">
</head>
<body>
<div>TODO write content</div>
</body>
</html>
</html>
ويظهر فيه رقم المنفذ 8084والمنفذ اﻹفتراضي لمخدم الـ tomcatهو 8080لكن اﻷخير ييستخدم في حالة
التثبيت النهائي للبرنامج لستخدامه من قبل مستخدمي النظام ،أما المنفذ اﻷول فييستخدم مع NetBeans
لتطوير برامج الويب ،ويمكن أن يحتوي الكمبيوتر على أكثر من نسخة tomcatيعملن في نفس الوقت ،لكن كل
واحد لديه منفذ مختلف.
نقوم بإغلق المتصفح لنرجع للبرنامج لنضيف فيه محتوي تفاعلي ،حيث أن الصفحة السابقة كانت صفحة ثابتة
staticأو أنها تستخدم تقنية مختلفة وهي .HTML
في شجرة المشروع وفي الفرع Source Packagesنقوم بإضافة Servletعن طريق الزر اليمين للماوس ثم
.Newثم نقوم بتسميته Timerكما في الشكل التالي:
وذلك بإعتبار أنه سوف يتم إدخال إسم المستخدم في العنوان كالتالي:
http://localhost:8084/firstweb/time?name=Mohammed
فتكون النتيجة كالتالي في المتصفح:
هذه المرة نستخدم ينسخة tomcatالمعدة للتثبيت النهائي للنظام والتي تكلمنا عنها سابقاا والتي تستخدم المنفذ
8080
لنحتاج لنسخ الملف يدوياا إلى الدليل webappsبل نستخدم مدير برامج الويب في مخدم Tomcatعن طريق
المتصفح ،حيث نكتب العنوان التالي:
http://localhost:8080
ثم نضغط رابط Manager Webappونقوم بإدخال إسم الدخول الذي اضفناه سابقاا لتظهر لنا الشاشة التالية في
المتصفح:
<%
Document : first
Created on : May 27, 2016, 12:10:27 PM
Author : motaz
>%
ﻹضافة كود جافا لها نقوم بكتابة الكود بين علمتي،HTML أي فقط،وهي عبارة عن صفحة ثابتة
<% %>
:كالتالي
<%
Document : first
Created on : May 27, 2016, 12:10:27 PM
Author : motaz
%>
يتم استخدام ملفات JSPفي حال أن كود الـ HTMLاكثر من كود جافا ،ويتم استخدام تقنية Servletفي حال أن
كود جافا أكثر من الـ .HTMLاو بمعني آخر يتم استخدام Servletفي حال أن كود جافا أكثر كود العرض
.presentation
تتميز ايضاا ملفات JSPعلى أنها يتم وضعها في المخدم كما هي source codeويمكن تعديلها بعد تثبيتها في
المخدم ،أي يمكن الوصول إليها داخل دليل tomcat/webappsفنجدها مكتوبة كمصدر برنامج يمكن قراءته
وتعديله ،بخلف الـ Servletوالتي نجدها في المخدم في شكل ملفات class byte codeل يمكن قراءتها
وتعديلها.
في الجانب العملي يتم استخدام التقنيتين في معظم برامج الويب المكتوبة بلغة جافا ،فيتم استقبال المستخدم
بواسطة ملف JSPالذي يمثل واجهة المستخدم الموجود فيها الـ HTMLو الـ Java scriptوالـ CCSوكود الجافا ،
وعندما يقوم بمليء الفورم مثلا يتم استقبال هذه المدخلت ومعالجتها بواسطة .Servlet
لتوضيح ذلك نقوم بإضافة هذا الكود في الملف frst.jsp
><html
><head
>"<meta httpequiv="ContentType" content="text/html; charset=UTF8
><title>JSP Page</title
></head
><body
><h1>Hello World!</h1
<%
;int x = 10
;)out.println("X = " + x
>%
>"<form action="Timer
Please enter your name
><input type="text" name="username" /
><br/
><input type="submit" /
></form
></body
></html
ثم عند عرض الـ JSPتظهر شاشة اﻹدخال ،وعند كتابة اﻹسم وضغط زر Submit Queryيتم نداء الـ Servlet
كالتالي:
.1عزل قاعدة البيانات ومخدمها عن اﻷجهزة العميلة ،وهذا ييقلل نقاط اﻹتصال على قاعدة البيانات .فإذا
ل ،فبد ا
ل من أن يتم عمل مائة نقطة إتصال مباشر مع قاعدة البيانات من كانت مؤسسة بها مائة عميل مث ا
أجهزة العملء ،يتم تجميع تلك اﻹتصالت في مخدم وسيط واحد أو إثنين وبدورها تقوم تلك اﻷجهزة
الوسيطة بالتعامل مع قاعدة البيانات.
.2لنحتاج لتثبيت مكتبات للوصول لقاعدة البيانات في أجهزة العملء ،فقط يكفي تثبيت مكتبة التعامل مع
قاعدة البيانات في اﻷجهزة الوسيطة .فإذا تم تغيير تلك المكتبة أو حتى إذا تم تغيير محرك قاعدة
البيانات نفسها يتم عمل هذا التغيير في البرامج الوسيطة فقط.
.3زيادة تأمين وسرية قاعدة البيانات .حيث قمنا بعزل العميل عن قاعدة البيانات .فييمكن أن يتم حصر
سماحية الوصول إلى قاعدة البيانات عن اﻷجهزة الوسيطة فقط.
.4وسيلة إتصال ومخاطبة برمجية بين المؤسسات المختلفة :فل يمكن لبنك مثلا أن يقوم بالسماح لبنك آخر
أو أ مؤسسة أخرى للدخول على قاعدة بياناته لتنفيذ عمليات معينة ،إنما يتم عمل خدمات ويب محصورة
في هذه الخدمات التي يطلبها البنك الخر وإعطاءه صلحية لندائها.
.5وسيلة إتصال بين اﻷنظمة المختلفة في المؤسسة الواحدة .حيث ييمكن لمؤسسة أن يكون لديها أكثر من
نظام من جهات مختلفة ،ولتكامل تلك اﻷنظمة مع بعضها ييمكن أن يوفر كل نظام خدمات ويب تسمح
للنظمة اﻷخرى اﻹستفادة منه .فمثلا إذا كان يهناك نظام ﻹرسال رسائل نصية فبدلا من إعطاء البرامج
اﻷخرى صلحية على قاعدة البيانات ﻹرسال تلك الرسائل ييفضل أن يكون لديه خدمات ويب ﻹرسال
وإستقبال الرسائل الموجهة إلى البرامج اﻷخرى.
.6التقليل من التحديثات المستمرة في برامج العملء .ففي أغلب اﻷحيان يكون التحديث واﻹضافات في
النظام تحدث في قاعدة البيانات والطبقة الوسيطة ولتتأثر البرامج الطرفية في أجهزة العملء بهذا
التغيير ،فنقلل بذلك تكلفة صيانة ومتابعة الينسخ عند المستخدمين.
نقوم بإنشاء برنامج جديد من نوع Java Web/Web Applicationونسميه logfleثم نختار tomcatكمخدم
ويب له:
. فنقوم بإختيار موافقة،METRO بعدها يتم التنبيه على أنه سوف يتم إضافة مكتبة
:Mylog.java يتم إضافة الكود التلقائي التالي في الملف
*/
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package Log;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;
/**
*
* @author motaz
*/
@WebService(serviceName = "Mylog")
public class Mylog {
/**
* This is a sample web service operation
*/
@WebService(serviceName = "Mylog")
public class Mylog {
فنضيف إجراء،Mylog عند فتحها نجدWeb Services ونجد أيضاا أنه تم إضافة فرع جديد في المشروع إسمه
Add Operation جديد فيه بواسطة
: insertLog نجد أنه تم إضافة اﻹجراءMylog.java وإذا رجعنا مرة إخرى للملف
@WebService(serviceName = "Mylog")
public class Mylog {
/**
* This is a sample web service operation
*/
@WebMethod(operationName = "hello")
public String hello(@WebParam(name = "name") String txt) {
return "Hello " + txt + " !";
}
/**
* Web service operation
*/
@WebMethod(operationName = "insertLog")
public Boolean insertLog(@WebParam(name = "text") String text) {
//TODO write your implementation code here:
return null;
}
}
textWriter.writeBytes(text);
textWriter.close();
fstream.close();
return (true); // success
}
catch (Exception e)
{
lastError = e.getMessage();
return (false); // fail
}
@WebMethod(operationName = "insertLog")
public Boolean insertLog(@WebParam(name = "text") String text) {
return result;
}
كما في المثال السابق لكن بدون أنAdd Operation بواسطةreadLog ثم اضفنا إجراء آخر للقراءة أسميناه
: فتتم إضافته بالشكل التالي. فقط مخرجات في شكل مقطع،تكون له مدخلت
@WebMethod(operationName = "readLog")
public String readLog() {
//TODO write your implementation code here:
return null;
}
:ثم قمنا بكتابة إجراء القراءة من ملف نصي ﻹرجاع الملف كاملا في متغير مقطعي بدلا من عرضه على الشاشة
private String readTextFile(String aFileName)
{
try{
BufferedReader reader = new BufferedReader(new FileReader(aFileName));
}
;)(reader.close
;)return (contents
}
)catch (Exception e
{
;)(lastError = e.getMessage
return (null); // fail
}
}
قمنا بنداء القراءة من الملف النصي في اﻹجراء readLogبالشكل التالي:
)"@WebMethod(operationName = "readLog
{ )(public String readLog
)"@WebMethod(operationName = "getLastError
{ )(public String getLastError
//TODO write your implementation code here:
;return lastError
}
حيث يستخدمه العميل لمعرفة الخطأ الذي حدث في خدمة الويب أثناء ندائها.
نلحظ أنه لبد أن نستخدم دليل به صلحية للمستخدم tomcat6أو tomcat7والذي يتم إستخدامه مع نظام
الشغيل عند التعامل مع خدمات الويب .وفي هذا المثال السابق استخدمنا الدليل /tmpبإعتبار أن به صلحية
لكافة المستخدمين في بيئة لينكس.
في الواقع العملي تكون إجراءات خدمة الويب مرتبطة بتنفيذ إجراءات في قواعد بيانات مثلا إدخال قيد
محاسبي ،إدراج معاملة بنكية ،دفع فاتورة هاتف .كذلك ييمكن أن تقوم خدمات الويب بنداء خدمات ويب أخرى،
بعد ذلك ييمكن تشغيل البرنامج فيتم فتح متصفح الويب تلقائياا لتظهر الشاشة التالية:
بعد نهاية عنوان الويب نقوم بإضافة إسم خدمة الويب Mylogلييصبح العنوان هو:
http://localhost:8080/logfle/Mylog
فيظهر لنا معلومات خدمة الويب :Mylog
http://localhost:8080/logfile/Mylog?wsdl
وهذا هو الشيء الوحيد الذي يحتاجه المبرمج لكتابة برنامج عميل ﻹستخدام خدمة الويب .ويمكن أن يقوم
بإستخدام أي لغة برمجة تدعم تقنية الـ SOAPلنداء الدالتين insertLogو .readLog
حيث نختار WSDL URLنضع فيه عنوان الـ WSDLلخدمة الويب .ثم نختار الحزمة calllogفي Packageثم
ونختارmain فنقوم بالضغط بالزر اليمين للماوس داخل اﻹجراءcalllog.java نرجع لملف الكود الرئيسي
: كما في الصورة التاليةCall Web Service Operation ثمInsert Code
:ثم قمنا بتعديلهما ﻹضافة إظهار الخطأ الذي يحدث في خدمة الويب
}
:عند تشغيل البرنامج نتحصل على الخرج التالي
والتي تقوم باﻹتصال الفعلي وإرسال واستقبالURLConnection كيمدخل لكائن من فئةurl ثم تمرير الكائن
:البيانات
URLConnection myURLConnection = url.openConnection();
myURLConnection.connect();
: وذلك بتهيئته من الكائن السابق للتصالInputStreamReader ثم تعريف كائن للقراءة من نوع
InputStreamReader reader;
reader = new InputStreamReader(myURLConnection.getInputStream());
: وهذا هو كود اﻹجراء كاملا.outputResult وتخزينه في المتغير المقطعي،ثم قراءة المحتويات من اﻹتصال
InputStreamReader reader;
reader = new InputStreamReader(myURLConnection.getInputStream());
reader.close();
return(outputResult);
يمكن استخدام هذه الطريقة للربط بين برنامجين بطريقة أكثر بساطة من بروتوكول الـ SOAPحيث يمكن أن
يكون المخدم هو برنامج ويب يحتوي على Servletيقوم باستقبال معلومات عن طريق GETويمكن ندائه
كالتالي:
= String content
;)"callURL("http://localhost:8080/JavaWebApp/GetCustomerInfo?customerid=1
;)System.out.println(content
ثم يقوم بتنفيذ كود معين ،مثلا قراءة معلومات من قاعدة بيانات ثم إرجاعها في شكل JSONأو حتى .XML
وهذه الطريقة يمكن استخدامها لتبادل البيانات بين برنامج أندرويد في الهاتف مع مخدم في النترنت .ويمكن
تحويل تلك الطريقة قليلا )ارسال المعلومات باستخدام POSTفي شكل JSONبدلا من إرسالها في شكل مدخلت
parametersلتصبح بروتوكول RESTأو ما ييسمى بالـ .RESTFull
كما ذكرنا في المثال السابق لقراءة معلومة من برنامج webباستخدام الـ ،URLوقلنا أنها طريقة بسيطة لعمل
خدمة ويب .وخدمات الويب مشابهة تمام اا في البروتوكول والتقنيات مع برامج الويب ،حيث أن التقنية
المستخدمة في برامج الويب ييمكن استخدامها في برامج الويب .أما اﻹختلفات فتكمن في التي:
.1المستخدم المباشر لبرامج الويب هو شخص يستخدم المتصفح لستعراض والتفاعل مع البرنامج ،أما من
يستخدم خدمة الويب فهو برنامج آخر وليس إنسان.
.2الرد الذي يرجع من برنامج الويب يكون في شكل HTMLحتى يستطيع المتصفح فهمه وعرضه بالشكل
المطلوب للمستخدم النهائي ،أما خدمات الويب فيكون الرد الذي ينتج عن نداء خدمة ويب أو إجراء فيها
هو هيكل بيانات متفق عليه بين خدمة الويب والبرنامج المستفيد منها ،مثل أن تكون في شكل XMLأو
JSONأو بيانات في شكل خصائص ،حيث أن طريقة إظهار المعلومة وشكل الفورم النهائي ليس له علقة
بخدمة الويب ،وإنما هو مسؤولية البرنامج العميل ،و يمكن أن يكون عبارة عن برنامج ذو واجهة رسومية،
مثل برنامج الـ .Swing
لعمل خدمة ويب من نوع الـ RESTFullيمكننا إضافة Servletجديد في برنامج ويب جديد أو في برامج قديم،
حيث يمكن لبرنامج ويب واحد أن يحتوي على خدمات ويب من نوع SOAPو RESTFullوحتى صفحات ويب،
لكن اﻷفضل أن يكون يهناك برنامج ويب منفصل لكل تقنية ﻷن كل واحدة يمكن أن تتطلب مكتبات مختلفة ،كذلك
فإن اﻷفضل دائم اا عزل أنواع البرامج لتكون متخصصة في خدمة ما حتى تسهل صيانتها ،وتشغيلها ،وتطويرها.
قمنا بعمل برنامج ويب اسميناه ،RESTServerثم اضفنا خدمة ويب بتقنية Servletاسميناها .GetServerInfo
;)"String os = System.getProperty("os.name
;)(Date now = new Date
;)"String java = System.getProperty("java.version
;)"out.println("OS=" + os + "\n
;)"out.println("time=" + now.toString() + "\n
;)out.println("javaversion=" + java
}
}
بعد ذلك نقوم بتشغيل البرنامج لعرضه في المتصفح وإضافة إسم خدمة الويب GetServerInfoإلى العنوان
ليصبح كالتالي:
http://localhost:8084/RESTServer/GetServerInfo
نلحظ أن البيانات ظهرت في سطر واحد ،حيث أننا لم نستخدم نسق الـ HTMLحتى تظهر بصورة جيدة ،وكما
ذكرنا فإن المقصود ليس المتصفح وإنما برنامج آخر تتم كتابته بواسطة المبرمج ،لكن يمكن استخدام المتصفح
أثناء تطوير البرنامج ﻷجل عرض البرامج .يمكن عرضه بطريقة أفضل بعرض مصدر الصفحة من المتصفح
وذلك بالضغط بالزر اليمين على الصفحة ثم اختيار View page sourceليظهر لنا النص كما جاء من المخدم
بدون تغيير:
كذلك يمكننا عمل برنامج يقرأ الـ URLكما كتبنا سابقاا ،يمكننا نداء اﻹجراء التي كتبناه سابقاا .callURL
قمنا بعمل برنامج Java Applicationجديد اسميناه CallRestواضنا إليه اﻹجراء callURLثم قمنا بندائه في
اﻹجراء mainكالتالي:
فكانت النتيجة:
OS=Linux
time=Sat Sep 03 11:42:41 EAT 2016
javaversion=1.7.0_111
String content;
content = callURL("http://localhost:8084/RESTServer/GetServerInfo");
// Parse output
Properties properties = new Properties();
properties.load(in);
String serverOS = properties.getProperty("OS");
String serverTime = properties.getProperty("time");
String javaVersion = properties.getProperty("javaversion");
// Display output
System.out.println("Server OS is : " + serverOS);
System.out.println("Server Time is : " + serverTime);
System.out.println("Server Java version is : " + javaVersion);
}
لقراءة محتويات المقطع الذي يحتوي على الخصائص لتحويلهاByteArrayInputStream قمنا باستخدام الفئة
وذلك ﻷن كائن الخصائص يستطيع القراءة من سلسلة بيانات ول يستطيع القراءة منstream إلى سلسلة بيانات
: فكان هذا بمثابة تحويل للية نقل البيانات،مقطع مباشرة
ByteArrayInputStream in = new ByteArrayInputStream(content.getBytes());
Properties properties = new Properties();
properties.load(in);
. لكن نريد إرسال بيانات من العميل إلى المخدم،في هذا المثال ركزنا على إرجاع بيانات من المخدم إلى العميل
وكمثال طلبنا من البرنامج العميل إدخال اسم،قمنا بتعديل خدمة الويب لقراءة مدخلت من نوع الخصائص
:الزبون وعنوانه
وذلك،قمنا باستخدام كائنة من فئة الخصائص في المخدم لقراءة المعلومات اليمرسلة بواسطة البرنامج العميل
:بإضافة هذا الكود
// read input
Properties properties = new Properties();
properties.load(request.getInputStream());
String customerName = properties.getProperty("name");
String customerAddress = properties.getProperty("address");
: ليصبح كود خدمة الويب كالتالي،قمنا كذلك بإرجاع نفس البيانات اليمرسلة
// read input
Properties properties = new Properties();
properties.load(request.getInputStream());
String os = System.getProperty("os.name");
Date now = new Date();
String java = System.getProperty("java.version");
out.println("OS=" + os);
out.println("time=" + now.toString());
out.println("javaversion=" + java);
out.println("customername=" + customerName);
out.println("customeraddress=" + customerAddress);
}
}
ﻷن إرسال البيانات الذي استخدمناه،هذه المكرة ل يمكننا نداء خدمة الويب هذه عن طريق المتصفح العادي
.URL والتي يتم إرسال البيانات فيها بمعزل عن العنوانPOST يستخدم طريقة
نقوم بإضافةFirefox مثلا في متصفح،لذلك لتجربة خدمة الويب هذه نحتاج لتثبيت أداة إضافية في المتصفح
: وذلك عن طريقRESTClient اﻷداة
Add-ons/Extensions
بعد ذلك نقوم، فتظهر في اعلى المتصفح، ثم نعيد تشغيله، ثم نضيفها إلى المتصفحRESTClient ثم نبحث عن
(Method) بإدخال عنوان خدمة الويب ثم كتابة اليمدخلت في شكل خصائص وتحويل طريقة إرسال البيانات
: بالشكال التاليPOST إلى
ثم قمنا بتعريف كائن للكتابة من نوع OutputStreamWriterﻹرسال تلك البيانات إلى كائن اﻹتصال:
;OutputStreamWriter writer
;))(writer = new OutputStreamWriter(myURLConnection.getOutputStream
: ثم إرجاع النتيجةPOST والذي يقوم بإرسال بيانات في شكلcallURL فكان هذا هو الشكل النهائي للجراء
// Write Input
OutputStreamWriter writer;
writer = new OutputStreamWriter(myURLConnection.getOutputStream());
writer.write(input);
writer.flush();
writer.close();
// Read result
InputStreamReader reader;
reader = new InputStreamReader(myURLConnection.getInputStream());
reader.close();
return(outputResult);
String input;
input = "name=Motaz Abdel Azeem\naddress=Khartoum, Sudan";
String content;
content = callURL("http://localhost:8084/RESTServer/GetServerInfo", input);
String input;
input = "name=Motaz Abdel Azeem\naddress=Khartoum, Sudan";
String content;
content = callURL("http://localhost:8084/RESTServer/GetServerInfo", input);
// Prase output
Properties properties = new Properties();
properties.load(in);
String serverOS = properties.getProperty("OS");
String serverTime = properties.getProperty("time");
String javaVersion = properties.getProperty("javaversion");
String customerName = properties.getProperty("customername");
String customerAddress = properties.getProperty("customeraddress");
// Display output
System.out.println("Server OS is : " + serverOS);
System.out.println("Server Time is : " + serverTime);
System.out.println("Server Java version is : " + javaVersion);
System.out.println("Customer name : " + customerName);
System.out.println("Customer address : " + customerAddress);
}
لشرحها أو ا
ل قبل استخدامها في خدمات الويب ،قمنا بعمل برنامج جافا عادي ثم اضفنا هذه المكتبة في جزء
libraryبواسطة Add JAR/Folderثم قمنا بكتابة هذا الكود لكتابة بيانات في شكل :JSON
;)(JSONObject myObject = new JSONObject
;)myObject.put("year", 2016
;)"myObject.put("service", "Customer Registration
;)myObject.put("valid", true
;))(System.out.println(myObject.toJSONString
في هذا المثال استخدمنا كائن من نوع الفئة JSONObjectللتعامل مع هذه النوعية من النسق.
وناتج التشغيل هو مقطع في شكل :JSON
}{"valid":true,"service":"Customer Registration","year":2016
بعد إضافة كافة العناصر باستخدام putنقوم في النهاية بالحصول على المقطع الذي يحتوي على هذا النسق
بواسطة .toJSONSting
وهذا الجزء ييستخدم في جانب العميل ﻹرسال بيانات في شكل ،JSONأما المخدم فيقوم بمعالجة هذه المعلومات
واستخلص القيم بواسطة أسماءها .قمنا بإضافة هذا الكود في نفس البرنامج لمعرفة آلية قراءة مقطع JSON
وتحويله إلى متغيرات بسيطة:
هذه المرة استخدمنا كائن من النوع JSONParserلتحويل المقطع إلى كائن JSONحتى نتعامل مع البيانات التي
بداخله مباشرة ،وفي هذا السطر يتم تحويل المقطع إلى :JSON
;)JSONObject received = (JSONObject)parser.parse(myInput
. بدلا من نوع الخصائصJSON ليستقبل بيانات من نوعRESTServer بعد ذلك قمنا بتحويل البرنامج
:JSON وهو مقطع الـ،أولا اضفنا إجراء جديد لقراءة المحتويات اليمرسلة وتحويلها إلى مقطع واحد
:وهذا هو الجزء الذي نقوم فيه باستقبال ثم معالجة اليمدخلت وتحويلها إلى بيانات بسيطة
try {
// read input
String requestStr = readClient(request);
String os = System.getProperty("os.name");
Date now = new Date();
String java = System.getProperty("java.version");
// prepare output
JSONObject result = new JSONObject();
result.put("success", true);
result.put("OS", os);
result.put("time", now.toString());
result.put("javaversion", java);
result.put("customername", customerName);
result.put("customeraddress", customerAddress);
// Write output
out.println(result.toJSONString());
}
catch (Exception ex){
JSONObject obj = new JSONObject();
obj.put("success", false);
obj.put("error", ex.toString());
out.println(obj.toJSONString());
}
}
}
JSON بإرسال اليمدخلت في شكل نسقFirefox في متصفحRESTClient يمكن مناداته باستخدام اﻷداة
:كالمثال التالي
{"name":""معتز عبدالعظيم,
"address":"Khartoum, Sudan"}
ثم تحويل اليمدخلت لشكلjson-simple ( فنقوم ايضاا بإضافة المكتبةCallRest أما في جزئية العميل )برنامج
.JSON
: كالتاليcallURL في اﻹجراءUTF-8 ثم قمنا بإضافة ﻹظهار اللغة العربية لتحويل البيانات إلى
String content;
false أما إذا كانت، قمنا بقراءة باقي القيمtrue فإذا كانت تحتوي علىsuccess لكن علينا أولا قراءة القيمة
:error فنقوم بإظهار الخطأ
JSONParser parser = new JSONParser();
JSONObject outputResult = (JSONObject) parser.parse(content);
boolean success = Boolean.valueOf(outputResult.get("success").toString());
if (success){
String serverOS = outputResult.get("OS").toString();
String serverTime = outputResult.get("time").toString();
String javaVersion = outputResult.get("javaversion").toString();
String customerName = outputResult.get("customername").toString();
String customerAddress =
outputResult.get("customeraddress").toString();
// Display output
System.out.println("Server OS is : " + serverOS);
System.out.println("Server Time is : " + serverTime);
System.out.println("Server Java version is : " + javaVersion);
System.out.println("Customer name : " + customerName);
System.out.println("Customer address : " + customerAddress);
}
else
{
System.out.println("Error: " + outputResult.get("error").toString());
}
ملوحظة:
هذا الكتاب مازال يتم تعديله من فترة ﻷخرى ،فنرجو الحرص على الحصول على آخر ينسخة من الموقع.