Redis实现用户会话

1.分布式会话

(1)什么是会话

会话Session代表的是客户端与服务器的一次交互过程,这个过程可以是连续也可以是时断时续的。曾经的Servlet时代(jsp),一旦用户与服务端交互,服务器tomcat就会为用户创建一个session,同时前端会有一个jsessionid,每次交互都会携带。如此一来,服务器只要在接到用户请求时候,就可以拿到jsessionid,并根据这个ID在内存中找到对应的会话session,当拿到session会话后,那么我们就可以操作会话了。会话存活期间,我们就能认为用户一直处于正在使用着网站的状态,一旦session超期过时,那么就可以认为用户已经离开网站,停止交互了。用户的身份信息,我们也是通过session来判断的,在session中可以保存不同用户的信息。

示例代码如下:

java 复制代码
@GetMapping("/setSession")
public Object setSession(HttpServletRequest request) {
    HttpSession session = request.getSession();
    session.setAttribute("userInfo", "new user");
    session.setMaxInactiveInterval(3600);
    session.getAttribute("userInfo");
    // session.removeAttribute("userInfo");
    return "ok";
}

(2)无状态会话

HTTP请求是无状态的,用户向服务端发起多个请求,服务端并不会知道这多次请求都是来自同一用户,这个就是无状态的。cookie的出现就是为了有状态的记录用户。

常见的,ios与服务端交互,安卓与服务端交互,前后端分离,小程序与服务端交互,他们都是通过发起http来调用接口数据的,每次交互服务端都不会拿到客户端的状态,但是我们可以通过手段去处理,比如每次用户发起请求的时候携带一个userid或者user-token,如此一来,就能让服务端根据用户id或token来获得相应的数据。每个用户的下一次请求都能被服务端识别来自同一个用户。

(3)有状态会话

Tomcat中的会话,就是有状态的,一旦用户和服务端交互,就有会话,会话保存了用户的信息,这样用户就"有状态"了,服务端会和每个客户端都保持着这样的一层关系,这个由容器来管理(也就是tomcat),这个session会话是保存到内存空间里的,如此一来,当不同的用户访问服务端,那么就能通过会话知道谁是谁了。tomcat会话的出现也是为了让http请求变的有状态。如果用户不再和服务端交互,那么会话超时则消失,结束了他的生命周期。如此一来,每个用户其实都会有一个会话被维护,这就是有状态会话。

场景:在传统项目或者jsp项目中是使用的最多的session都是有状态的,session的存在就是为了弥补http的无状态。

注:tomcat会话可以通过手段实现多系统之间的状态同步,但是会损耗一定的时间,一旦发生同步那么用户请求就会等待,这种做法不可取。

(4)单Tomcat会话(图)

先来看一下单个tomcat会话,这个就是有状态的,用户首次访问服务端,这个时候会话产生,并且会设置jsessionid放入cookie中,后续每次请求都会携带jsessionid以保持用户状态。

(5)动静分离会话(图)

用户请求服务端,由于动静分离,前端发起http请求,不会携带任何状态,当用户第一次请求以后,我们手动设置一个token,作为用户会话,放入redis中,如此作为redis-session,并且这个token设置后放入前端cookie中(app或小程序可以放入本地缓存),如此后续交互过程中,前端只需要传递token给后端,后端就能识别这个用户请求来自谁了。

(6)集群分布式系统会话(图)

集群或分布式系统本质都是多个系统,假设这个里有两个服务器节点,分别是AB系统,他们可以是集群,也可以是分布式系统,一开始用户和A系统交互,那么这个时候的用户状态,我们可以保存到redis中,作为A系统的会话信息,随后用户的请求进入到了B系统,那么B系统中的会话我也同样和redis关联,如此AB系统的session就统一了。当然cookie是会随着用户的访问携带过来的。那么这个其实就是分布式会话,通过redis来保存用户的状态。

(7)类似关系:局部变量与全局变量

Tomcat会话相当于一个类中某个方法的局部变量,只能在当前方法中使用;分布式会话相当于一个类中的公用全局变量,可以被类中诸多方法使用。如下代码:

public class DistributedClusterTest {

复制代码
public String distributedSession = "global-1001";

public void UserSystem() {
    String userSession = "user-2001";

    System.out.println(distributedSession);
    System.out.println(orderSession);
}

public void OrderSystem() {
    String orderSession = "order-3001";

    System.out.println(distributedSession);
    System.out.println(userSession);
}

}

