我正在使用带有Richfaces和Facelets的JSF 1.2。
我有一个包含许多会话范围的bean和一些应用程序bean的应用程序。
用户使用Firefox登录。创建一个ID =“A”的会话; 然后他打开Chrome并使用相同的凭据再次登录。创建一个ID =“B”的会话。
创建会话“B”时,我希望能够销毁会话“A”。怎么做?
另外。当Firefox中的用户做任何事情时,我希望能够显示一个弹出窗口或某种通知,说“你已经登出,因为你已经从其他地方登录了”。
我有一个sessionListener,可以跟踪创建和销毁的会话。问题是,我可以将HTTPSession对象保存在应用程序范围的bean中,并在检测到用户已登录两次时将其销毁。但有些东西告诉我这是错的,不会奏效。
JSF是否跟踪服务器端某处的会话?如何通过标识符访问它们?如果没有,如何在用户登录两次时首次登录?
答案 0 :(得分:20)
独立于数据库的方法是让User
拥有static Map<User, HttpSession>
变量并实施HttpSessionBindingListener
(以及Object#equals()
和Object#hashCode()
)。这样你的webapp仍会在意外崩溃后仍然可以运行,这可能导致数据库值不会更新(当然你可以创建一个ServletContextListener
来重置webapp启动时的数据库,但这只是越来越多的工作)。
以下是User
的外观:
public class User implements HttpSessionBindingListener {
// All logins.
private static Map<User, HttpSession> logins = new ConcurrentHashMap<>();
// Normal properties.
private Long id;
private String username;
// Etc.. Of course with public getters+setters.
@Override
public boolean equals(Object other) {
return (other instanceof User) && (id != null) ? id.equals(((User) other).id) : (other == this);
}
@Override
public int hashCode() {
return (id != null) ? (this.getClass().hashCode() + id.hashCode()) : super.hashCode();
}
@Override
public void valueBound(HttpSessionBindingEvent event) {
HttpSession session = logins.remove(this);
if (session != null) {
session.invalidate();
}
logins.put(this, event.getSession());
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
logins.remove(this);
}
}
当您按如下方式登录User
时:
User user = userDAO.find(username, password);
if (user != null) {
sessionMap.put("user", user);
} else {
// Show error.
}
然后它将调用valueBound()
,它将从logins
地图中删除任何先前登录的用户并使会话无效。
当您按如下方式退出User
时:
sessionMap.remove("user");
或当会话超时时,将调用valueUnbound()
,从logins
地图中移除用户。
答案 1 :(得分:4)
userLoggedInCount
invalidate()
会话并递减数据库中的值< / LI>
答案 2 :(得分:1)
我喜欢BalusC使用HttpSessionBindingListener的答案。
但是在Enterprise JavaBeansTM Specification,Version 2.0中写道:
企业Bean不得使用读/写静态字段。使用只读静态字段是 允许。因此,建议企业bean类中的所有静态字段都是 宣布为最终
因此,如果不使用静态字段来创建一个存储表应用程序范围的ApplicationScoped Bean,那不是更好吗???
它尝试了它似乎工作...
以下是我的例子:
@Named
@ApplicationScoped
public class UserSessionStorage implements java.io.Serializable,HttpSessionBindingListener {
@Inject
UserManagement userManagement;
private static final long serialVersionUID = 1L;
/**
* Application wide storage of the logins
*/
private final Map<User, List<HttpSession>> logins = new HashMap<User, List<HttpSession>>();
@Override
public void valueBound(final HttpSessionBindingEvent event) {
System.out.println("valueBound");
/**
* Get current user from userManagement...
*/
User currentUser = userManagement.getCurrentUser();
List<HttpSession> sessions = logins.get(currentUser);
if (sessions != null) {
for (HttpSession httpSession : sessions) {
httpSession.setAttribute("invalid", "viewExpired");
}
} else {
sessions = new ArrayList<HttpSession>();
}
HttpSession currentSession = event.getSession();
sessions.add(currentSession);
logins.put(currentUser, sessions);
}
@Override
public void valueUnbound(final HttpSessionBindingEvent event) {
System.out.println("valueUnbound");
User currentUser = userManagement.getCurrentUser();
List<HttpSession> sessions = logins.get(currentUser);
if (sessions != null) {
sessions.remove(event.getSession());
} else {
sessions = new ArrayList<HttpSession>();
}
logins.put(currentUser, sessions);
}
}
- &GT;对不起我的änglish...