Я использую JBoss6.1.Final, JSF 2.0 (Mojarra), Weld CDI, MyFaces CODI 1.0.5 (для просмотра-доступа к области видимости)SFSB удаляется
Я использую что-то вроде шлюза Шаблон от Real World Java EE Patterns Rethinking Best Practices (к сожалению, у меня его нет, поэтому я, возможно, что-то прикрутил). В принципе, приложение позволяет пользователю перейти в «режим редактирования» и отредактировать список людей (создавать, редактировать, удалять), поддерживаемые в фонотеке @ViewAccessScoped с расширенным контекстом персистентности, а затем щелкнуть ссылку «сохранить», которая сбрасывается все их изменения в базе данных. Сначала у меня возникла проблема с ViewExpiredExceptions (если браузер простаивал за период ожидания сеанса, а затем выполнялся дальнейший запрос), но я добавил некоторый jQuery, чтобы сделать запрос на получение сервлета, который поддерживает сеанс (10 секунд до таймаута сессии). Кажется, что это работает, но теперь у меня есть другая проблема: бэк-файл также является SFSB, и после некоторого времени простоя он удаляется, в результате чего записывается следующее сообщение об ошибке (и все данные, обработанные ajax, исчезают) при попытке выполнить больше изменений ...
13: 06: 22,063 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] javax.el.ELException: /index.xhtml @ 27,81 rendered = "# {! talkBean. Editmode} ": javax.ejb.NoSuchEJBException: не удалось найти компонент с учетом состояния: 43h1h2f-9c7qkb-h34t0f34-1-h34teo9p-де
Любые идеи о том, как я мог бы предотвратить удаление SFSB или, по крайней мере, справиться с этим более изящно?
Вот моя поддержка боб:
package com.ray.named;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJBTransactionRolledbackException;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.ViewAccessScoped;
import com.ray.model.Person;
@Named
@Stateful
@ViewAccessScoped
@TransactionAttribute(javax.ejb.TransactionAttributeType.NEVER)
public class ConversationBean implements Serializable {
private static final long serialVersionUID = 1L;
//properties
private List<Person> people;
private String name;
private Boolean editMode;
@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
@PostConstruct
public void init() {
people = em.createNamedQuery("Person.findAll", Person.class).getResultList();
setEditMode(false);
}
//event listeners
public void beginEdits() {
setEditMode(true);
}
public void addPerson() {
Person p = new Person(name);
em.persist(p);
people.add(p);
name = null;
}
public void removePerson(Person p) {
people.remove(people.indexOf(p));
em.remove(p);
}
//this method flushes the persistence context to the database
@TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRES_NEW)
public void saveEdits() {
setEditMode(false);
}
//getters/setters
public List<Person> getPeople() {
return people;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getEditMode() {
return editMode;
}
public void setEditMode(Boolean editMode) {
this.editMode = editMode;
}
}
Вот Person бин сущности:
package com.ray.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Version;
@Entity
@NamedQueries({
@NamedQuery(name="Person.findAll",
query="SELECT p FROM Person p")
})
public class Person {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
@Version
private int version;
public Person() { }
public Person(String name) {
setName(name);
}
public boolean equals(Object o) {
if (!(o instanceof Person)) {
return false;
}
return id == ((Person)o).id;
}
//getters/setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
}
Вот мнение:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function() {
setInterval(function() {
$.get("#{request.contextPath}/poll");
}, #{(session.maxInactiveInterval - 10) * 1000});
});
</script>
<title>Conversation Test</title>
</h:head>
<h:body>
<h:form>
<h:commandLink value="Begin Edits" rendered="#{!conversationBean.editMode}">
<f:ajax render="@form" listener="#{conversationBean.beginEdits}"/>
</h:commandLink>
<h:commandLink value="Save" rendered="#{conversationBean.editMode}">
<f:ajax render="@form" listener="#{conversationBean.saveEdits}"/>
</h:commandLink>
<h:dataTable id="peopleTable" value="#{conversationBean.people}" var="person">
<h:column>
<f:facet name="header">Name</f:facet>
<h:panelGroup>
<h:inputText value="#{person.name}" disabled="#{!conversationBean.editMode}">
<f:ajax/>
</h:inputText>
<h:commandLink value="X" disabled="#{!conversationBean.editMode}">
<f:ajax render="@form" listener="#{conversationBean.removePerson(person)}"/>
</h:commandLink>
</h:panelGroup>
</h:column>
</h:dataTable>
<h:panelGrid columns="2">
<h:outputLabel for="name">Name:</h:outputLabel>
<h:inputText id="name" value="#{conversationBean.name}" disabled="#{!conversationBean.editMode}"/>
</h:panelGrid>
<h:commandButton value="Add" disabled="#{!conversationBean.editMode}">
<f:ajax execute="@form" render="@form" listener="#{conversationBean.addPerson}"/>
</h:commandButton>
</h:form>
</h:body>
</html>
Вот сервлет используется для поддержания сеанса в живых (вызванный jQuery ajax получить запрос за 10 секунд до окончания сессии):
package com.ray.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class PollServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void init() throws ServletException {
}
public String getServletInfo() {
return null;
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.getSession(); //Keep session alive
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
}
public void destroy() {
}
}
Спасибо еще раз января Просто любопытно, видите ли вы что-нибудь недостатки с моим примером кода? Есть ли что-то, что бы вы сделали по-другому? – JasonI
Я добавил аннотированный метод @PrePassivate и мог видеть, что компонент бэканга/сеанса действительно пассивировался. Я экспериментирую с RichFaces a4j: poll с интервалом в 10 секунд меньше, чем session.maxInactiveInterval, и это, похоже, делает трюк. Сеанс остается в живых до тех пор, пока открыто окно браузера. – JasonI
@Jasonl (# 1) Нет, в коде нет ничего плохого. Я не могу выразить себя лучше, как я уже сделал в ответ ... –