问题
I\'m currently evaluating Java EE 6 / JSF 2.1 with RichFaces.
A bean which is declared as
@ManagedBean
@ViewScoped
- Gets an ID set (to prepare e.g. a delete operation).
- Via JSF a confirmation popup is displayed.
- If the user confirms, the delete method is invoked and removes the row for which the ID was stored in step 1.
Since CDI beans don\'t have a ViewScope I tried to declare the bean as:
@Named
@ConversationScoped
Now the processing fails in step 3. because the value that was set in step 1 (checked that) is no longer available.
Do I have to use Conversation.begin()
and Conversation.end()
methods?
If so, where would be good place to invoke them?
回答1:
If you can upgrade to JSF 2.2, immediately do it. It offers a native @ViewScoped annotation for CDI.
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
Alternatively, install OmniFaces which brings its own CDI compatible @ViewScoped, including a working @PreDestroy
(which is broken on JSF @ViewScoped
).
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
Another alternative is to install MyFaces CODI which transparently bridges JSF 2.0/2.1 @ViewScoped
to CDI. This only adds an autogenerated request parameter to the URL (like @ConversationScoped
would do).
import javax.faces.bean.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
If you really need to use @ConversationScoped
, then you indeed need to maunally begin and end it. You need to @Inject
a Conversation and invoke begin()
in the @PostConstruct
and end()
in the latest step of the conversation, usually an action method which redirects to a new view.
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";
}
}
See also:
- How to choose the right bean scope?
回答2:
I think you can benefit from CDI extension to create your own scope so you can implement the context and use the @NormalScope
.
- CDI fires an event
AfterBeanDiscovery
after each bean call - You can use CDI extension to
@Observes
this event and add your context implementation - In your scope implementation you can :
- Use
Contextual
to get your bean by its name fromFacesContext
ViewRoot
Map
and return it after each ajax call back - Use
CreationalContext
if the bean name from first step is not found to create it in theFacesContext
ViewRoot
Map
- Use
For a more in-depth explanation, I recommend this link : http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
回答3:
Inject the conversation into your bean and in the @PostConstructor
method start the conversation if the conversation is transient.
And after deleting the record, end your conversation and navigate to your destination page. When beginning a conversation. Here is an example
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";
}
}
回答4:
There is a project which holds an extentions to the Java EE stack features: DeltaSpike. It is a consolidation of Seam 3, Apache CODI. Above others, it includes the @ViewScoped into CDI. This is an old article and by now it has reached version 1.3.0
回答5:
You can use:
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class PageController implements Serializable {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void execute() {
setValue("value");
}
@PostConstruct
public void init() {
System.out.println("postcontructor");
}
}
来源:https://stackoverflow.com/questions/14384369/how-to-replace-managedbean-viewscope-by-cdi-in-jsf-2-0-2-1