Java动态修改任意用户Session,终极解决方案,锋哥出品
2022/6/17 5:50:25
本文主要是介绍Java动态修改任意用户Session,终极解决方案,锋哥出品,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
社会你“小峰哥“用Java实现了管理员可以修改任意用户Session的功能
、唐城 2021-08-12 19:30:19 阅读数:50 评论数:0 点赞数:0 收藏数:0标签:java管理实现管理员社会 <iframe data-google-container-id="a!2" data-google-query-id="CLaR7aOtsvgCFU3NTAIdEPIAYQ" data-load-complete="true" frameborder="0" height="280" id="aswift_1" marginheight="0" marginwidth="0" name="aswift_1" scrolling="no" src="https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-6520186056508361&output=html&h=280&slotname=5718442022&adk=1989532630&adf=3014641317&pi=t.ma~as.5718442022&w=730&fwrn=4&fwrnh=100&lmt=1655395620&rafmt=1&psa=0&format=730x280&url=https%3A%2F%2Fcopyfuture.com%2Fblogs-details%2F20210812192432416e&fwr=0&fwrattr=true&rpe=1&resp_fmts=3&wgl=1&uach=WyJXaW5kb3dzIiwiMTAuMC4wIiwieDg2IiwiIiwiOTYuMC40NjY0LjExMCIsW10sbnVsbCxudWxsLCI2NCIsW10sZmFsc2Vd&dt=1655395620586&bpp=25&bdt=668&idt=25&shv=r20220614&mjsv=m202206130101&ptt=9&saldr=aa&abxe=1&cookie=ID%3Db64ee4d448dab4a9-22d6b50889d4003d%3AT%3D1655395619%3ART%3D1655395619%3AS%3DALNI_MYb2bPotaTyDhfdhRf1kIkglPWo7Q&gpic=UID%3D000006b33b0bba5b%3AT%3D1655395619%3ART%3D1655395619%3AS%3DALNI_Mbb1Yqy30Eh_L_k9rlEpLiGLxGDxw&prev_fmts=0x0&nras=1&correlator=6781455279298&frm=20&pv=1&ga_vid=1257384511.1655395620&ga_sid=1655395620&ga_hid=1280503765&ga_fc=0&u_tz=480&u_his=1&u_h=864&u_w=1536&u_ah=832&u_aw=1536&u_cd=24&u_sd=1.25&dmc=8&adx=213&ady=298&biw=1536&bih=730&scr_x=0&scr_y=0&eid=44759875%2C44759926%2C44759842%2C44763505%2C31065544%2C31067768%2C31068012%2C21066430%2C31065722%2C31064019&oid=2&pvsid=3481521339727398&tmod=576466466&uas=0&nvt=1&ref=https%3A%2F%2Fcn.bing.com%2F&eae=0&fc=1920&brdim=0%2C0%2C0%2C0%2C1536%2C0%2C1536%2C832%2C1536%2C730&vis=1&rsz=%7C%7CeE%7C&abl=CS&pfx=0&fu=128&bc=31&ifi=2&uci=a!2&fsb=1&xpc=WSgghfgbCT&p=https%3A//copyfuture.com&dtd=31" style="left: 0; position: absolute; top: 0; border: 0; width: 730px; height: 280px" width="730"></iframe>
目录
1 Session会话简介
2 简单实例准备
3 动态修改用户Session场景分析
4 动态修改Session原理介绍
5 动态修改Session实现
6 高并发下的性能优化
7 完整源码+配套视频教程分享
8 留了一点小作业
1 Session会话简介
session 是另一种记录服务器和客户端会话状态的机制,并且session 是基于 cookie 实现的。服务器要知道当前请求发给自己的是谁,为了做这种区分,服务器就是要给每个客户端分配不同的"身份标识",然后客户端每次向服务器发请求的时候,都带上这个“身份标识”。
Cookie是浏览器实现的一种数据存储技术。一般由服务器生成,发送给浏览器(客户端也可进行cookie设置)进行存储,下一次请求同一网站时会把该cookie发送给服务器。
2 简单实例准备
我们做一个简单实例,模拟用户登录,以及获取登录用户信息;
新建一个springboot项目modify-session
,最终目录结构如下:
项目pom.xml
,引入一个web依赖即可;
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.java1234</groupId> <artifactId>modify-session</artifactId> <version>0.0.1-SNAPSHOT</version> <name>modify-session</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
启动类ModifySessionApplication
:
package com.java1234; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ModifySessionApplication { public static void main(String[] args) { SpringApplication.run(ModifySessionApplication.class, args); } }
项目配置文件application.yml
server: port: 80 servlet: context-path: /
用户实体类User
package com.java1234.entity; /** * 用户信息 * @author java1234_小锋 * @site www.java1234.com * @company 南通小锋网络科技有限公司 * @create 2021-08-03 21:14 */ public class User { public Integer id; public String userName; private String password; private String level="common"; // common 普通会员 vip vip会员 public User() { } public User(Integer id, String userName, String password) { this.id = id; this.userName = userName; this.password = password; } 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 getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getLevel() { return level; } public void setLevel(String level) { this.level = level; } }
新建一个UserController,提供两个接口方法,分别是模拟用户登录,和获取用户信息:
package com.java1234.controller; import com.java1234.entity.User; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; /** * 用户controller * @author java1234_小锋 * @site www.java1234.com * @company 南通小锋网络科技有限公司 * @create 2021-08-03 21:10 */ @RestController @RequestMapping("/user") public class UserController { /** * 模拟用户登录 * @return */ @RequestMapping("/login") public String login(HttpSession session){ User uesr=new User(1,"java1234","123456"); session.setAttribute("currentUser",uesr); System.out.println(session.getId()); return "success"; } /** * 获取当前用户信息 * @param session * @return */ @RequestMapping("/getUserInfo") public User getUserInfo(HttpSession session){ return (User)session.getAttribute("currentUser"); } }
我们启动项目;
浏览器地址栏输入:http://localhost/user/login
浏览器地址栏输入:http://localhost/user/getUserInfo 获取用户信息
后端打印出sessionId
我们通过谷歌开发者工具,F12;
后端同时返回了SessionId,作为Cookie;
浏览器地址栏输入:http://localhost/user/getUserInfo
返回用户信息,同时我们看到,请求的时候带了Cookie里的SessionId,去后端查询指定Session信息;
3 动态修改用户Session场景分析
当前用户自身是可以通过sesssion.setAttribute方法修改session信息的。
但是我们在某些情况,业务上要求非自身用户修改Session;
比如管理员后台充值好vip后,数据是修改了,但是登录用户的Session没变化,用户看到的依然是非Vip,需要重新登录后,才能看到vip信息,用户体验就差劲了;如果我们可以动态的去修改任意一个用户的Session信息,那用户无需登录,刷新网页就立即能看到vip信息,那用户体验就上来了。
4 动态修改Session原理介绍
我们终极解决方案如下图:
我们可以创建一个Session监听器,来监听用户Session的创建和销毁事件,所以这里,我们可以去维护一个sessionId
和Session对象关系的存储介质,一般情况下可以用HashMap
,正好是key-value键值对,假如高并发情况,也可以存储到告诉缓存Redis,当然对象的话,注意要序列化;
同时每次用户登录后,我们可以得到userId
和sessionId
,我们也用一个存储介质维护起来,我们这里为了测试方便,用servletContext
全局上下文存储,高并发下,依然要选用Redis存储;
有了以上两个核心的存储介质加上session监听器,我们就可以实现动态修改Session了;
具体步骤如下:
第一步:用户登录,得到sessionId和userId;
第二步:把sessionId和userId存储到servletContext全局上下文,格式 { userId : sessionId } ;
第三步:登录请求触发session监听器的sessonCreated方法;
第四步:sessionCreated方法添加session信息到HashMap,格式 { sessionId : session对象 } ;
第五步:管理员登录,根据userId去servletContext查询sessionId;
第六步:得到sessionId后去hashMap里去查询session对象;
通过以上步骤,得到指定用户的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)注解的类,完成注册
到了这里,我们来测试下监听器是否有效;
启动项目,浏览器地址栏输入:http://localhost/user/login
说明监听器触发成功,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删除;
修改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 模拟登录
浏览器地址栏:http://localhost/user/getUserInfo 获取用户信息
我们另外开一个浏览器地址栏:http://localhost/manager/modifySession 模拟管理员修改session
然后刷新getUserInfo;
我们发现session会话信息变了。测试成功!
6 高并发下的性能优化
在高并发下,同一时刻登录用户会很多,如果把session都放内存,会影响性能,甚至内存溢出;所以session可以存储到redis;
另外如下图的两个存储介质,也要存储到redis,以达到最佳性能;
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功能
https://blog.csdn.net/qq_41570658/article/details/119648674
这篇关于Java动态修改任意用户Session,终极解决方案,锋哥出品的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-07-04TiDB 资源管控的对撞测试以及最佳实践架构
- 2024-07-03万字长文聊聊Web3的组成架构
- 2024-07-02springboot项目无法注册到nacos-icode9专业技术文章分享
- 2024-06-26结对编程到底难不难?答案在这里
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现