Recently I have a requirement to update User's online status when user's session timeout. The key point is to get User's id to update his online status.
Though I had written a session listener to listen session destroyed event, I cannot get the User object which is stored in Session as an attribute, because everything had been destroyed except for the sessionId. I come across the same problem as the one on StackOverflow : Session Handling Issue(To update DB row) - Session closes along with browser
I come up with a solution, define a Spring bean which contains only a ConcurrentHashMap property, when user logins, put sessionId as key and user's Id as value. When user logouts actively or got logout proactively at the time session timeout, get sessionId from Session Timout Event, then get userId from ConcurrentHashMap by sessionId, update DB, then remove the entry from ConcurrentHashMap.
Code of defining Spring bean contains ConcurrentHashMap:
@Component
public class SessionUserMap {
private ConcurrentHashMap<String, Integer> userMap = new ConcurrentHashMap<>();
public ConcurrentHashMap<String, Integer> getUserMap() {
return userMap;
}
public void setUserMap(ConcurrentHashMap<String, Integer> userMap) {
this.userMap = userMap;
}
}
Should put userId to this ConcurrentHashMap when user logins.
Then write DB update logic in Session Listener:
public class CmsSessionListener implements HttpSessionListener {
private static final Logger logger = Logger.getLogger(CmsSessionListener.class);
@Override
public void sessionCreated(HttpSessionEvent se) {
logger.debug("session created." + se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
User user = (User)session.getAttribute(CmsConstants.SESSION_ATTR_USER);
if (user == null){
logger.debug("Had invoked session.invalidated().");
}
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean("jdbcTemplate");
SessionUserMap userMap = (SessionUserMap)context.getBean("sessionUserMap");
logger.debug("Session timeout or user logouts, update user's online status.");
jdbcTemplate.execute("update t_c_user set online = 0 where id = "
+ userMap.getUserMap().get(session.getId()));
userMap.getUserMap().remove(session.getId());
logger.debug(user.getFullName() + "exits system.");
}
}