目录
  • 1.安装redis,并配置密码
  • 2.pom.xml文件中引入需要的maven
  • 3.在项目的配置文件中加入redis的配置
  • 4.添加redis的配置文件放在项目的config文件夹下
  • 5.具体实现思路(手动实现)
    • 实现思路
    • 代码实现
      • 创建过滤器 SessionFilter
      • 注册过滤器
      • 创建 HttpSessionWrapper 类
      • 登录控制器
  • 6.利用Spring Session Data Redis框架实现
    • 引入Spring Session Data Redis 的依赖
      • 创建Spring Session的配置类
        • Session的创建存储和获取

        1.安装redis,并配置密码

        这里就不针对于redis的安装约配置进行说明了,直接在项目中使用。

        redis在windows环境下安装: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.具体实现思路(手动实现)

        实现思路

        创建一个过滤器,拦截除了登录之外的所有请求,判断请求中是否存在cookie,如果存在cookie则判断redis中是否存在以cookie为key的键值对数据,如果有则取出对应的value同时对这个key的过期时间进行续期,如果没有则返回一个响应,说明登录已经过期了,将Value就是session进行Jason反序列化得到session对象,然后把Session绑定到当前的请求中,如果不存在cookie,则直接返回一个响应,说明还未登录。如果是登录请求的话,直接到controller中进行登录校验,让深沉的session通过json序列化放到redis中,并且以uuid为key,同时,返回给前端一个cookie字段,cookie字段的值就是uuid,请求完成之后,在过滤器中将会话数据session更新到redis中。

        下面是思路流程图

        SpringBoot使用redis实现session共享功能

        代码实现

        创建过滤器 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)) {
                    // 直接转发到登录控制器
                    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) {
                                // 续期
                                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);
         
                                // 继续执行过滤器链
                                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;
        }

        创建 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;
            }
         
            // ... 实现 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) {
                // ... 登录逻辑 ...
         
                // 创建新的会话
                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";
                }
         
                // 创建 Cookie 并设置给客户端
                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;
                }
            }
         
            /**
             * 转换集合
             * 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框架实现

        引入Spring Session Data Redis 的依赖

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

        创建Spring Session的配置类

        创建一个配置类 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 {
         
            // 配置会话过期时间(例如,设置为 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 作为会话数据的存储后端。
        3. 注册一个 SessionRepositoryFilter 的 Bean,这个 Filter 负责拦截请求,并将标准的 HttpSession 替换为 Spring Session 的实现。

        Session的创建存储和获取

        做完上面的配置之后,你可以像使用常规 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实现session共享的详细内容,更多关于SpringBoot redis session共享的资料请关注其它相关文章!

        声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。