الاختلافات بين العمل و ActionListener
-
29-09-2019 - |
سؤال
ماهو الفرق بين action
و actionListener
, ومتى يجب أن أستخدم action
عكس actionListener
?
المحلول
ActionListener
يستخدم actionListener
إذا كنت تريد أن يكون لديك خطاف قبل يتم تنفيذ الإجراء التجاري الحقيقي ، على سبيل المثال لتسجيله ، و/أو لتعيين خاصية إضافية (بواسطة <f:setPropertyActionListener>
) ، و/أو للوصول إلى المكون الذي استدعى الإجراء (وهو متاح بواسطة ActionEvent
جدال). لذلك ، بحتة لإعداد الأغراض قبل التذرع في الإجراء التجاري الحقيقي.
ال actionListener
الطريقة تفتقر إلى التوقيع التالي:
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
ومن المفترض أن يتم الإعلان عن ذلك على النحو التالي ، دون أي قوسين:
<h:commandXxx ... actionListener="#{bean.actionListener}" />
لاحظ أنه لا يمكنك المرور إضافي الحجج من قبل 2.2. ومع ذلك يمكنك تجاوز ActionEvent
حجة تمامًا عن طريق تمرير وتحديد وسيطة (ق) مخصصة. الأمثلة التالية صالحة:
<h:commandXxx ... actionListener="#{bean.methodWithoutArguments()}" />
<h:commandXxx ... actionListener="#{bean.methodWithOneArgument(arg1)}" />
<h:commandXxx ... actionListener="#{bean.methodWithTwoArguments(arg1, arg2)}" />
public void methodWithoutArguments() {}
public void methodWithOneArgument(Object arg1) {}
public void methodWithTwoArguments(Object arg1, Object arg2) {}
لاحظ أهمية الأقواس في التعبير عن الطريقة غير المجدية. إذا كانت غائبة ، فإن JSF لا يزال يتوقع طريقة معها ActionEvent
جدال.
إذا كنت على EL 2.2+ ، فيمكنك إعلان طرق مستمع إجراء متعددة عبر <f:actionListener binding>
.
<h:commandXxx ... actionListener="#{bean.actionListener1}">
<f:actionListener binding="#{bean.actionListener2()}" />
<f:actionListener binding="#{bean.actionListener3()}" />
</h:commandXxx>
public void actionListener1(ActionEvent event) {}
public void actionListener2() {}
public void actionListener3() {}
لاحظ أهمية الأقواس في binding
ينسب. إذا كانوا غائبين ، فإن El سوف يربك javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
, ، بسبب ال binding
السمة يتم تفسيرها افتراضيًا على أنها تعبير قيمة ، وليس كتعبير عن الطريقة. إن إضافة قوسين EL 2.2+ يحول بشفافية تعبيرًا عن القيمة إلى تعبير طريقة. انظر أيضا AO لماذا أنا قادر على الربطu003Cf:actionListener> إلى طريقة تعسفية إذا لم تكن مدعومة من قبل JSF؟
عمل
يستخدم action
إذا كنت ترغب في تنفيذ إجراء عمل وإذا لزم الأمر ، قم بالتعامل مع التنقل. ال action
يمكن أن تُرجع الطريقة (وبالتالي ، لا يجب) إرجاع أ String
والتي سيتم استخدامها كنتيجة حالة التنقل (العرض الهدف). قيمة إرجاع null
أو void
سوف تدعها تعود إلى نفس الصفحة والحفاظ على نطاق العرض الحالي على قيد الحياة. ستعود أيضًا قيمة الإرجاع لسلسلة فارغة أو نفس معرف العرض إلى نفس الصفحة ، ولكن إعادة إنشاء نطاق العرض وبالتالي تدمير أي حبوب عرض نشطة حاليًا ، وإذا كان ذلك ممكنًا ، أعيد إنشائها.
ال action
يمكن أن تكون الطريقة صالحة MethodExpression
, ، أيضًا تلك التي تستخدم حجج EL 2.2 مثل أدناه:
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
مع هذه الطريقة:
public void edit(Item item) {
// ...
}
لاحظ أنه عندما تقوم طريقة الإجراء الخاصة بك بإرجاع سلسلة فقط ، يمكنك أيضًا تحديد هذه السلسلة بالضبط في action
ينسب. وبالتالي ، هذا خرقاء تمامًا:
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
مع هذه الطريقة التي لا معنى لها إرجاع سلسلة متشددين:
public String goToNextpage() {
return "nextpage";
}
بدلاً من ذلك ، فقط ضع هذه السلسلة المتشددين مباشرة في السمة:
<h:commandLink value="Go to next page" action="nextpage" />
يرجى ملاحظة أن هذا بدوره يشير إلى تصميم سيء: التنقل عن طريق البريد. هذا ليس مستخدمًا ولا صديقًا لكبار المسئولين الاقتصاديين. تم شرح كل هذا في متى يجب أن أستخدم H: OutputLink بدلاً من H: CommandLink؟ ومن المفترض أن يتم حلها
<h:link value="Go to next page" outcome="nextpage" />
أنظر أيضا كيف تنقل في JSF؟ كيفية جعل عنوان URL تعكس الصفحة الحالية (وليس السابقة).
F: مستمع Ajax
منذ JSF 2.x هناك طريقة ثالثة ، <f:ajax listener>
.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
ال ajaxListener
الطريقة تفتقر إلى التوقيع التالي:
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
في موجارا ، AjaxBehaviorEvent
الوسيطة اختيارية ، أدناه يعمل بشكل جيد.
public void ajaxListener() {
// ...
}
لكن في myfaces ، سوف يرمي MethodNotFoundException
. يعمل أدناه في كلا تطبيقات JSF عندما تريد حذف الوسيطة.
<h:commandXxx ...>
<f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>
مستمعي Ajax ليسوا مفيدين حقًا على مكونات الأوامر. فهي أكثر فائدة في الإدخال وتحديد المكونات <h:inputXxx>
/<h:selectXxx>
. في مكونات القيادة ، فقط التمسك action
و/أو actionListener
من أجل الوضوح وأفضل رمز توثيق الذات. علاوة على ذلك ، مثل actionListener
, ، ال f:ajax listener
لا يدعم إعادة نتيجة التنقل.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
للشرح على execute
و render
سمات ، توجه إلى فهم عملية/تحديث PrimeFaces و JSF F: سمات تنفيذ/تقديم AJAX.
أمر الاحتجاج
ال actionListener
يتم استدعاء s دائما قبل ال action
في نفس الترتيب الذي تم الإعلان عنه في العرض وربطه بالمكون. ال f:ajax listener
يتم استدعاؤه دائمًا قبل أي مستمع عمل. لذا ، المثال التالي:
<h:commandButton value="submit" actionListener="#{bean.actionListener}" action="#{bean.action}">
<f:actionListener type="com.example.ActionListenerType" />
<f:actionListener binding="#{bean.actionListenerBinding()}" />
<f:setPropertyActionListener target="#{bean.property}" value="some" />
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandButton>
سوف تستدعي الأساليب بالترتيب التالي:
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
معالجة الاستثناء
ال actionListener
يدعم استثناء خاص: AbortProcessingException
. إذا تم إلقاء هذا الاستثناء من actionListener
الطريقة ، ثم تقوم JSF بتخطي أي مستمعين من الإجراءات المتبقية وطريقة الإجراء والمضي قدمًا في تقديم الاستجابة مباشرة. لن ترى صفحة خطأ/استثناء ، فسيقوم JSF بتسجيله. سيتم أيضًا القيام بذلك ضمنيًا كلما تم طرح أي استثناء آخر من actionListener
. لذا ، إذا كنت تنوي حظر الصفحة حسب صفحة خطأ نتيجة استثناء العمل ، فعليك بالتأكيد أداء المهمة في action
طريقة.
إذا كان السبب الوحيد لاستخدام actionListener
هو أن يكون void
الطريقة التي تعود إلى نفس الصفحة ، فهذا أمر سيء. ال action
يمكن أن تعود الأساليب أيضًا بشكل مثالي void
, ، على عكس ما تتيح لك بعض IDEs تصديقه عبر التحقق من الصحة. نلاحظ أن عرض PrimeFaces الأمثلة مليئة بهذا النوع من actionListener
ق فوق كل مكان. هذا خطأ بالفعل. لا تستخدم هذا كذريعة للقيام بذلك بنفسك.
في طلبات AJAX ، هناك حاجة إلى معالج استثناء خاص. هذا بغض النظر عما إذا كنت تستخدم listener
سمة <f:ajax>
أم لا. للشرح ومثال ، توجه إلى استثناء معالجة في طلبات JSF Ajax.
نصائح أخرى
كما أشار Balusc ، actionListener
بشكل افتراضي ، استثناءات Swallows ، ولكن في JSF 2.0 هناك المزيد لهذا. وهي ، لا يبتلع ويسجلات فحسب ، بل في الواقع نشر الاستثناء.
يحدث هذا من خلال مكالمة كهذه:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
المستمع الافتراضي لهذا الحدث هو ExceptionHandler
التي تم تعيينها ل Mojarra com.sun.faces.context.ExceptionHandlerImpl
. سيعيد هذا التنفيذ بشكل أساسي أي استثناء ، إلا عندما يتعلق الأمر بمعالجة إحباط ، والذي تم تسجيله. يلف ActionListeners الاستثناء الذي يتم إلقاؤه بواسطة رمز العميل في مثل هذا الإجهاض المعالجة التي تشرح سبب تسجيلها دائمًا.
هذه ExceptionHandler
يمكن استبداله في الوجوه config.xml بتنفيذ مخصص:
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
بدلاً من الاستماع على مستوى العالم ، يمكن لحبة واحدة أيضًا الاستماع إلى هذه الأحداث. فيما يلي دليل على مفهوم هذا:
@ManagedBean
@RequestScoped
public class MyBean {
public void actionMethod(ActionEvent event) {
FacesContext.getCurrentInstance().getApplication().subscribeToEvent(ExceptionQueuedEvent.class, new SystemEventListener() {
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
ExceptionQueuedEventContext content = (ExceptionQueuedEventContext)event.getSource();
throw new RuntimeException(content.getException());
}
@Override
public boolean isListenerForSource(Object source) {
return true;
}
});
throw new RuntimeException("test");
}
}
(لاحظ ، هذا ليس كيف ينبغي للمرء أن يرمز بشكل طبيعي ، وهذا هو فقط لأغراض العرض التوضيحي!)
استدعاء هذا من الهيكل مثل هذا:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h:form>
<h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
</h:form>
</h:body>
</html>
سوف يؤدي إلى عرض صفحة خطأ.
يتم إطلاق ActionListener أولاً ، مع خيار لتعديل الاستجابة ، قبل استدعاء الإجراء ويحدد موقع الصفحة التالية.
إذا كان لديك أزرار متعددة على نفس الصفحة التي يجب أن تنتقل إلى نفس المكان ولكنها تقوم بأشياء مختلفة قليلاً ، فيمكنك استخدام نفس الإجراء لكل زر ، ولكن استخدام قائمة عمل مختلفة للتعامل مع وظائف مختلفة قليلاً.
فيما يلي رابط يصف العلاقة:
TL ؛ د:
ال ActionListener
S (يمكن أن يكون هناك متعددة) تنفيذ بالترتيب الذي تم تسجيله قبل action
اجابة طويلة:
عمل action
عادةً ما يستدعي خدمة EJB وإذا لزم الأمر ، فإن النتيجة النهائية و/أو تتنقل إلى وجهة نظر مختلفة إذا لم يكن هذا ما تفعله actionListener
هو أكثر ملاءمة IE عندما يتفاعل المستخدم مع المكونات ، مثل h:commandButton
أو h:link
يمكن التعامل معها عن طريق تمرير اسم طريقة الفول المدارة في actionListener
سمة مكون واجهة المستخدم أو لتنفيذ ActionListener
واجهة وتمرير اسم فئة التنفيذ إلى actionListener
سمة مكون واجهة المستخدم.