有时候我们在做登录模块过程中难免会遇到这种问题,即使我们给用户进行了多重判断,比如:用户名,管理员,验证码,一系列的判断… 你是否真正考虑到用户的体验,比如不能让用户在同一时间,同一个浏览器重复登录问题,同时也包括不同浏览器登录(异地登录)问题。
这些都是我们应该去考虑的。如果是用Spring 框架的话,Spring security 是可以实现防止用户重复登录的问题的,但我这里并没有用到框架,因为我这里不需要做太高的限制。
我们可以利用 Servlet三大域对象 request、session、application(ServletContext)中的ServletContext,它是一个全局的储存信息的空间,服务器启动后就被创建,服务器停止后才销毁。
request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。
思路:我们将用户的登录信息保存在context里, 然后利用监听器HttpSessionListener监听每一个登录用户的登录情况,实时监控session。
Servlet:
/*登录方法*/
public void login(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
String username = request.getParameter("username");//登录名
String password = request.getParameter("password");//密码
HttpSession session=request.getSession();
response.setCharacterEncoding("UTF-8");
PrintWriter out=response.getWriter();
SystemUsertable usertable = service.login(username);//SystemUsertable 自己封装存放用户信息的类
if (usertable != null) {
if (usertable.getPassword().equals(password)) {
session.setAttribute("userid", usertable.getUserid());
session.setAttribute("username", usertable.getUsername());
} else {
out.write("<html><head><meta charset='utf-8'></head><script>alert('密码错误');window.location.href='../jsp/login.jsp';</script>");
}
}else {
out.write("<html><head><meta charset='utf-8'></head><script>alert('用户不存在');window.location.href='../jsp/login.jsp';</script>");
}
ServletContext context = session.getServletContext();
@SuppressWarnings("unchecked")
Map<String, Object> loginMap = (Map<String, Object>) context.getAttribute("loginMap");
if (loginMap == null) {
loginMap = new HashMap<String, Object>();
}
for (String key : loginMap.keySet()) {
int result=usertable.getUserid();
String day = "";
day = String.valueOf(result);
if (day.equals(key)) {
if (session.getId().equals(loginMap.get(key))) {
out.write("<html><head><meta charset='utf-8'></head><script>alert('在同一地点重复登录');window.location.href='../jsp/login.jsp';</script>");
} else {
out.write("<html><head><meta charset='utf-8'></head><script>alert('异地已登录,请先退出登录');window.location.href='../jsp/login.jsp';</script>");
}
}else{
}
}
loginMap.put(String.valueOf(usertable.getUserid()),session.getId());
context.setAttribute("loginMap", loginMap);
// 将用户保存在session当中
session.setAttribute("usertable", usertable);
// session 销毁时间
session.setMaxInactiveInterval(10*60);
out.write("<html><head><meta charset='utf-8'></head><script>alert('登录成功');window.location.href='../jsp/main.jsp';</script>");
}
这时候我们需要写一个监听器,监听每一个登录用户的登录情况。首先去web.xml 配置监听器:
/*监听器存放路径*/
<listener>
<listener-class>
com.day.listener.SessionListener
</listener-class>
</listener>
Listener:
/*监听器*/
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {//创建
// TODO Auto-generated method stub
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {//销毁
// TODO Auto-generated method stub
HttpSession session = httpSessionEvent.getSession();
SystemUsertable user = (SystemUsertable) session.getAttribute("usertable");
if (user != null) {
ServletContext application = session.getServletContext();
@SuppressWarnings("unchecked")
Map<String, Object> loginMap = (Map<String, Object>) application.getAttribute("loginMap");
loginMap.remove(user.getUserid());
application.setAttribute("loginMap", loginMap);
session.removeAttribute("usertable");
}
}
}
最后需要对它的退出登录进行处理,退出时销毁session, 清除用户登录信息。
/*退出登录*/
public void loginOut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
HttpSession session = request.getSession();
String id = session.getId();
if (session != null) {
try {
session.removeAttribute("usertable");
String user= id;
if (session.getAttribute(user) != null) {
session.removeAttribute(user);
}
ServletContext context = session.getServletContext();
@SuppressWarnings("unchecked")
Map<String, Object> loginMap = (Map<String, Object>) context.getAttribute("loginMap");
if (loginMap != null) {
loginMap = new HashMap<String, Object>();
}
context.setAttribute("loginMap", loginMap);
} catch (Exception e) {
e.printStackTrace();
}
}
request.getRequestDispatcher("/jsp/login.jsp").forward(request, response);
}
这样子就可以把登录的用户信息清除掉,用户可去其他浏览器登录亦或是继续登录。其实,这些大多可以根据自己的需求而定,代码可以是固定的,但思想是活的。