欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot使用redis實現(xiàn)session共享功能

 更新時間:2024年05月10日 09:51:02   作者:編程小猹  
這篇文章主要介紹了pringboot項目使用redis實現(xiàn)session共享,文中通過代碼示例講解的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

1.安裝redis,并配置密碼

這里就不針對于redis的安裝約配置進行說明了,直接在項目中使用。

redis在windows環(huán)境下安裝:Window下Redis的安裝和部署詳細圖文教程_Redis_腳本之家 (jb51.net)

2.pom.xml文件中引入需要的maven

     <dependency>
		<groupId>redis.clients</groupId>
		<artifactId>jedis</artifactId>
		<version>2.9.0</version>
	</dependency>

3.在項目的配置文件中加入redis的配置

redis:
  database: 0
  host: localhost
  password: 123456
  pool:
    max-active: 8
    max-idle: 8
    max-wait: -1
    min-idle: 0
  port: 6379
  timeout: 3000

4.添加redis的配置文件放在項目的config文件夾下

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
 
/**
 * @author kjz
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
 
	@Value("${redis.host}")
	private String host;
 
	@Value("${redis.port}")
	private int port;
 
	@Value("${redis.timeout}")
	private int timeout;
 
	@Value("${redis.pool.max-idle}")
	private int maxIdle;
 
	@Value("${redis.pool.max-wait}")
	private long maxWaitMillis;
 
	@Value("${redis.password}")
	private String password;
 
	@Bean
	public JedisPool redisPoolFactory() {
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
 
		JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout);
		return jedisPool;
	}
 
	@Bean
	public RedisConnectionFactory redisConnectionFactory() {
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
		JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
		jedisConnectionFactory.setHostName(host);
		jedisConnectionFactory.setPort(port);
		jedisConnectionFactory.setTimeout(timeout);
		jedisConnectionFactory.setPassword(password);
		return jedisConnectionFactory;
	}
 
}

5.具體實現(xiàn)思路(手動實現(xiàn))

實現(xiàn)思路

創(chuàng)建一個過濾器,攔截除了登錄之外的所有請求,判斷請求中是否存在cookie,如果存在cookie則判斷redis中是否存在以cookie為key的鍵值對數(shù)據(jù),如果有則取出對應(yīng)的value同時對這個key的過期時間進行續(xù)期,如果沒有則返回一個響應(yīng),說明登錄已經(jīng)過期了,將Value就是session進行Jason反序列化得到session對象,然后把Session綁定到當(dāng)前的請求中,如果不存在cookie,則直接返回一個響應(yīng),說明還未登錄。如果是登錄請求的話,直接到controller中進行登錄校驗,讓深沉的session通過json序列化放到redis中,并且以uuid為key,同時,返回給前端一個cookie字段,cookie字段的值就是uuid,請求完成之后,在過濾器中將會話數(shù)據(jù)session更新到redis中。

下面是思路流程圖

代碼實現(xiàn)

創(chuàng)建過濾器 SessionFilter

import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.Jedis;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
 
public class SessionFilter implements Filter {
 
    private JedisPool jedisPool;
    private ObjectMapper objectMapper;
    private static final String LOGIN_PATH = "/login";
    private static final int SESSION_EXPIRATION_TIME = 30 * 60; // 30 minutes in seconds
 
    public SessionFilter(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
        this.objectMapper = new ObjectMapper();
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
 
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
 
        String requestUri = httpRequest.getRequestURI();
 
        if (requestUri.equals(LOGIN_PATH)) {
            // 直接轉(zhuǎn)發(fā)到登錄控制器
            chain.doFilter(request, response);
        } else {
            // 檢查 Cookie
            Cookie[] cookies = httpRequest.getCookies();
            String sessionId = null;
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if ("SESSIONID".equals(cookie.getName())) {
                        sessionId = cookie.getValue();
                        break;
                    }
                }
            }
 
            if (sessionId != null) {
                try (Jedis jedis = jedisPool.getResource()) {
                    String sessionDataJson = jedis.get(sessionId);
                    if (sessionDataJson != null) {
                        // 續(xù)期
                        jedis.expire(sessionId, SESSION_EXPIRATION_TIME);
 
                        // 反序列化 Session
                        Map<String, Object> sessionAttributes = objectMapper.readValue(sessionDataJson, Map.class);
                        HttpSessionWrapper wrappedSession = new HttpSessionWrapper(sessionAttributes);
                        request.setAttribute("httpSession", wrappedSession);
 
                        // 繼續(xù)執(zhí)行過濾器鏈
                        chain.doFilter(request, response);
 
                        // 更新 Session 到 Redis
                        if (wrappedSession.isDirty()) {
                            jedis.set(sessionId, objectMapper.writeValueAsString(wrappedSession.getSessionData()));
                        }
                    } else {
                        // 登錄過期
                        httpResponse.setContentType("application/json");
                        httpResponse.getWriter().write("{\"error\": \"Session expired\"}");
                    }
                } catch (Exception e) {
                    // 處理異常
                    e.printStackTrace();
                    httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                }
            } else {
                // 未登錄
                httpResponse.setContentType("application/json");
                httpResponse.getWriter().write("{\"error\": \"Not logged in\"}");
            }
        }
    }
 
    // ... 其他 Filter 方法 ...
}

注冊過濾器

在 Spring 配置中注冊過濾器:

@Bean
public FilterRegistrationBean<SessionFilter> sessionFilterRegistration(SessionFilter sessionFilter) {
    FilterRegistrationBean<SessionFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(sessionFilter);
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
}

創(chuàng)建 HttpSessionWrapper 類

將session和sessionid封裝到這個類里面

import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
 
public class HttpSessionWrapper implements HttpSession {
 
    private final Map<String, Object> attributes;
    private boolean dirty;
 
    public HttpSessionWrapper(Map<String, Object> attributes) {
        this.attributes = attributes;
        this.dirty = false;
    }
 
    // ... 實現(xiàn) HttpSession 接口的方法 ...
 
    public void setAttribute(String name, Object value) {
        attributes.put(name, value);
        dirty = true;
    }
 
    public Map<String, Object> getSessionData() {
        return attributes;
    }
 
    public boolean isDirty() {
        return dirty;
    }
 
    // ... 其他方法 ...
}

登錄控制器

@RestController
public class LoginController {
 
    @PostMapping("/login")
    public HttpServletResponse login(HttpServletRequest request, HttpServletResponse response) {
        // ... 登錄邏輯 ...
 
        // 創(chuàng)建新的會話
        String sessionId = UUID.randomUUID().toString();
        Map<String, Object> sessionAttributes = new HashMap<>();
        // 填充會話屬性
        sessionAttributes.put("user", user);
 
        // 使用 JsonUtil 序列化會話并存儲到 Redis
        String sessionDataJson = JsonUtil.obj2String(sessionAttributes);
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.setex(sessionId, SESSION_EXPIRATION_TIME, sessionDataJson);
        } catch (Exception e) {
            // 處理異常
            e.printStackTrace();
            return "Error";
        }
 
        // 創(chuàng)建 Cookie 并設(shè)置給客戶端
        Cookie sessionCookie = new Cookie("SESSIONID", sessionId);
        sessionCookie.setPath("/");
        sessionCookie.setHttpOnly(true); // 確保 Cookie 不會被 JavaScript 訪問
        sessionCookie.setSecure(true); // 確保 Cookie 在 HTTPS 連接中傳輸
        response.addCookie(sessionCookie);
 
        return HttpServletResponse ;
    }
}

下面是序列化工具類

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
 
 
/**
 *@author kjz
 */