distributedSession是这个类中的全局变量,可以在其他的方法中被使用到,而userSession和orderSession是在方法中的局部变量,局部变量只能在本方法中使用,全局变量可以在其他方法里都能使用。那么分布式会话和单个tomcat会话其实也是一样的道理。

2.实现redis用户会话

示例代码:将user-token存放在usersVO 中;

java 复制代码
public UsersVO convertUsersVO(Users user){
        String uniqueToken = UUID.randomUUID().toString().trim();
        redisOperator.set(REDIS_USER_TOKEN+":"+user.getId(),uniqueToken);

        UsersVO usersVO =new UsersVO();
        BeanUtils.copyProperties(user,usersVO);
        usersVO.setUserUniqueToken(uniqueToken);
        return usersVO;

    }
java 复制代码
//实现用户的redis会话
UsersVO usersVO = convertUsersVO(userResult);
//设置cookie的值,使用工具类cookieutils
CookieUtils.setCookie(request,response,"user", JsonUtils.objectToJson(usersVO),true);
java 复制代码
// 用户退出登录,清楚cookie信息     
redisOperator.del(REDIS_USER_TOKEN+":"+userId);
//分布式会话中需要清除用户数据
CookieUtils.deleteCookie(request, response, xxx);

3.SpringSession实现用户会话

SpringSession介绍

Springsession框架就是解决方案,提供一组API和实现,用于管理用户的session信息,

它把servlet容器实现的httpsession替换成Springsession,专注于解决session管理问题,

Session信息存储在Redis中,可简单快速无缝的集成到我们的应用中。

SpringSession的特性:提供用户session管理的API和实现;提供HttpSession,以

中立的方式取代web容器的session,比如tomcat中的session;支持集群的session处理,

不必绑定具体的web容器去解决集群下的session共享问题

引入SpringSession(分别是springsession的引入以及Spring安全框架):

java 复制代码
<dependency>
	<groupId>org.springframework.session</groupId>
	<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

配置存储类型

java 复制代码
spring:
  session:
    store-type: redis

开启redis作为SpringSession

@EnableRedisHttpSession // 开启使用redis作为spring session
去除安全自动装配

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})

代码实现:

java 复制代码
 @GetMapping("/setSession")
    public Object setSession(HttpServletRequest request){

        HttpSession session = request.getSession();
        session.setAttribute("userInfo","new user");
        session.setMaxInactiveInterval(3600);
        session.getAttribute("userInfo");
//        session.removeAttribute("userInfo");

        return "ok";
    }

**总结:**SpringSession:通过httpServletRequest去获取session。HttpSession:就是一个Springsession,包含了一些相应的会话机制,由Spring来进行管理。缺点:耦合度比较高

建议使用Redis,调用redis中相关的值存取就会更加方便。

对于SpringSession的补充:HTTP协议本身是无状态的,为了保存会话信息,

浏览器Cookie通过SessionId标识会话请求,服务器以sessionID为key来存储会话信息。

通常情况下,session交由tomcat容器来负责存储和管理。但是如果项目部署在多台tomcat,

对于session的管理就会存在很大问题。多台tomcat之间无法共享session。

相关推荐
不光头强42 分钟前
Spring框架的事务管理
数据库·spring·oracle
百***92023 小时前
【MySQL】MySQL库的操作
android·数据库·mysql
q***76663 小时前
Spring Boot 从 2.7.x 升级到 3.3注意事项
数据库·hive·spring boot
信仰_2739932433 小时前
Redis红锁
数据库·redis·缓存
人间打气筒(Ada)3 小时前
Centos7 搭建hadoop2.7.2、hbase伪分布式集群
数据库·分布式·hbase
心灵宝贝3 小时前
如何在 Mac 上安装 MySQL 8.0.20.dmg(从下载到使用全流程)
数据库·mysql·macos
奋斗的牛马4 小时前
OFDM理解
网络·数据库·单片机·嵌入式硬件·fpga开发·信息与通信
忧郁的橙子.5 小时前
一、Rabbit MQ 初级
服务器·网络·数据库
杰杰7985 小时前
SQL 实战:用户访问 → 下单 → 支付全流程转化率分析
数据库·sql
爬山算法5 小时前
Redis(120)Redis的常见错误如何处理?
数据库·redis·缓存