Java使用监听器和Token完成单态登录

在门户网站一般都有这样的一个功能,你用另外一个设备或者在另一个网站登录,前一次登录的状态将会被挤下去。今天我们就使用监听器来实现这个功能。
主要的思路就是,在监听器内部建立一个map,key为当前登录用户信息计算出的token,value为对的会话session,如果需要对session的数据进行增删改则会触发监听器,判断用户是否已经登录,如果登录了,那么就在对印的session中删除用户登录信息。

工具类

package com.openlab.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtil {
    private static final ThreadLocal<SqlSession> SQLSESSION = new ThreadLocal<>();
    private static SqlSessionFactory factory;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private MybatisUtil(){

    }
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = SQLSESSION.get();
        if (sqlSession == null){
            SQLSESSION.set(factory.openSession());
            return SQLSESSION.get();
        }else {
            return sqlSession;
        }
    }

    public static void close(){
        SqlSession sqlSession = SQLSESSION.get();
        if (sqlSession!=null){
            sqlSession.close();
            SQLSESSION.set(null);
        }
    }
}

package com.openlab.utils;

import com.openlab.pojo.User;

public class TokenUtil {
    private TokenUtil(){

    }
    //简单实现以下生成Token
    public static String getToken(User user){
        return user.hashCode()+"";
    }
}

实体类

package com.openlab.pojo;

import java.util.Objects;

public class User {
    private Integer id;
    private String userName;
    private String userPassword;
    private String phone;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) &&
                Objects.equals(userName, user.userName) &&
                Objects.equals(userPassword, user.userPassword) &&
                Objects.equals(phone, user.phone);
    }

    @Override
    public int hashCode() {

        return Objects.hash(id, userName, userPassword, phone);
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", userPassword='" + userPassword + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

映射文件和接口

package com.openlab.mapper;

import com.openlab.pojo.User;
import org.apache.ibatis.annotations.Param;

public interface UserMapper {

    public User queryForLogin(@Param("userName") String userName,
                              @Param("password") String password);
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.openlab.mapper.UserMapper">
    <select id="queryForLogin" resultType="User">
        SELECT
        id,userName,userPassword,phone
        FROM
        smbms_user
        WHERE
        userName=#{userName} AND userPassword=#{password}
    </select>
</mapper>

servlet

package com.openlab.servlet;

import com.openlab.mapper.UserMapper;
import com.openlab.pojo.User;
import com.openlab.utils.MybatisUtil;
import org.apache.ibatis.session.SqlSession;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "LoginServlet",value = "/login.do")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        String userName = request.getParameter("userName");
        String password = request.getParameter("password");
        User user = mapper.queryForLogin(userName, password);
        if (user != null){
            request.getSession().setAttribute("user",user);
            response.sendRedirect(request.getContextPath()+"/info.jsp");
        }else {
            request.setAttribute("error","用户名密码不正确");
            request.getRequestDispatcher("login.jsp").forward(request,response);
        }

    }
}

监听器

package com.openlab.listen;
import com.openlab.pojo.User;
import com.openlab.utils.TokenUtil;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.util.HashMap;
@WebListener
public class LoginStateListen implements HttpSessionAttributeListener {
    private static HashMap<String,HttpSession> map = new HashMap<>();
    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        HttpSession session = httpSessionBindingEvent.getSession();//当前添加用户的session
        String name = httpSessionBindingEvent.getName();

        if ("user".equals(name)){
            User user = (User)httpSessionBindingEvent.getValue();
            String token = TokenUtil.getToken(user);
            if (map.containsKey(token)){//说明之前已经登录了
                HttpSession oldSession = map.get(token);
                oldSession.removeAttribute("user");
                map.put(token,session);
            }else {
                //之前没有登录
                map.put(token,session);
            }
        }else {

        }
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        HttpSession session = httpSessionBindingEvent.getSession();
        String name = httpSessionBindingEvent.getName();
        if ("user".equals(name)){
            //是需要删除user
            String token = TokenUtil.getToken((User) httpSessionBindingEvent.getValue());
            map.remove(token);
        }
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        String name = httpSessionBindingEvent.getName();
        if ("user".equals(name)){
            HttpSession session = httpSessionBindingEvent.getSession();
            User user = (User) httpSessionBindingEvent.getValue();//以前的值
            String oldToken = TokenUtil.getToken(user);
            map.remove(oldToken);//移除以前的记录
            User newUser = (User) session.getAttribute("user");
            String newToken = TokenUtil.getToken(newUser);
            map.put(newToken,session);
        }
    }
}

前端页面

<%--
  Created by IntelliJ IDEA.
  User: 上杉
  Date: 2020/8/11
  Time: 15:00
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>用户登录</h3>
<form action="${pageContext.request.contextPath}/login.do" method="post">
    <label for="userName">用户名</label><input type="text" id="userName" name="userName" ><br/>
    <label for="password">&nbsp;</label><input type="password" id="password" name="password"><br>
    <p style="color: red">${error}</p>
    <input type="submit" value="登录">
</form>

</body>
</html>

<%@ page import="java.util.Date" %><%--
  Created by IntelliJ IDEA.
  User: 上杉
  Date: 2020/8/11
  Time: 15:23
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--每三秒检测一次登录状态--%>
    <script>setTimeout("location=location;",3000)</script>
    <c:if test="${user!=null}">
        <h1>恭喜您成功登录</h1>
        <p>${user}</p>
    </c:if>
    <c:if test="${user==null}">
        您的账号已经在别处登录,已经强制下线<br>
        <a href="login.jsp">返回登录</a>
    </c:if>
</body>
</html>

结果测试

我们先在谷歌浏览器打开登录页面
在这里插入图片描述
登录成功的页面
在这里插入图片描述

接下来我们再从火狐浏览器进行登录
在这里插入图片描述
登录成功后,我们返回谷歌浏览器查看
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值