Domanda

Qual è la differenza tra action e actionListener, e quando devo usare action contro actionListener?

È stato utile?

Soluzione

ActionListener

Usa actionListener se si vuole avere un gancio prima eseguita l'azione vera e propria attività, per esempio per registrare, e / o per impostare una proprietà aggiuntiva (da <f:setPropertyActionListener> ), e / o avere accesso al componente che richiama l'azione (che è disponibile da ActionEvent argomento). Così, puramente per la preparazione di scopi, prima viene invocata l'azione vero e proprio business.

Il metodo actionListener ha per default la seguente firma:

import javax.faces.event.ActionEvent;
// ...

public void actionListener(ActionEvent event) {
    // ...
}

E si suppone essere dichiarata come segue, senza alcuna parentesi di metodo:

<h:commandXxx ... actionListener="#{bean.actionListener}" />

Si noti che non è possibile passare ulteriore argomenti di EL 2.2. È tuttavia possibile ignorare l'argomento ActionEvent del tutto passando e specificando l'argomento personalizzato (s). Gli esempi che seguono sono validi:

<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) {}

Si noti l'importanza delle parentesi nel metodo espressione argumentless. Se fossero assenti, JSF sarebbe ancora aspettano un metodo con argomenti ActionEvent.

Se siete su EL 2.2+, allora si può dichiarare più metodi action listener tramite <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() {}

Si noti l'importanza delle parentesi nel dell'attributo binding. Se fossero assenti, EL avrebbe confusamente gettare un javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean, perché l'attributo binding è per default interpretato come un'espressione di valore, non come un'espressione metodo. Aggiunta EL 2.2 + parentesi stile diventa trasparente un'espressione di valore in un'espressione metodo. Vedi anche A.O. Perché am sono in grado di legarsi ? un metodo arbitrario se non è supportato da JSF


azione

Usa action se si desidera eseguire un'azione di business e, se necessario, la navigazione maniglia. Il metodo può action (quindi, non deve) restituire un String che sarà utilizzato come caso navigazione esito (la visualizzazione di destinazione). Un valore restituito di null o void sarà lasciarlo tornare alla stessa pagina e mantenere viva la vista ambito corrente. Un valore restituito di una stringa vuota o lo stesso ID vista anche ritornare alla stessa pagina, ma ricreare la portata vista e così distruggere qualsiasi vista ambito fagioli attualmente attivi e, se del caso, li ricreare.

Il metodo action può essere qualsiasi valida MethodExpression , anche quelli che utilizza EL 2,2 argomenti, come di seguito:

<h:commandXxx value="submit" action="#{bean.edit(item)}" />

Con questo metodo:

public void edit(Item item) {
    // ...
}

Si noti che quando il metodo di azione restituisce solo una stringa, allora si può anche solo specificare esattamente quella stringa nell'attributo action. Quindi, questo è totalmente goffo:

<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />

Con questo metodo senza senso restituendo una stringa hardcoded:

public String goToNextpage() {
    return "nextpage";
}

Invece, appena messo quella stringa hardcoded direttamente l'attributo:

<h:commandLink value="Go to next page" action="nextpage" />

Si noti che questo a sua volta indica una cattiva progettazione: la navigazione per posta. Questo non è utente né SEO friendly. Tutto questo è spiegato in Quando devo usare h: outputLink invece di h:? commandLink e si suppone da risolvere come

<h:link value="Go to next page" outcome="nextpage" />

Si veda anche Come navigare in JSF? Come rendere URL riflettere pagina corrente (e non quella precedente) .


f: Ajax ascoltatore

Dal JSF 2.x c'è una terza via, la <f:ajax listener>.

<h:commandXxx ...>
    <f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>

Il metodo ajaxListener ha per default la seguente firma:

import javax.faces.event.AjaxBehaviorEvent;
// ...

public void ajaxListener(AjaxBehaviorEvent event) {
    // ...
}

Nel Mojarra, l'argomento AjaxBehaviorEvent è facoltativo, sotto funziona come buona.

public void ajaxListener() {
    // ...
}

Ma in MyFaces, sarebbe gettare un MethodNotFoundException. Qui di seguito opere in entrambe le implementazioni JSF quando si vuole omettere l'argomento.

<h:commandXxx ...>
    <f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>

ascoltatori Ajax non sono realmente utili sui componenti di comando. Essi sono più utili in ingresso e selezionare i componenti <h:inputXxx> / <h:selectXxx>. Nei componenti di comando, basta attenersi a action e / o actionListener per chiarezza e una migliore codice autoesplicativo. Inoltre, come actionListener, il f:ajax listener non supporta la restituzione di un risultato di navigazione.

<h:commandXxx ... action="#{bean.action}">
    <f:ajax execute="@form" render="@form" />