@Slf4j
public class JsonUtil {
 
    private static ObjectMapper objectMapper = new ObjectMapper();
 
    static{
        //對象的所有字段全部列入
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
    }
 
    public static <T> String obj2String(T obj){
        if(obj == null){
            return null;
        }
        try {
            return obj instanceof String ? (String)obj :  objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("Parse Object to String error",e);
            return null;
        }
    }
 
    /**
     * 格式化json串,看起來比較好看,但是有換行符等符號,會比沒有格式化的大
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2StringPretty(T obj){
        if(obj == null){
            return null;
        }
        try {
            return obj instanceof String ? (String)obj :  objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("Parse Object to String error",e);
            return null;
        }
    }
 
 
    public static <T> T string2Obj(String str,Class<T> clazz){
        if(StringUtils.isEmpty(str) || clazz == null){
            return null;
        }
 
        try {
            return clazz.equals(String.class)? (T)str : objectMapper.readValue(str,clazz);
        } catch (Exception e) {
            log.warn("Parse String to Object error",e);
            return null;
        }
    }
 
 
    public static <T> T string2Obj(String str, TypeReference<T> typeReference){
        if(StringUtils.isEmpty(str) || typeReference == null){
            return null;
        }
        try {
            return (T)(typeReference.getType().equals(String.class)? str : objectMapper.readValue(str,typeReference));
        } catch (Exception e) {
            log.warn("Parse String to Object error",e);
            return null;
        }
    }
 
    /**
     * 轉(zhuǎn)換集合
     * List<User></>
     * @param str
     * @param collectionClass
     * @param elementClasses
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str,Class<?> collectionClass,Class<?>... elementClasses){
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass,elementClasses);
        try {
            return objectMapper.readValue(str,javaType);
        } catch (Exception e) {
            log.warn("Parse String to Object error",e);
            return null;
        }
    }
}

6.利用Spring Session Data Redis框架實現(xiàn)

引入Spring Session Data Redis 的依賴

 <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
        <version>2.7.0</version>
    </dependency>

創(chuàng)建Spring Session的配置類

創(chuàng)建一個配置類 SessionConfig,使用 @EnableRedisHttpSession 注解來啟用 Spring Session 的 Redis 支持:

import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@EnableRedisHttpSession
public class SessionConfig {
 
    // 配置會話過期時間(例如,設(shè)置為 1800 秒,即 30 分鐘)
    @Bean
    public RedisHttpSessionConfiguration redisHttpSessionConfiguration() {
        RedisHttpSessionConfiguration configuration = new RedisHttpSessionConfiguration();
        configuration.setMaxInactiveIntervalInSeconds(1800);
        return configuration;
    }
 
    // 如果你使用的是 Spring Boot 2.3 或更高版本,你可能需要定義這個 Bean 來避免警告
    @Bean
    public static ConfigureRedisAction configureRedisAction() {
        return ConfigureRedisAction.NO_OP;
    }
}

@EnableRedisHttpSession 是一個方便的注解,它做了以下幾件事情:

  1. 啟用 Spring Session 的支持,使得 HttpSession 能夠被 Spring Session 管理。
  2. 配置 Redis 作為會話數(shù)據(jù)的存儲后端。
  3. 注冊一個 SessionRepositoryFilter 的 Bean,這個 Filter 負責(zé)攔截請求,并將標(biāo)準(zhǔn)的 HttpSession 替換為 Spring Session 的實現(xiàn)。

Session的創(chuàng)建存儲和獲取

做完上面的配置之后,你可以像使用常規(guī) HttpSession 一樣使用 Spring Session。每次修改會話時,Spring Session 都會自動將這些更改同步到 Redis。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
import javax.servlet.http.HttpSession;
 
@RestController
public class SessionController {
 
    @GetMapping("/setSession")
    public String setSession(HttpSession session) {
        session.setAttribute("message", "Hello, Redis Session!");
        return "Session set in Redis";
    }
 
    @GetMapping("/getSession")
    public String getSession(HttpSession session) {
        return "Session message: " + session.getAttribute("message");
    }
}

以上就是SpringBoot使用redis實現(xiàn)session共享的詳細內(nèi)容,更多關(guān)于SpringBoot redis session共享的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java在linux系統(tǒng)下開機啟動無法使用sudo命令的原因及解決辦法

    java在linux系統(tǒng)下開機啟動無法使用sudo命令的原因及解決辦法

    每次開機自動啟動的java進程,頁面上的關(guān)機按鈕都無法實現(xiàn)關(guān)機功能,但是此時如果以chb賬號通過ssh登錄該服務(wù)器,手動殺掉tomcat進程,然后再重新啟動tomcat,頁面上的關(guān)機按鈕就有效了
    2013-08-08
  • Mybatis實現(xiàn)一對多映射處理

    Mybatis實現(xiàn)一對多映射處理

    MyBatis是一種流行的Java持久化框架,這篇文章主要為大家介紹了Mybatis如何實現(xiàn)一對多映射處理,文中的示例代碼講解詳細,需要的可以參考下
    2023-08-08
  • Spring中@Primary注解的作用詳解

    Spring中@Primary注解的作用詳解

    這篇文章主要介紹了Spring中@Primary注解的作用詳解,@Primary 注解是Spring框架中的一個注解,用于標(biāo)識一個Bean作為默認的實現(xiàn)類,當(dāng)存在多個實現(xiàn)類時,通過使用@Primary注解,可以指定其中一個作為默認的實現(xiàn)類,以便在注入時自動選擇該實現(xiàn)類,需要的朋友可以參考下
    2023-10-10
  • druid?return行為方法源碼示例解析

    druid?return行為方法源碼示例解析

    這篇文章主要為大家介紹了druid?return行為源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • 解決SpringBoot整合RocketMQ遇到的坑

    解決SpringBoot整合RocketMQ遇到的坑

    這篇文章主要介紹了解決SpringBoot整合RocketMQ遇到的坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 使用EasyPoi實現(xiàn)word文檔生成和段落循環(huán)

    使用EasyPoi實現(xiàn)word文檔生成和段落循環(huán)

    EasyPoi是一個Java的Excel和Word處理庫,主要用于將Java對象轉(zhuǎn)換為Excel或Word文檔,本文主要介紹了如何使用EasyPoi實現(xiàn)word文檔生成和段落循環(huán),有需要的可以了解下
    2025-04-04
  • Java單測void類型的方法詳解

    Java單測void類型的方法詳解

    這篇文章主要給大家介紹了Java中單測void類型的方法,文中給出了詳細的示例代碼,相信對大家的理解和學(xué)習(xí)具有一定的參考借鑒價值,需要的朋友可以跟著小編下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-01-01
  • java多線程數(shù)據(jù)分頁處理實例講解

    java多線程數(shù)據(jù)分頁處理實例講解

    在本篇內(nèi)容里小編給大家分享了一篇關(guān)于java多線程數(shù)據(jù)分頁處理實例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-01-01
  • 淺談Java中的private方法是否可以被代理

    淺談Java中的private方法是否可以被代理

    這篇文章主要介紹了淺談Java中的private方法是否可以被代理,在?Java?8之前,接口可以有常量變量和抽象方法,我們不能在接口中提供方法實現(xiàn),如果我們要提供抽象方法和非抽象方法(方法與實現(xiàn))的組合,那么我們就得使用抽象類,需要的朋友可以參考下
    2023-12-12
  • Java的關(guān)鍵字與標(biāo)識符小結(jié)

    Java的關(guān)鍵字與標(biāo)識符小結(jié)

    這篇文章主要介紹了Java的關(guān)鍵字與標(biāo)識符,總結(jié)整理了Java各種常見的關(guān)鍵字與標(biāo)識符功能、用法及操作注意事項,需要的朋友可以參考下
    2020-04-04

最新評論