web-dev-qa-db-fra.com

Comment remplacer @ManagedBean/@ViewScope par CDI dans JSF 2.0/2.1

J'évalue actuellement Java EE 6/JSF 2.1 avec RichFaces.

Un haricot qui est déclaré comme 

@ManagedBean
@ViewScoped
  1. Obtient un ensemble d'identifiants (pour préparer, par exemple, une opération de suppression).
  2. Via JSF, une fenêtre de confirmation s’affiche.
  3. Si l'utilisateur confirme, la méthode de suppression est appelée et supprime la ligne pour laquelle l'ID a été stocké à l'étape 1.

Comme les beans CDI n’ont pas de ViewScope, j’ai essayé de déclarer le bean comme suit:

@Named
@ConversationScoped

À présent, le traitement échoue à l'étape 3. En effet, la valeur définie à l'étape 1 (cochée) n'est plus disponible. 

Dois-je utiliser les méthodes Conversation.begin() et Conversation.end()?

Si oui, où serait le bon endroit pour les invoquer?

22
stacker

Si vous pouvez passer à JSF 2.2, faites-le immédiatement. Il offre une annotation @ViewScoped native pour CDI.

import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class Bean implements Serializable {
    // ...
}

Vous pouvez également installer OmniFaces qui apporte son propre CDI compatible @ViewScoped , y compris un @PreDestroy qui fonctionne (qui est interrompu sur JSF @ViewScoped).

import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;

@Named
@ViewScoped
public class Bean implements Serializable {
    // ...
}

Une autre solution consiste à installer MyFaces CODI qui relie de manière transparente JSF 2.0/2.1 @ViewScoped à CDI. Cela ajoute uniquement un paramètre de requête généré automatiquement à l'URL (comme le ferait @ConversationScoped).

import javax.faces.bean.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class Bean implements Serializable {
    // ...
}

Si vous devez vraiment utiliser @ConversationScoped, alors vous devez commencer et terminer manuellement. Vous devez @Inject a Conversation et appeler begin() dans les @PostConstruct et end() dans la dernière étape de la conversation, généralement une méthode d'action qui redirige vers une nouvelle vue.

import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;

@Named
@ConversationScoped
public class Bean implements Serializable {

    @Inject
    private Conversation conversation;

    // ...

    @PostConstruct
    public void init() {
        conversation.begin();
    }

    public String submit() {
        // ...

        conversation.end();
        return "some.xhtml?faces-redirect=true";
    }

}

Voir également:

48
BalusC

Je pense que vous pouvez bénéficier de l'extension CDI pour créer votre propre étendue afin de pouvoir implémenter le contexte et utiliser le @NormalScope.

  • Le CDI déclenche un événement AfterBeanDiscovery après chaque appel de haricot
  • Vous pouvez utiliser l'extension CDI pour @Observes cet événement et ajouter votre implémentation de contexte
  • Dans votre implémentation de scope, vous pouvez:
    1. Utilisez Contextual pour obtenir le nom de votre haricot parmi FacesContextViewRootMap et le renvoyer après chaque rappel ajax.
    2. Utilisez CreationalContext si le nom du bean de la première étape n’est pas trouvé pour le créer dans la FacesContextViewRootMap 

Pour une explication plus détaillée, je recommande ce lien: http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/

6
Kurohige

Injectez la conversation dans votre bean et utilisez la méthode @PostConstructor pour démarrer la conversation si la conversation est transitoire.

Et après la suppression de l'enregistrement, mettez fin à la conversation et accédez à la page de destination. Au début d'une conversation. Voici un exemple

public class BaseWebBean implements Serializable {

private final static Logger logger = LoggerFactory.getLogger(BaseWebBean.class);
@Inject
protected Conversation conversation;

@PostConstruct
protected void initBean(){
}

public void continueOrInitConversation() {
        if (conversation.isTransient()) {
            conversation.begin();
            logger.trace("conversation with id {} has started by {}.", conversation.getId(), getClass().getName());
        }
    }

public void endConversationIfContinuing() {
        if (!conversation.isTransient()) {
            logger.trace("conversation with id {} has ended by {}.", conversation.getId(), getClass().getName());
            conversation.end();
        }
}

}

@ConversationScoped
@Named
public class yourBean extends BaseWebBean implements Serializable {
    @PostConstruct
    public void initBean() {
        super.initBean();
        continueOrInitConversation();
    }

    public String deleteRow(Row row)
    {
        /*delete your row here*/
        endConversationIfContinuing();
        return "yourDestinationPageAfter removal";
    }

}
3
cubbuk

Il existe un projet qui étend les fonctionnalités de la pile Java EE: DeltaSpike . C'est une consolidation de Seam 3, Apache CODI. Au-dessus des autres, il inclut le @ViewScoped dans CDI. Ceci est un ancien article qui a atteint la version 1.3.0.

0
Endrik