عناصر البرمجة النصية في JSP
عناصر البرمجة النصية في JSP
صُمّمت صفحات JavaServer Pages (JSP) كوسيلة لتضمين المخرجات الديناميكية مباشرةً داخل HTML. لتحقيق ذلك، عرّفت المواصفة الأصلية ثلاثة عناصر برمجية نصية تتيح كتابة Java داخل ملف .jsp: الكتل النصية (scriptlets)، والتعبيرات (expressions)، والتصريحات (declarations). ينبغي لكل مطوّر JSP أن يتعرّف على هذه البنى — سواء لصيانة الكود القديم أو لفهم السبب الجوهري الذي يجعل JSP الحديثة تتجنّبها عمدًا.
كيف تعمل ترجمة JSP
قبل الخوض في التفاصيل، من المفيد أن تفهم ما يفعله حاوي servlet فعليًا بملف JSP. عندما يصل طلب لمورد .jsp، يترجم الحاوي (Tomcat أو WildFly أو غيرهما) الملف إلى ملف Java مصدري يمتد من HttpJspBase، ثم يصرّفه إلى bytecode، ومن ثمّ يخدم الطلبات اللاحقة من servlet المُصرَّفة — تمامًا كـ HttpServlet المكتوبة يدويًا. عناصر البرمجة النصية هي كود Java حرفي يُدمج في الفئة المُولَّدة. وهذا النموذج التحويلي هو السبب في كون عناصر البرمجة النصية قويةً وخطرةً في آنٍ واحد.
الكتل النصية: <% ... %>
تضع الكتلة النصية جمل Java اعتباطية داخل الدالة _jspService() المُولَّدة. الصياغة هي <% javaCode; %>.
ينسج الحاوي مقاطع HTML بين الكتل النصية داخل استدعاءات out.write("..."). والنتيجة تُصرَّف وتعمل، لكن الكود المُولَّد يتشابك فيه Java وكتابة السلاسل النصية بطريقة تجعل اختباره أو صيانته شبه مستحيل.
التعبيرات: <%= ... %>
يُقيّم عنصر التعبير تعبير Java واحدًا ويكتب قيمة toString() الخاصة به مباشرةً في الاستجابة. لا يوجد فاصلة منقوطة داخل وسم التعبير.
يترجم الحاوي <%= expr %> إلى out.print(expr);. انتبه إلى أنه إذا أسفر التعبير عن null، تُكتب السلسلة "null" في المخرجات — لا توجد حماية من null.
out.print(). لا يمكنك استخدام الجمل (الإسنادات، الحلقات، الشروط) داخل وسم التعبير — بل تعبيرٌ واحد فقط يُنتج قيمة.
التصريحات: <%! ... %>
تضع التصريح كودًا على مستوى الفئة في servlet المُولَّدة، خارج _jspService(). يمكنك تصريح متغيرات النسخة والدوال هنا.
توجيه الصفحة (Page Directive)
تبدأ كل ملفات JSP تقريبًا بـتوجيه الصفحة، الذي يُهيّئ إعدادات servlet المُولَّدة. إنه ليس عنصر برمجة نصية، لكنه يظهر دائمًا بجانبها.
السمات الرئيسية: import يضيف جمل import إلى الفئة المُولَّدة؛ contentType يضبط ترويسة Content-Type للاستجابة؛ errorPage يحوّل الاستثناءات غير الملتقطة إلى صفحة خطأ مخصصة.
لماذا تتجنّب JSP الحديثة الكتل النصية
توصّل مجتمع Java EE إلى توافق واسع — رُسّخ في كتاب Core J2EE Patterns من Sun ولاحقًا في توجيهات مواصفة JSP 2.0 — مفاده أن الكتل النصية لا ينبغي أن تظهر في ملفات JSP الإنتاجية. الأسباب ملموسة:
- كود غير قابل للاختبار. لا يمكن تشغيل المنطق داخل الكتلة النصية إلا بنشر الصفحة وإرسال طلب HTTP. لا توجد طريقة لكتابة اختبار وحدة لكتلة نصية.
- صياغة معادية للمصمّمين. لا يستطيع مصمّمو HTML/CSS ومهندسو الواجهة الأمامية العمل مع ملفات JSP مليئة بكود Java. تعاني أدوات مثل بيئات التطوير المتكاملة والمحللات الساكنة من الصياغة المختلطة.
- تكلفة الصيانة. تضاعف كل تغيير العبء المعرفي عند تشابك Java وHTML. تُظهر دراسات قواعد الكود القديمة باستمرار أن الكتل النصية في JSP تمثّل نقطة ساخنة للصيانة.
- توجد بدائل أفضل. توفّر لغة التعبير (EL) وJSTL — التي تُغطَّى في الدروس القادمة — بدائل تصريحية وسهلة التعامل للمصمّمين لكل نمط شائع من الكتل النصية (التكرار، الشروط، التنسيق). تذهب Thymeleaf وFreeMarker أبعد من ذلك بكونهما HTML صالحًا حتى قبل معالجة القوالب.
<scripting-invalid>true</scripting-invalid> إلى <jsp-property-group> في ملف web.xml. يحوّل هذا أي كتلة نصية متبقية في المشروع إلى خطأ وقت التصريف — حاجز مفيد عند تهيئة قاعدة كود موروثة.
مرجع سريع: العناصر الثلاثة للبرمجة النصية
<% statements; %>— الكتلة النصية: جمل Java اعتباطية، تُوضع في_jspService(). تجنّبها في الكود الجديد.<%= expression %>— التعبير: تعبير Java واحد تُطبع قيمته في الاستجابة. يحلّ محله EL بصيغة${expression}.<%! declaration %>— التصريح: أعضاء على مستوى الفئة (حقول، دوال). محفوف بالمخاطر بسبب الحالة المشتركة القابلة للتغيير؛ نادرًا ما تكون مطلوبة.
الخلاصة
تتيح الكتل النصية والتعبيرات والتصريحات تضمين Java مباشرةً داخل HTML — وهذا بالضبط ما يجعلها إشكالية. فهي تخلط مخاوف العرض بالمنطق، وتُنتج كودًا غير قابل للاختبار، وتستلزم فهم نموذج الترجمة (فئة servlet المُولَّدة، الدالة _jspService()) للاستدلال على سلوكها. يستبدل تطوير JSP الحديث الثلاثة بـ EL وJSTL، اللتين توفّران المخرجات الديناميكية ذاتها دون خلط اللغتين. في الدرس القادم ستستكشف الكائنات الضمنية المتاحة دائمًا في كل JSP — فهمها يُكمل الصورة قبل الانتقال إلى EL وJSTL.