社会你“小峰哥“用Java实现了管理员可以修改任意用户Session的功能 下

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 社会你“小峰哥“用Java实现了管理员可以修改任意用户Session的功能 下

5 动态修改Session实现

我们来实现下具体代码:

我们定义一个自定义session上下文MySessionContext,里面定义HashMap属性来存储session信息,格式 sessionId :session对象;

package com.java1234.custom;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
/**
 * 自定义session上下文
 * @author java1234_小锋
 * @site www.java1234.com
 * @company 南通小锋网络科技有限公司
 * @create 2021-08-05 10:39
 */
public class MySessionContext {
    private static MySessionContext instance;
    // session map存储session  如果session较多,影响到系统性能的话,可以把用redis,key-value  sessionId->session对象 session对象序列化
    public static HashMap<String,HttpSession> sessionMap;
    private MySessionContext() {
        sessionMap = new HashMap<String,HttpSession>();
    }
    /**
     * 单例
     * @return
     */
    public static MySessionContext getInstance() {
        if (instance == null) {
            instance = new MySessionContext();
        }
        return instance;
    }
    /**
     * 添加session
     * @param session
     */
    public synchronized void addSession(HttpSession session) {
        if (session != null) {
            System.out.println("session添加成功!");
            sessionMap.put(session.getId(), session);
        }
    }
    /**
     * 删除session
     * @param session
     */
    public synchronized void delSession(HttpSession session) {
        if (session != null) {
            System.out.println("session删除成功!");
            sessionMap.remove(session.getId());
        }
    }
    /**
     * 根据sessionId获取session
     * @param sessionID
     * @return
     */
    public synchronized HttpSession getSession(String sessionID) {
        if (sessionID == null) {
            return null;
        }
        return sessionMap.get(sessionID);
    }
}

新建session监听器SessionListener,监听session创建和销毁;

session创建的时候,把session信息存储到自定义session上下文;session销毁时,自定义session上下文中也删除掉该session;

注意,要加@WebListener注解

package com.java1234.listener;
import com.java1234.custom.MySessionContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
 * session监听器
 * @author java1234_小锋
 * @site www.java1234.com
 * @company 南通小锋网络科技有限公司
 * @create 2021-08-05 10:43
 */
@WebListener
public class SessionListener implements HttpSessionListener {
    // 获取自定义session上下文实例
    private MySessionContext msc = MySessionContext.getInstance();
    /**
     * session创建事件
     * @param se
     */
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("session创建");
        HttpSession session = se.getSession();
        msc.addSession(session);  // 添加当前session到自定义session上下文
    }
    /**
     * session销毁事件
     * @param se
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("session销毁");
        HttpSession session = se.getSession();
        //todo 要从数据库或者redis缓存把指定sessionId的用户session信息删除
        msc.delSession(session);  // 从自定义session上下文里删除当前session
    }
}

在springboot项目中,要使得监听器有效,我们启动类要加@ServletComponentScan注解

@ServletComponentScan,自动扫描带有(@WebServlet, @WebFilter, and @WebListener)注解的类,完成注册

0c813e62b50201f45ec8548cfbac701.png

到了这里,我们来测试下监听器是否有效;

启动项目,浏览器地址栏输入:http://localhost/user/login

2e79a83fa6fa4c3b3bee63183e65bd3.png

说明监听器触发成功,session添加成功!

session的销毁方法触发,有以下三种方式;

1、超时(一般服务器设置超时时间为30分钟)服务器会销毁session;

2、点击控制台的红色按钮异常关闭服务器要销毁session

3、手动调用session的invalidate方法session.invalidate();

为了演示,我把session有效期设置成30秒;

server:
  port: 80
  servlet:
    context-path: /
    session:
      timeout: 30s

我们执行模拟登录30秒后,只要不继续请求操作,30秒后,触发session销毁事件,session删除;

2e79a83fa6fa4c3b3bee63183e65bd3.png

修改UserController,通过session获取servletContext上下文,存储用户session信息,格式 { userId : sessionId }

/**
     * 模拟用户登录
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpSession session){
        User uesr=new User(1,"java1234","123456");
        session.setAttribute("currentUser",uesr);
        System.out.println(session.getId());
        ServletContext servletContext = session.getServletContext();
        // 模拟存储用户session信息到数据库 用application模拟
        servletContext.setAttribute(String.valueOf(uesr.getId()),session.getId()); // key-value 用户id-sessionId
        return "success";
    }

创建ManagerController测试:

package com.java1234.controller;
import com.java1234.custom.MySessionContext;
import com.java1234.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
/**
 * 管理员Controller控制器
 * @author java1234_小锋
 * @site www.java1234.com
 * @company 南通小锋网络科技有限公司
 * @create 2021-08-07 23:05
 */
