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对象后,就可以任意操作了;