Как заменить @ManagedBean/@ViewScope на CDI в JSF 2.0/2.1
В настоящее время я оцениваю Java EE 6/JSF 2.1 с помощью RichFaces.
A bean, который объявлен как
@ManagedBean
@ViewScoped
- Получает набор идентификаторов (для подготовки, например, операции удаления).
- Через JSF отображается всплывающее окно подтверждения.
- Если пользователь подтверждает, вызывается метод удаления и удаляет строку, для которой идентификатор был сохранен на шаге 1.
Поскольку CDI beans не имеет ViewScope, я попытался объявить bean как:
@Named
@ConversationScoped
Теперь обработка завершилась с ошибкой на шаге 3., поскольку значение, которое было установлено на шаге 1 (отмечено этим), больше не доступно.
Нужно ли использовать методы Conversation.begin()
и Conversation.end()
?
Если да, то где было бы хорошим местом для их вызова?
Ответы
Ответ 1
Если вы можете перейти на JSF 2.2, немедленно сделайте это. Он предлагает встроенную аннотацию @ViewScoped
для CDI.
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
В качестве альтернативы установите OmniFaces, который приносит свой собственный CDI-совместимый @ViewScoped
, включая рабочий @PreDestroy
(который разбит на JSF @ViewScoped
).
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
Другой альтернативой является установка MyFaces CODI, который прозрачно соединяет JSF 2.0/2.1 @ViewScoped
с CDI. Это добавляет только параметр автогенерированного запроса в URL (например, @ConversationScoped
).
import javax.faces.bean.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
Если вам действительно нужно использовать @ConversationScoped
, то вам действительно нужно начинать и заканчивать его. Вам нужно @Inject
a Conversation
и вызвать begin()
в @PostConstruct
и end()
на последнем шаге разговора, обычно метод действия, который перенаправляется на новое представление.
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";
}
}
См. также:
Ответ 2
Я думаю, вы можете использовать расширение CDI для создания своей собственной области, чтобы вы могли реализовать контекст и использовать @NormalScope
.
- CDI запускает событие
AfterBeanDiscovery
после каждого вызова bean
- Вы можете использовать расширение CDI для
@Observes
этого события и добавить свою реализацию контекста.
- В рамках вашей реализации вы можете:
- Используйте
Contextual
, чтобы получить bean по имени от FacesContext
ViewRoot
Map
и вернуть его после каждого обратного вызова ajax
- Используйте
CreationalContext
, если имя bean с первого шага не найдено, чтобы создать его в FacesContext
ViewRoot
Map
Для более подробного объяснения я рекомендую эту ссылку: http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
Ответ 3
Ввести разговор в ваш bean и в @PostConstructor
метод начать разговор, если разговор преходящ.
И после удаления записи завершите разговор и перейдите на страницу назначения. При начале разговора. Вот пример
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
Существует проект, который содержит расширения для функций стека Java EE: DeltaSpike. Это консолидация Seam 3, Apache CODI. Помимо других, он включает @ViewScoped в CDI. Это старая статья, и к настоящему времени она достигла версии 1.3.0
Ответ 5
Вы можете использовать:
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");
}
}