1.集群的Session共享问题
多台Tomcat并不共享Session存储空间,当请求切换到不同tomcat服务器时会导致数据丢失:
当用户量增多,我们需要进行负载均衡、对tomcat做水平扩展,可是存储在Tomcat里的Session不是共享的,这就会导致Nginx进行轮询时轮循到另一个Tomcat而其中并没有之前的Session信息。总而言之,由于Session在Tomcat之间数据不共享的问题会使程序不满足应对高并发的能力,因此使用Redis来替代Session,让每一次被轮循到的Tomcat服务器来访问服务器内存中的Redis,以此来得到相关信息。
2.为什么以前会选择Session?
因为我们不需要考虑“取数据”的题,请求来了创建一个Session(在以前没有的情况下)写到Cookie中,getAttribute底层就是直接通过JSessionID来拿非常方便
此外
Tomcat内部维护了很多独立的Session,也就是说在每一个不同的浏览器发请求的时候都有一个独立的Session,用户输入手机号往往是伴随着请求的发生,当调用了后端的接口,验证码就会生成并且被单独保存在独立的Session中。这就做到了互不干扰完全独立的效果!与此同时,输入的手机号与随机生成的验证码也做到了一一对应,独立保存!
使用Redis后拿什么作为Key?
可以使用phone但推荐使用UUID生成的token,将token作为登陆凭证,将发送的请求携带上token。token其实是保存在前端浏览器的,使用手机号来作为凭证的话其实不太安全
3.基于Redis实现短信的登陆
用Redis来取代Session就是将以前存到Session里的动作变为存到Redis中,利用Hash结构来存储并使用token作为Key。Service中数据库里查到的对象——User——UserDTO——Map作为Value存到Redis,取的过程也是如此,在拦截器里根据token取user对应的map在进行类型转换存到ThreadLocal。只不过之间类型的转换要做到位,细节决定成败
Map<String, Object> stringObjectMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),
CopyOptions.create().
setIgnoreNullValue(true).
//将所有字段值转字符串,避免出现Long——>String的错误,因为自动系列化反序列化,
//在存储数据时会把类的信息写入到Redis,这就涉及到了Long转String,以此类推其他的类型亦是如此
setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString())); //对象转map
4.解决针对登陆状态重复刷新token有效期
当用户登陆后一直去访问首页,商品页…一些不需要拦截的路径,token就不会去刷新,而Redis中的token有效期过后,用户再去浏览一些需要拦截的页面(需要登录的页面)就会出现访问不了的情况,为了解决需要新增一个拦截器拦截所有路径判断来刷新token,判断需要登录状态的页面中是否有用户的事交给另一个拦截器,并定义执行顺序,先刷新后判断。
这里我一直以为,使用两个拦截器的话你不登陆就浏览不了任何页面了,其实是错了!因为我在第一个刷新的拦截器里可以设置:如果查不到UserDTO对象我也放行 直接return true!这样就做到了!有则刷新,无则放行!