</h:commandXxx>

Per una spiegazione sugli attributi execute e render, testa a primefaces comprensione dei processi / aggiornamento e JSF f: ajax eseguire / renda attributi

.

Invocation ordine

I actionListeners sono sempre invocata prima il action nello stesso ordine in cui sono stati dichiarati nella vista e fissata al componente. Il f:ajax listener è sempre invocato prima qualsiasi ascoltatore azione. Così, il seguente esempio:

<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>

Sarà richiamare i metodi nel seguente ordine:

  1. Bean#ajaxListener()
  2. Bean#actionListener()
  3. ActionListenerType#processAction()
  4. Bean#actionListenerBinding()
  5. Bean#setProperty()
  6. Bean#action()

La gestione delle eccezioni

Il actionListener supporta una particolare eccezione: AbortProcessingException . Se questa eccezione viene generata da un metodo actionListener, allora JSF ignorerà eventuali ascoltatori azione rimanenti e il metodo di azione e procedere rendere direttamente risposta. Non vedrete una pagina di errore / eccezione, JSF sarà comunque il login esso. Questo sarà anche implicitamente essere fatto ogni volta che qualsiasi altra eccezione viene gettata da un actionListener. Quindi, se avete intenzione di bloccare la pagina una pagina di errore come risultato di un'eccezione di business, allora si dovrebbe sicuramente svolgere il lavoro nel metodo action.

Se l'unica ragione per usare un actionListener è quello di avere un metodo void ritornare alla stessa pagina, allora questo è uno cattivo. I metodi possono action perfettamente anche restituire void, al contrario di quello che alcuni IDE consentono di credere tramite convalida EL. Si noti che il primefaces vetrina esempi sono disseminati di questo tipo di actionListeners su tutto posto. Questo è davvero sbagliato. Non utilizzare questo come una scusa per fare anche tu stesso.

Nel richieste Ajax, tuttavia, è necessario un gestore speciale eccezione. Ciò a prescindere dal fatto che si utilizzi l'attributo listener di <f:ajax> o meno. Per una spiegazione e un esempio, la testa di manipolazione in JSF Eccezione ajax richieste .

Altri suggerimenti

Come BalusC indicato, il actionListener da eccezioni predefinite rondini, ma in JSF 2.0 c'è un po 'di più per questo. Vale a dire, lo fa non solo rondini e registri, ma in realtà PUBBLICAMENTE l'eccezione.

Ciò avviene attraverso una chiamata in questo modo:

context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,                                                          
    new ExceptionQueuedEventContext(context, exception, source, phaseId)
);

L'ascoltatore di default per questo evento è la ExceptionHandler che da Mojarra è impostato su com.sun.faces.context.ExceptionHandlerImpl. Questa implementazione sarà essenzialmente rigenerare qualsiasi eccezione, tranne quando si tratta di un AbortProcessingException, che viene registrato. ActionListeners avvolgono l'eccezione che viene generata dal codice client in tale AbortProcessingException che spiega il motivo per cui queste sono sempre registrati.

Questa ExceptionHandler può essere sostituito comunque in faces-config.xml con un'implementazione personalizzata:

<exception-handlerfactory>
   com.foo.myExceptionHandler
</exception-handlerfactory>

Invece di ascoltare a livello globale, un singolo chicco può anche ascoltare questi eventi. Quanto segue è un proof of concept di questo:

@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");
    }

}

(nota, questo non è come si dovrebbe normalmente ascoltatori di codice, questo è solo a scopo dimostrativo!)

La chiamata a questo da un facelet in questo modo:

<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>

comporterà visualizzata una pagina di errore.

ActionListener s'incendia prima, con la possibilità di modificare la risposta, prima che l'azione viene chiamato e determina la posizione della pagina successiva.

Se si dispone di più pulsanti sulla stessa pagina che dovrebbe andare nello stesso posto, ma fare le cose un po 'diverse, è possibile utilizzare la stessa azione per ogni pulsante, ma utilizzare un ActionListener diverso per gestire funzionalità leggermente differenti.

Ecco un link che descrive la relazione:

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

TL; DR :

L'ActionListeners (ci possono essere molteplici) eseguito nell'ordine in cui sono stati registrati prima action

Long risposta :

Un action affari invoca tipicamente un servizio EJB e, se necessario, stabilisce anche il risultato finale e / o naviga verso una visione diversa se non è quello che si sta effettuando un actionListener è cioè più appropriata per quando l'utente interagisce con i componenti, come h:commandButton o h:link essi possono essere gestiti da passare il nome del metodo bean gestito in attributo actionListener di un componente UI o implementare un'interfaccia ActionListener e passare il nome classe di implementazione all'attributo actionListener di un componente UI.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top