有時我們可能有多個不同的Web應用,可以互相調用,這時如果每個應用都有自己的session,那使用者跳轉到另一個應用時就又需要登陸一次,這樣會帶來很不好的體驗,是以我們需要在不同的應用中共享session。這裡,我們采用redis來實作。
前置說明
由于隻用到redis和springboot的整合,是以隻能實作一個URL下的不同端口的應用之間的session共享,如果連應用名稱都完全不同的兩個應用要實作session共享,在這個基礎上還需要使用到Nginx,這種方式我暫時還沒有試過。(SpringBoot項目預設就是不帶應用名稱的,除非自己在配置檔案中修改過)
需要提前在本地安裝好redis,或者連接配接遠端redis伺服器。這裡就不寫安裝教程了,可以自行去網上搜尋。
添加依賴
需要為springboot項目添加以下兩個依賴,參與session共享的項目都需要添加。
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.session
spring-session-data-redis
一個是redis的依賴,一個是spring-session-data-redis的依賴。
配置redis參數
在SpringBoot項目的application.properties配置檔案中配置redis參數:
# Redis資料庫索引(預設為0)
spring.redis.database=0
# Redis伺服器位址,如果是遠端redis伺服器,就改成伺服器位址
spring.redis.host=127.0.0.1
# Redis伺服器連接配接端口,預設是6379
spring.redis.port=6379
# 連接配接池最大連接配接數(使用負值表示沒有限制)
spring.redis.lettuce.pool.max-active=8
# 連接配接池最大阻塞等待時間(使用負值表示沒有限制)
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,就進行如下配置:
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過期時間
建立一個用于配置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";
}
// 查找該使用者,成功後根據該使用者的類别傳回到對應頁面
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可以直接解析的對象,那就不會有什麼問題,但是如果是存取對象就需要進行序列化了,比如上文中存的是我自定義的一個User對象,那麼在存的時候,是會對該對象進行序列化的,取出時也會進行反序列化,是以該對象要實作Serializable接口,并且需要進行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,不同應用中的User對象的這個序列号必須相同,否則無法正确進行反序列化。
小結
之是以要實作這個功能是因為在我搭建自己的網站時想內建之前做過的另一個應用,把它作為一個功能嵌入這個應用中,通過http互通。中間遇到了很多坑,這種方式的主要缺點就是不能支援不同應用名稱的應用之間的session共享,下一次可以嘗試一下加入Nginx。
到此這篇關于多個SpringBoot項目采用redis實作Session共享功能的文章就介紹到這了,更多相關SpringBoot Session共享内容請搜尋腳本之家以前的文章或繼續浏覽下面的相關文章希望大家以後多多支援腳本之家!