سؤال

ماهو الفرق بين 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>

سوف تستدعي الأساليب بالترتيب التالي:

  1. Bean#ajaxListener()
  2. Bean#actionListener()
  3. ActionListenerType#processAction()
  4. Bean#actionListenerBinding()
  5. Bean#setProperty()
  6. 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 أولاً ، مع خيار لتعديل الاستجابة ، قبل استدعاء الإجراء ويحدد موقع الصفحة التالية.

إذا كان لديك أزرار متعددة على نفس الصفحة التي يجب أن تنتقل إلى نفس المكان ولكنها تقوم بأشياء مختلفة قليلاً ، فيمكنك استخدام نفس الإجراء لكل زر ، ولكن استخدام قائمة عمل مختلفة للتعامل مع وظائف مختلفة قليلاً.

فيما يلي رابط يصف العلاقة:

http://www.java-samples.com/showtutorial.php؟tutorialid=605

TL ؛ د:

ال ActionListenerS (يمكن أن يكون هناك متعددة) تنفيذ بالترتيب الذي تم تسجيله قبل action

اجابة طويلة:

عمل action عادةً ما يستدعي خدمة EJB وإذا لزم الأمر ، فإن النتيجة النهائية و/أو تتنقل إلى وجهة نظر مختلفة إذا لم يكن هذا ما تفعله actionListener هو أكثر ملاءمة IE عندما يتفاعل المستخدم مع المكونات ، مثل h:commandButton أو h:link يمكن التعامل معها عن طريق تمرير اسم طريقة الفول المدارة في actionListener سمة مكون واجهة المستخدم أو لتنفيذ ActionListener واجهة وتمرير اسم فئة التنفيذ إلى actionListener سمة مكون واجهة المستخدم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top