com.yuweix.kuafu.session.CacheHttpSession Maven / Gradle / Ivy
The newest version!
package com.yuweix.kuafu.session;
import java.util.*;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSession;
import com.yuweix.kuafu.core.json.Json;
import com.yuweix.kuafu.session.cache.SessionCache;
import com.yuweix.kuafu.session.conf.SessionConf;
import org.springframework.util.CollectionUtils;
/**
* 一个HttpSession的实现,实际的属性会储存在指定的缓存实现中。
* @author yuwei
*/
public class CacheHttpSession implements HttpSession {
private final String id;
/**
* session是否已失效
*/
private boolean invalid = false;
/**
* 存入cache的session的key
*/
private final String fullSessionId;
/**
* 如果要避免重复登录,后登录的覆盖之前登录的,如果sessionIdKey为空,表明不需要处理重复登录的问题。
* sessionIdKey用于记录存入cache的session的key。
* 如用户编号为1001,登录成功后在cache中存入两条数据:
* 1、cache.kuafu.session.008c203973554062b2b04cd3535661f1={......},
* 2、cache.kuafu.session.current.1001=cache.kuafu.session.008c203973554062b2b04cd3535661f1
* 其中cache.kuafu.session.current.1001即为sessionIdKey
*/
private String sessionIdKey;
private final String sessionIdKeyPre;
private SessionAttribute sessionAttribute;
/**
* 初始化时必须指定一个id字符串和缓存引擎实现。
* @param id id字符串。
*/
public CacheHttpSession(String id) {
SessionConf sessionConf = SessionConf.getInstance();
this.id = id;
this.sessionIdKeyPre = SessionConstant.SESSION_ID_PRE + sessionConf.getApplicationName() + "." + SessionConstant.SESSION_ID_KEY_CURRENT;
this.fullSessionId = SessionConstant.SESSION_ID_PRE + sessionConf.getApplicationName() + "." + this.id;
init();
}
/**
* 此Session的ID值。
* 这里返回存入cache的key值
* @return id值。
*/
@Override
public String getId() {
return fullSessionId;
}
/**
* 获取此Session的创建时间。
* @return 创建时间。
*/
@Override
public long getCreationTime() {
return sessionAttribute.getCreateTime().getTime();
}
/**
* 获取最后访问时间。
* @return 最后访问时间。
*/
@Override
public long getLastAccessedTime() {
return sessionAttribute.getLastAccessTime().getTime();
}
/**
* 获取当前的属性键值对。
* @return 属性键值对。
*/
public SessionAttribute getSessionAttribute() {
return sessionAttribute;
}
/**
* 表示此Session被访问。
*/
public void access() {
sessionAttribute.setLastAccessTime(Calendar.getInstance().getTime());
}
/**
* @param interval 秒
*/
@Override
public void setMaxInactiveInterval(int interval) {
SessionConf.getInstance().setMaxInactiveInterval(interval / 60);
}
@Override
public int getMaxInactiveInterval() {
return SessionConf.getInstance().getMaxInactiveInterval() * 60;
}
/**
* 获取属性值。
* @param attributeName 属性名称。
* @return 属性值。
*/
@Override
public Object getAttribute(String attributeName) {
return sessionAttribute.getAttribute(attributeName);
}
/**
* 更新属性。
* @param attributeName 属性名称。
* @param attributeValue 属性值。
*/
@Override
public void setAttribute(String attributeName, Object attributeValue) {
if (attributeValue instanceof RepeatKey) {
String rVal = ((RepeatKey) attributeValue).getValue();
sessionAttribute.putAttribute(attributeName, rVal);
this.sessionIdKey = sessionIdKeyPre + "." + rVal;
sessionAttribute.setRepeatKey(attributeName);
sessionAttribute.setRepeatValue(rVal);
} else {
sessionAttribute.putAttribute(attributeName, attributeValue);
}
}
/**
* 移除已有的属性。
* @param attributeName 属性名称。
*/
@Override
public void removeAttribute(String attributeName) {
sessionAttribute.removeAttribute(attributeName);
}
/**
* 让Session过期。
*/
@Override
public void invalidate() {
this.invalid = true;
}
/**
* 判断是否已经超过了最大活动时间。
* @return true超过,false没有超过。
*/
public boolean isInvalid() {
if (!this.invalid) {
int mii = SessionConf.getInstance().getMaxInactiveInterval();
if (mii <= 0) {
this.invalid = false;
} else {
long invalidMillis = mii * 60 * 1000L;
long lastAccessTime = getLastAccessedTime();
long now = Calendar.getInstance().getTimeInMillis();
this.invalid = (now - lastAccessTime) > invalidMillis;
}
}
return this.invalid;
}
/**
* 判断此Session是否为新的。
* @return true 为新的,false为非新的。
*/
@Override
public boolean isNew() {
return sessionAttribute.isNewBuild();
}
@Override
public int hashCode() {
return fullSessionId.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CacheHttpSession)) {
return false;
}
CacheHttpSession other = (CacheHttpSession) obj;
if (id == null && other.id == null) {
return true;
} else if (id != null && other.id != null) {
return id.equals(other.id);
}
return false;
}
public void removeSessionFromCache() {
SessionConf.getInstance().getCache().remove(fullSessionId);
if (sessionIdKey != null) {
SessionConf.getInstance().getCache().remove(sessionIdKey);
}
}
/**
* 更新当前Session至缓存。如果已经失效,从缓存中删除。
* @return sessionId
*/
public String sync() {
if (isInvalid() || sessionAttribute == null || CollectionUtils.isEmpty(sessionAttribute.getAttributes())) {
removeSessionFromCache();
return fullSessionId;
}
SessionCache sessionCache = SessionConf.getInstance().getCache();
long timeSec = SessionConf.getInstance().getMaxInactiveInterval() * 60L;
Json json = SessionConf.getInstance().getJson();
sessionCache.put(fullSessionId, json.serialize(sessionAttribute), timeSec);
/**
* 如果sessionIdKey不为空,表明需要避免重复登录
*/
if (sessionIdKey != null) {
/**
* 把当前账号之前登录的session清除掉,防止重复登录
*/
String sessionId = sessionCache.get(sessionIdKey);
if (sessionId != null && !sessionId.equals(fullSessionId)) {
sessionCache.remove(sessionId);
}
sessionCache.put(sessionIdKey, fullSessionId, timeSec);
}
return fullSessionId;
}
/**
* 初始化方法。
* 初始化缓存中的属性容器。
* 如果缓存中没有,则新建并设定创建时间和最后访问时间为当前时间和为新的会话。
*/
private void init() {
initSessionAttribute();
String repeatValue = sessionAttribute.getRepeatValue();
if (repeatValue != null && !"".equals(repeatValue)) {
this.sessionIdKey = sessionIdKeyPre + "." + repeatValue;
}
this.access();
}
private void initSessionAttribute() {
if (sessionAttribute != null) {
return;
}
Json json = SessionConf.getInstance().getJson();
sessionAttribute = json.deserialize(SessionConf.getInstance().getCache().get(fullSessionId));
if (sessionAttribute == null) {
removeSessionFromCache();
sessionAttribute = new SessionAttribute();
} else {
sessionAttribute.setNewBuild(false);
}
}
@Override
public Enumeration getAttributeNames() {
return new SessionEnumeration(sessionAttribute.getAttributes().keySet());
}
private static class SessionEnumeration implements Enumeration {
Iterator iterator;
public SessionEnumeration (Set _attributeNames) {
Set attributeNames = new HashSet<>();
if (_attributeNames != null && _attributeNames.size() > 0) {
attributeNames.addAll(_attributeNames);
}
iterator = attributeNames.iterator();
}
@Override
public boolean hasMoreElements() {
return iterator.hasNext();
}
@Override
public String nextElement() {
return iterator.next();
}
}
@Override
public ServletContext getServletContext() {
return null;
}
}