一、前言
登录登出状态采用sessioni-cookie的模式,但是在前后分离的设计中,发现采用sessionId传输,总是有跨域问题,于是将sessionId 改名为token ,才得以解决。建立一个session的监听,当用户登录之后,会建立session,然后将session放到自定义的session容器中,就可以根据token 也就是sessionId得到session。就能够判断登录状态了。讲的比较乱,请大家看代码。
二、代码
1.BaseSessionContext
这里采用一种单例模式,如果不了解单例模式的小伙伴们,可以先去了解一下设计模式,推荐大家看《大话设计模式》。
package com.base.infrastructure.common.session;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
/**
*
*/
public class BaseSessionContext {
private static BaseSessionContext instance;
private HashMap mymap;
/**
* 私有构造方法
*/
private BaseSessionContext() {
mymap = new HashMap();
}
/**
* 静态工厂方法
* @return
*/
public static BaseSessionContext getInstance() {
if (instance == null) {
instance = new BaseSessionContext();
}
return instance;
}
public synchronized void AddSession(HttpSession session) {
if (session != null) {
mymap.put(session.getId(), session);
}
}
public synchronized void DelSession(HttpSession session) {
if (session != null) {
mymap.remove(session.getId());
}
}
public synchronized HttpSession getSession(String session_id) {
if (session_id == null) return null;
return (HttpSession) mymap.get(session_id);
}
}
2. SessionListener
- sessionCreated 方法在session创建得到时候调用
- sessionDestroyed 方法在session销毁得到时候调用
package com.base.infrastructure.common.session;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
@Slf4j
public class SessionListener implements HttpSessionListener {
private BaseSessionContext myc = BaseSessionContext.getInstance();
@Override
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
myc.AddSession(session);
log.info("SessionListener------------" + session.getId() + "-----------------sessionCreated");
}
@Override
public void sessionDestroyed(HttpSessionEvent event) throws ClassCastException {
HttpSession session = event.getSession();
log.info("SessionListener-------------" + session.getId() + "-----------------sessionDestroyed");
myc.DelSession(session);
}
}
3. @ServletComponentScan
- 要想使SessionListener 生效,需要在主启动类,也就是ApplicationMain类上添加一个注解,就是@ServletComponentScan
- 作用:Enables scanning for Servlet components (filters, servlets, and listeners)
三、运行测试
1. 新建接口
- 重点在2,3,4 步骤
@ApiOperation(value = "测试sessionListener")
@GetMapping("/sessionTest")
@ResponseBody
public ServiceApiResult<String> sessionTest(HttpServletRequest request, HttpServletResponse response) {
try {
BaseSessionContext myc = BaseSessionContext.getInstance();
//1. 模拟 登录 新建session
HttpSession session = request.getSession();
session.setAttribute("userName", "123123");
//2. 模拟 将sessionId返回给前端
String sessionId = session.getId();
//3. 再次请求后端时候 携带sessionId,通过自定义的session容器获取session
HttpSession sessionforContext = myc.getSession(sessionId);
//4. 获取参数,判断登录状态
String userName = String.valueOf(sessionforContext.getAttribute("userName"));
log.info("[测试sessionListener]-userName:{}", userName);
//5. 登出时,销毁session
session.invalidate();
return ServiceApiResult.success("测试sessionListener");
} catch (Exception e) {
e.printStackTrace();
return ServiceApiResult.error(e.getMessage());
}
}
2.调用接口
2021-10-13 15:33:30.546 INFO 95776 --- [nio-8327-exec-3] c.m.common.session.SessionListener : SessionListener------------5284BC91C799D78F4C6B7BB426ABF7A9-----------------sessionCreated
2021-10-13 15:34:53.484 WARN 95776 --- [l-1 housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=1m20s224ms157µs900ns).
2021-10-13 15:34:57.601 INFO 95776 --- [nio-8327-exec-3] c.m.controller.OrganizationController : [测试sessionListener]-userName:123123
2021-10-13 15:34:58.964 INFO 95776 --- [nio-8327-exec-3] c.m.common.session.SessionListener : SessionListener-------------5284BC91C799D78F4C6B7BB426ABF7A9-----------------sessionDestroyed