这期内容当中小编将会给大家带来有关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")
List listeners = (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了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注创新互联行业资讯频道。