@RequestMapping("/manager")
@RestController
public class ManagerController {
    /**
     * 模拟用户登录
     * @return
     */
    @RequestMapping("/modifySession")
    public String modifySession(HttpSession session){
        ServletContext servletContext = session.getServletContext();
        String userId="1"; // 修改userId=1的用户
        String sessionId = (String)servletContext.getAttribute(userId);  // 从servletContext上下文 根据userId获取sessionId
        System.out.println("sessionId:"+sessionId);
        HashMap<String, HttpSession> sessionMap = MySessionContext.sessionMap; // 获取sessionMap
        HttpSession currentSession = sessionMap.get(sessionId); // 根据sessionId获取用户session
        User user = (User)currentSession.getAttribute("currentUser"); // 根据session得到用户信息
        user.setLevel("vip"); // 修改内容
        return "success";
    }
}

浏览器地址栏:http://localhost/user/login 模拟登录


浏览器地126b3723a5b3439b201dcd91ca10a09.png址栏:http://localhost/user/getUserInfo 获取用户信息

df65e1a0f8a26d590936d5210d00fe7.png

我们另外开一个浏览器地址栏:http://localhost/manager/modifySession 模拟管理员修改session

c0af42081778f09ac9e2b8e81213e6e.png

然后刷新getUserInfo;

18e48cca88f0a0c2bcfe7e3b449c685.png

我们发现session会话信息变了。测试成功!

6 高并发下的性能优化

在高并发下,同一时刻登录用户会很多,如果把session都放内存,会影响性能,甚至内存溢出;所以session可以存储到redis;

另外如下图的两个存储介质,也要存储到redis,以达到最佳性能;

810cba2134eeec163c667115c6ebf38.png

7 完整源码+配套视频教程分享

源码和文档+视频我放在了Github和码云上面,大家有需要参考源码的直接pull下,IDEA工具;

码云地址:https://gitee.com/java_1234/modify-session

Github地址: https://github.com/java1234/modify-session

8 留了一点小作业

如果你是一个有理想的程序员,不妨可以升级下锋哥的实例;

第一:搭建一个高可用的redis集群环境;

第二:springboot+redis实现session存储到redis高速缓存;

第三:如上图的两个存储介质也存储到redis;

原文地址:老板发了我2千奖金,原因是我用Java实现管理员可以修改任意用户Session功能

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
运维 监控 JavaScript
JAVA村卫生室、诊所云HIS系统源码 支持医保功能
运维运营分系统 1、系统运维:环境管理、应用管理、菜单管理、接口管理、任务管理、配置管理 2、综合监管:统计监管的医疗机构的综合信息,包括医疗业务量、人员配备量、支付分类占比等。 3、系统运营:机构管理、药品目录管理、用户管理、角色管理、字典管理、模板管理、消息管理、运营配置、售后服务、外部系统。
29 0
|
1月前
|
Java
【Java每日一题】— —第二十一题:编程把现实生活的手机事物映射成一个标准类Phone,并定义一个测试类PhoneDemo测试Phone类的功能
【Java每日一题】— —第二十一题:编程把现实生活的手机事物映射成一个标准类Phone,并定义一个测试类PhoneDemo测试Phone类的功能
36 0
|
3月前
|
JavaScript 小程序 Java
基于Java的高校宣讲会管理系统设计与实现(亮点:选题新颖、功能实用、老师看见直接过!)
基于Java的高校宣讲会管理系统设计与实现(亮点:选题新颖、功能实用、老师看见直接过!)
22 0
|
1月前
|
安全 Java 数据库连接
【Java每日一题】——第四十四题:综合案例:编程模拟智能手机和普通手机功能。
【Java每日一题】——第四十四题:综合案例:编程模拟智能手机和普通手机功能。
44 0
|
1月前
|
存储 Java API
Java统计功能
Java统计功能
14 0
|
1月前
|
存储 搜索推荐 Java
Java筛选功能的秘密
Java筛选功能的秘密
12 0
|
1月前
|
存储 算法 安全
Java代码能实现这些隐藏的加密功能
Java代码能实现这些隐藏的加密功能
58 0
|
1月前
|
Java
Java代码打造直播互动功能
Java代码打造直播互动功能
11 1