spring Boot整合Spring session
1.模拟场景
有两台相同的服务器,并且用nginx管理,用户的访问在两台机器之间权重相同(也就是说用户的访问是一次一台服务器,下一次访问的是另一台服务器),这样存在的问题是登录在一台服务器,下次访问应该传递回的是登录后的界面,但因为跨服务器,服务器对权限检查发现session中未包含信息,表明没有权限,而做了错误响应
SpringSession就是为了解决上面的问题
2.场景实现

2.1依赖导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.2 页面开发
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form th:action="@{/dologin}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1><span th:text="${#session.getAttribute('username')}"></span>你好,登录成功</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="退出登录">
</form>
</body>
</html>
2.3controller开发
DemoController
@Controller
public class DemoController {
@GetMapping("/")//访问根地址时进入home界面,但是会被自定义的拦截器先进行拦截判断是否有权限
public String homeShow(){
return "home";
}
//响应可以的dologin操作,并将username属性存放到session中,要求用户进行重定向到另一台机器
@PostMapping("/dologin")
public String doLogin(@RequestParam("username")String userName,
@RequestParam("password") String password, HttpServletRequest request){
request.getSession().setAttribute("username",userName);
return "redirect:/";
}
//响应用户的logout操作
@PostMapping("/logout")
public String LoginOut( HttpServletRequest request){
//登出将session失效
request.getSession().invalidate();
return "login";
}
}
2.4 拦截器开发
LoginInterceptor
@Component //注入到容器中
@Slf4j //用于日志记录
public class LoginInterceptor extends HandlerInterceptorAdapter {
//定义拦截器,前置拦截,对权限进行判断
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//用日志功能查看拦截到的路径
log.info("拦截到"+request.getRequestURI());
//检查路径,对/login /dologin不拦截
if (request.getRequestURI().equals("/login")|| request.getRequestURI().equals("/dologin")){
return true;
}
//如果session中存在username,表明已登录则放行
if (request.getSession()!=null&& request.getSession().getAttribute("username")!=null){
// String username =(String) request.getSession().getAttribute("username");
// if ( username.trim().length()>0 ){
return true;
}
//验证没有登录,重定向到登录界面
response.sendRedirect(request.getContextPath()+"/login");
return false;
}
}
2.5 web配置类
WebMvcConfig
@Configuration
@AllArgsConstructor //所有变量的构造方法,利用spring自动注入所有成员变量
public class WebMvcConfig implements WebMvcConfigurer {
private LoginInterceptor loginInterceptor;
//添加/login的请求响应界面
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login");
}
//注入拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor);
}
}
2.6 配置文件

增加两个配置文件,其中定义端口号分别为8081 和9092
application.properties设置启动时默认的配置文件为M1
2.7复制一台服务器
在idea中右键复制一个相同的服务器
右键新建的机器,进行编辑配置

2.8 使用nginx进行管理
修改nginx配置文件
指定好网络和端口,权重设置都为1
2.9 使用SwitchHost进行网页统一

2.10浏览器访问
启动服务


点击提交后依然会重新进入login界面
3.问题解决
解决的思路主要有两种:
- 将session单独存放到一个服务器,运行的两台服务器在进行服务时都从第三台服务器上读取session
- 在用户进行登录后给用户返回特定字符串(JWT技术),每次用户进行后续访问都自动携带这串信息,在服务器上只需进行这串信息合法性判断即可(这里不做过多讨论)
针对第一种方案,使用redis进行session存储,用到的框架就是SpringSession
3.1 依赖导入
<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>
</dependency>
3.2 application.properties配置
#设置程序启动时默认的配置文件
spring.profiles.active=M1
#进行redis配置
spring.redis.host=172.16.2.134
spring.redis.database=1
spring.redis.port=6379
spring.redis.password=123456
# springSession配置
spring.session.store-type=redis
spring.session.timeout=30m
# 可以配置redis中存储的文件夹
spring.session.redis.namespace=demo1:555
3.3 启动网址


3.4 redis查看
这里需要注意的是,必须在controller中拿到session才会触发保存到redis的操作(即request.getSession()),否则不会进行存储
因为springSession进行自动存储,所以序列化格式采用了JDK默认方式,不太好修改,但是如果我们自己想要在redis中进行存储,可以设置存储格式:
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
版权声明:本文为Guesshat原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。