Redis及分布式会话的实现
1.分布式会话
查看我们原来的代码,是基于tomcat容器实现的使用cookie传输sessionid的方式实现的登陆功能
//登陆 this.request.getSession().setAttribute("IS_LOGIN",true); this.request.getSession().setAttribute("LOGIN_USER",userModel);
当使用分布式架构之后,如果仍将登录态保存在tomcat容器中的session里的话,那么可能出现一个账户怎么登陆,都登陆不上去的状况(登陆态保存在不同的服务器上),那么怎么才能避免这种问题呢?
我们将登录态使用redis统一保存在后端的一个或者多个redis集群上,这样通过前端访问的时候,总是能够保证数据的一致性。
使用redis保存登录态
1.1 引入相应的jar包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>2.0.5.RELEASE</version> </dependency>
1.2 实现相应的配置类,注入spring容器中
@Component @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600) public class RedisConfig { }
1.3 序列化相应的Java实体类
@Data @NoArgsConstructor @AllArgsConstructor public class UserModel implements Serializable { rivate Integer id; @NotBlank(message = "用户名不能为空") private String name; @NotNull(message = "性别不能不填写") private Integer gender; @NotNull(message = "年龄不能不填写") @Min(value = 0,message = "年龄必须大于0岁") @Max(value = 150,message = "年龄必须小于150岁") private Integer age; @NotBlank(message = "手机号不能为空") private String telephone; private String registerMode; private String thirdPartyId; @NotBlank(message = "密码不能为空") private String encrptPassword; }
1.4 application.properties中配置相应参数
#配置springboot对redis的依赖 spring.redis.port=6379 spring.redis.host=127.0.0.1 spring.redis.database=10 #设置jedis连接池 spring.redis.jedis.pool.max-active=50 spring.redis.jedis.pool.min-idle=20
1.5 使用redisTemplate存储用户登陆态
//生成登陆凭证token,UUID String uuidToken = UUID.randomUUID().toString(); uuidToken = uuidToken.replace("-",""); //建立token和用户登录态之间的联系 redisTemplate.opsForValue().set(uuidToken,userModel); redisTemplate.expire(uuidToken,1, TimeUnit.HOURS);
1.6 前端同步修改localStorage
login.html
$.ajax({ type: "POST", contentType: "application/x-www-form-urlencoded", url: "http://"+g_host+"/user/login", data: { "telephone": $("#telphone").val(), "password":password }, xhrFields:{withCredentials:true}, success: function (data) { if(data.status == "success"){ alert("登陆成功"); var token = data.data; //将返回的token存入localStorage,以便后续的页面使用 window.localStorage["token"] = token; window.location.href="./listitem.html"; }else{ alert("登陆失败,原因为"+data.data.errMsg); } }, error: function (data) { alert("登陆失败,原因为"+data.responseText); } })
getitem.html
$("#createorder").on("click", function () { //下单前进行token的验证,没有下发token则不能下单 var token = window.localStorage["token"]; if (token == null) { alert("没有登陆,不能下单!"); window.location.href = "login.html"; return false; } $("#verifyDiv img").attr("src","http://"+g_host+"/order/generateverifycode?token="+token); $("#verifyDiv").show(); });
这样子,一个使用redis保存用户登陆状态的分布式会话就简单实现了。