Вызывать метод непосредственно перед истечением сеанса
У моего webapp есть пользователи, которые заходят в систему. Существует тайм-аут. До истечения срока действия сессии я хотел бы выполнить метод для очистки некоторых блокировок.
Я реализовал sessionListener
, но после того, как я дошел до public void sessionDestroyed(HttpSessionEvent event)
, сеанс уже исчез, и мне нужны некоторые данные из него, поэтому я хотел бы выполнить метод (который нуждается в сеансе и доступ к нему FacesConfig.getCurrentInstance()
) до истечения срока действия сеанса.
Как я могу это сделать? Есть идеи? Это мой прослушиватель сеансов:
public class MySessionListener implements HttpSessionListener {
private static final Logger log = LoggerFactory.getLogger(MySessionListener.class);
public MySessionListener() {
}
public void sessionCreated(HttpSessionEvent event) {
log.debug("Current Session created : "
+ event.getSession().getId()+ " at "+ new Date());
}
public void sessionDestroyed(HttpSessionEvent event) {
// get the destroying session...
HttpSession session = event.getSession();
prepareLogoutInfoAndLogoutActiveUser(session);
log.debug("Current Session destroyed :"
+ session.getId()+ " Logging out user...");
/*
* nobody can reach user data after this point because
* session is invalidated already.
* So, get the user data from session and save its
* logout information before losing it.
* User redirection to the timeout page will be
* handled by the SessionTimeoutFilter.
*/
// Only if needed
}
/**
* Clean your logout operations.
*/
public void prepareLogoutInfoAndLogoutActiveUser(HttpSession httpSession) {
UserBean user = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{user}", UserBean.class);
LockBean lock = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{lock}", LockBean.class);
lock.unlock(user.getUsername());
log.info("Unlocked examination for user: "+user.getUsername());
}
}
Но я получаю NullPointerException
в FacesContext.getCurrentInstance().getApplication()
, потому что либо getCurrentInstance
имеет значение null, либо getApplication
возвращает null
Ответы
Ответ 1
Вы можете добиться этого, выполнив HttpSessionBindingListener, вам нужно зарегистрировать сеанс, который содержит блокировку, вызывая registerSession
(строка "sessionBindingListener" не может быть изменена). Контейнер обратится к методу valueUnbound()
после истечения времени ожидания сеанса и до, когда сеанс будет уничтожен.
public class ObjectLock implements Serializable,HttpSessionBindingListener {
public void valueBound(HttpSessionBindingEvent event) {
log.info("valueBound:" + event.getName() + " session:" + event.getSession().getId() );
}
public void registerSession() {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put( "sessionBindingListener", this );
log.info( "registered sessionBindingListener" );
}
public void valueUnbound(HttpSessionBindingEvent event) {
log.info("valueUnBound:" + event.getName() + " session:" + event.getSession().getId() );
// add you unlock code here:
clearLocksForSession( event.getSession().getId() );
}
}
Ответ 2
Еще одно элегантное решение:
Просто добавьте аннотацию @PreDestroy
к сеансу Bean! Если сеанс будет уничтожен, он предварительно вызовет PreDestroy на всех SessionBeans, там вы можете выйти и все!
Хотя в настоящее время это не работает со многими ApplicationServers, кажется, это нечеткий сегмент Спецификации JSF. Таким образом, переход с принятым ответом (HttpSessionBindingListener) будет необходим, пока @PreDestroy не будет работать на всех серверах.