重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这期内容当中小编将会给大家带来有关springboot中如何整合spring-session,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
我们提供的服务有:网站建设、网站设计、微信公众号开发、网站优化、网站认证、西乡ssl等。为上1000+企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的西乡网站制作公司
它可以替代 HttpSesession
。而且改动极小,对应用透明。底层可以使用内存,redis等存储Session信息。通过Redis
这种方式可以做到Session
共享,在集群环境中所有节点共享Session。
文档 https://docs.spring.io/spring-session/docs/current/reference/html5/
使用 spring-session-data-redis,一定要先整合redis到项目。
org.springframework.session spring-session-data-redis
配置类:
RedisSessionProperties
spring: session: timeout: 1800 # session的过期时间,单位是秒 store-type: REDIS # session的存储类型,枚举 redis: namespace: "spring:session" # session存储在redis中的命名空间 flush-mode: IMMEDIATE # 刷出模式,枚举:ON_SAVE ,IMMEDIATE cleanup-cron: "0 * * * * *" # 定时清理过期session任务的`cron`表达式
关于 spring.session.redis.flush-mode
ON_SAVE
只有当
SessionRepository.save(Session)
方法被调用时, 才会将session中的数据同步到redis中. 在web 应用中, 当请求完成响应后, 才开始同步. 也就是说在执行response 之前session数据都是缓存在本地的。
IMMEDIATE
当执行
SessionRepository.createSession()
时, 会将session数据同步到redis中; 当对session的attribute进行set/remove 等操作时, 也会同步session中的数据到redis中。它是实时同步的
使用并需要修改什么,像平时一样。获取到 Servlet的Session就是了。
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @RequestMapping("/test") @Controller public class TestController { @GetMapping("/session") public ModelAndView session(HttpServletRequest request) { HttpSession httpSession = request.getSession(); // 是否新创建的 true System.out.println(httpSession.isNew()); // 实现类 org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper System.out.println(httpSession.getClass().getName()); // 写入数据到session(底层使用redis存储) httpSession.setAttribute("name", "SpringBoot中文社区"); return new ModelAndView("test/test"); } }
Test Hello ${name}
默认情况下,客户端使用Cookie来存储会话id
Connection: keep-alive Content-Encoding: gzip Content-Language: zh-CN Content-Type: text/html;charset=UTF-8 Date: Thu, 17 Oct 2019 08:57:07 GMT Server: nginx Set-Cookie: PHPSESSIONID=Y2YwMDM1YjctMjBiYy00OWRiLWI5NGItZjFmNDU4ZDcxNThm; Max-Age=36000; Expires=Thu, 17 Oct 2019 18:57:07 GMT; Path=/; HttpOnly; SameSite=Lax Transfer-Encoding: chunked
server: servlet: session: cookie: name: PHPSESSIONID #cookie名称 domain: # 域 path: # 路径 comment: # 备注 httpOnly: # 是否仅用于http传输 secure: # 是否仅在SSL的情况下传输 maxAge: # 生命周期
自定义
CookieSerializer
到IOC。
@Bean public CookieSerializer cookieSerializer() { DefaultCookieSerializer serializer = new DefaultCookieSerializer(); serializer.setCookieName("JSESSIONID"); serializer.setCookiePath("/"); serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); return serializer; }
通俗的理解就是,可以建立key和session的索引,根据某些key获取到session。
需求:根据用户id,获取到它的会话
value仅仅接受字符串
@Autowired FindByIndexNameSessionRepository extends Session> sessions; .... 代码省略 Integer userId = user.getId(); // 往session中存入用户的id信息 request.getSession().setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, userId + "");
@Autowired FindByIndexNameSessionRepository extends Session> sessions; .... 代码省略 Integer userId = user.getId(); // 返回该用户的所有的有效session Mapsessions = this.sessions.findByPrincipalName(userId + ""); for (Session session : sessions.values()) { // 根据sessionId删除 this.sessions.deleteById(session.getId()); }
public interface FindByIndexNameSessionRepositoryextends SessionRepository{ String PRINCIPAL_NAME_INDEX_NAME =FindByIndexNameSessionRepository.class.getName() .concat(".PRINCIPAL_NAME_INDEX_NAME"); MapfindByIndexNameAndIndexValue(String indexName, String indexValue); default Map findByPrincipalName(String principalName) { return findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName); } }
可以通过findByIndexNameAndIndexValue
方法自己建立key和session的索引信息。
session过期,销毁事件依赖于redis的key过期通知。事件对象通过spring的事件订阅发布机制来发布
SessionCreatedEvent 创建 SessionDestroyedEvent |-SessionExpiredEvent 过期 |-SessionDeletedEvent 删除(用户主动 invalidate())
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.session.events.SessionCreatedEvent; import org.springframework.session.events.SessionDeletedEvent; import org.springframework.session.events.SessionExpiredEvent; import org.springframework.stereotype.Component; @Component public class SpringSessionListener { private static final Logger LOGGER = LoggerFactory.getLogger(SpringSessionListener.class); @EventListener(SessionCreatedEvent.class) @Async public void sessionCreatedEvent(SessionCreatedEvent sessionCreatedEvent) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("session 创建:{}", sessionCreatedEvent.getSessionId()); } } @EventListener(SessionExpiredEvent.class) public void sessionExpiredEvent(SessionExpiredEvent sessionCreatedEvent) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("session 到期:{}", sessionCreatedEvent.getSessionId()); } } @EventListener(SessionDeletedEvent.class) public void sessionDeletedEvent(SessionDeletedEvent sessionCreatedEvent) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("session 删除:{}", sessionCreatedEvent.getSessionId()); } } }
比较麻烦,需要自己通过代码配置添加
需要添加SessionEventHttpSessionListenerAdapter到ioc, 通过这个bean的构造函数, 添加多个 HttpSessionListener 实现 SessionEventHttpSessionListenerAdapter
SessionEventHttpSessionListenerAdapter(List
但是这个Bean其实框架已经自动添加了, 再次添加会导致异常
曲线救国, 从IOC里面读取到这个bean, 通过反射, 对私有属性 listeners 添加监听器
@Configuration public class SpringSessionConfiguration { private static final Logger LOGGER = LoggerFactory.getLogger(SpringSessionConfiguration.class); @Autowired SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter; @PostConstruct public void addHttpSessionListener() { try { Field field = SessionEventHttpSessionListenerAdapter.class.getDeclaredField("listeners"); field.setAccessible(Boolean.TRUE); @SuppressWarnings("unchecked") Listlisteners = (List ) field.get(sessionEventHttpSessionListenerAdapter); listeners.add(new SessionListener()); if (LOGGER.isDebugEnabled()) { LOGGER.debug("添加SESSION监听器"); } } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } // @Bean //BeanDefinitionOverrideException // public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() { // SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter = new SessionEventHttpSessionListenerAdapter(Arrays.asList(new SessionListener())); // return sessionEventHttpSessionListenerAdapter; // } }
默认客户端使用Cookie来存储session id。但是对于一些客户端来说,cookie不一定方便,可以通过 http header来携带cookie的id。
实现类 CookieHttpSessionIdResolver
使用Cookie(默认) HeaderHttpSessionIdResolver
使用Header
@Bean public HttpSessionIdResolver httpSessionIdResolver() { return HeaderHttpSessionIdResolver.xAuthToken(); // 使用 X-Auth-Token 解析Cookie }
HeaderHttpSessionIdResolver 还支持自定义header的名称,代码及简单,可以自己阅读学习。
spring:session:expirations:1570672200000 spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:1 spring:session:sessions:d82bf2bb-deb3-474c-89bb-96c2bfa646c4 spring:session:sessions:expires:94b2ce1f-053e-4c20-a8b7-f4d69102a114
上述就是小编为大家分享的springboot中如何整合spring-session了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注创新互联行业资讯频道。