多個SpringBoot項目采用redis實現(xiàn)Session共享功能
有時我們可能有多個不同的Web應(yīng)用,可以相互調(diào)用,這時如果每個應(yīng)用都有自己的session,那用戶跳轉(zhuǎn)到另一個應(yīng)用時就又需要登陸一次,這樣會帶來很不好的體驗,因此我們需要在不同的應(yīng)用中共享session。這里,我們采用redis來實現(xiàn)。
前置說明
由于只用到redis和springboot的整合,所以只能實現(xiàn)一個URL下的不同端口的應(yīng)用之間的session共享,如果連應(yīng)用名稱都完全不同的兩個應(yīng)用要實現(xiàn)session共享,在這個基礎(chǔ)上還需要使用到Nginx,這種方式我暫時還沒有試過。(SpringBoot項目默認(rèn)就是不帶應(yīng)用名稱的,除非自己在配置文件中修改過)
需要提前在本地安裝好redis,或者連接遠(yuǎn)程redis服務(wù)器。這里就不寫安裝教程了,可以自行去網(wǎng)上搜索。
添加依賴
需要為springboot項目添加以下兩個依賴,參與session共享的項目都需要添加。
<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>
一個是redis的依賴,一個是spring-session-data-redis的依賴。
配置redis參數(shù)
在SpringBoot項目的application.properties配置文件中配置redis參數(shù):
# Redis數(shù)據(jù)庫索引(默認(rèn)為0) spring.redis.database=0 # Redis服務(wù)器地址,如果是遠(yuǎn)程redis服務(wù)器,就改成服務(wù)器地址 spring.redis.host=127.0.0.1 # Redis服務(wù)器連接端口,默認(rèn)是6379 spring.redis.port=6379 # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制) spring.redis.lettuce.pool.max-active=8 # 連接池最大阻塞等待時間(使用負(fù)值表示沒有限制) spring.redis.lettuce.pool.max-wait=-1ms # 連接池中的最大空閑連接 spring.redis.lettuce.pool.max-idle=5 # 連接池中的最小空閑連接 spring.redis.lettuce.pool.min-idle=0 # 連接超時時間(毫秒) spring.redis.timeout=5000 spring.session.store-type=redis
如果你的項目使用的是application.yml,就進(jìn)行如下配置:
spring: redis: database: 0 host: 127.0.0.1 port: 6379 lettuce: pool: max-idle: 8 min-idle: 0 max-active: 8 max-wait: -1ms timeout: 5000 session: store-type: redis
配置session過期時間
創(chuàng)建一個用于配置session過期時間的配置類:
import org.springframework.context.annotation.Configuration; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @Configuration @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30) public class SessionConfig { }
簡單的登錄邏輯
@RequestMapping("/doLogin") public String doLogin(HttpServletRequest request, Model model){ String username = request.getParameter("username"); String password = request.getParameter("password"); if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){ model.addAttribute("errorMsg", "用戶名和密碼不能為空"); return "login"; } // 查找該用戶,成功后根據(jù)該用戶的類別返回到對應(yīng)頁面 User user = userService.getUserByUsernameAndPassword(username, password); if(user == null) { model.addAttribute("errorMsg", "用戶名或密碼錯誤"); return "login"; } else { request.getSession().setAttribute("currentUser", user); model.addAttribute("currentUser", user); String identity = user.getIdentity(); if("admin".equals(identity)){ return "admin"; }else{ return "user"; } } }
直接按照原來的方式將對象存入session:request.getSession().setAttribute("currentUser", user);
此時session會存入redis。
登錄過濾器
@Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); User currentUser = (User) session.getAttribute("currentUser"); if(currentUser == null){ response.sendRedirect(request.getContextPath() + "/toLogin"); return false; }else{ return true; } } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
同樣按原來的方式從session中取出對象:User currentUser = (User) session.getAttribute("currentUser");
此時會從redis中取出該對象。
注意
如果只是存字符串等redis可以直接解析的對象,那就不會有什么問題,但是如果是存取對象就需要進(jìn)行序列化了,比如上文中存的是我自定義的一個User對象,那么在存的時候,是會對該對象進(jìn)行序列化的,取出時也會進(jìn)行反序列化,因此該對象要實現(xiàn)Serializable接口,并且需要進(jìn)行session共享的項目中都要有一個一模一樣的對象,比如我的User定義如下:
import java.io.Serializable; public class User implements Serializable { private String id; private String username; private String password; private String email; private String identity; private static final long serialVersionUID = -5809782578272943999L; // 省略getter、setter方法 }
注意這個序列號serialVersionUID
,不同應(yīng)用中的User對象的這個序列號必須相同,否則無法正確進(jìn)行反序列化。
小結(jié)
之所以要實現(xiàn)這個功能是因為在我搭建自己的網(wǎng)站時想集成之前做過的另一個應(yīng)用,把它作為一個功能嵌入這個應(yīng)用中,通過http互通。中間遇到了很多坑,這種方式的主要缺點就是不能支持不同應(yīng)用名稱的應(yīng)用之間的session共享,下一次可以嘗試一下加入Nginx。
到此這篇關(guān)于多個SpringBoot項目采用redis實現(xiàn)Session共享功能的文章就介紹到這了,更多相關(guān)SpringBoot Session共享內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot利用限速器RateLimiter實現(xiàn)單機(jī)限流的示例代碼
本文主要介紹了SpringBoot利用限速器RateLimiter實現(xiàn)單機(jī)限流的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01Java使用正則表達(dá)式驗證手機(jī)號和電話號碼的方法
今天小編就為大家分享一篇關(guān)于Java使用正則表達(dá)式驗證手機(jī)號和電話號碼的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12Java動態(tài)線程池插件dynamic-tp集成過程淺析
這篇文章主要介紹了Java動態(tài)線程池插件dynamic-tp集成過程,dynamic-tp是一個輕量級的動態(tài)線程池插件,它是一個基于配置中心的動態(tài)線程池,線程池的參數(shù)可以通過配置中心配置進(jìn)行動態(tài)的修改2023-03-03Java實現(xiàn)連接kubernates集群的兩種方式詳解
這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)連接kubernates集群的兩種方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01