背景:需要记录小程序用户登陆的sessionid并与其openid关联,定时清除
核心代码实现
总体思路:使用ConcurrentHashMap去存缓存的对象,PriorityBlockingQueue去优化弹出(定时移除,按失效时间排序),ScheduledExecutorService去定期执行移除,初始化时调用单例对象的initial()方法
import java.text.DecimalFormat;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserSessionKeyCache {
private static Logger LOGGER = LoggerFactory.getLogger(UserSessionKeyCache.class);
private static UserSessionKeyCache singleton;
private final static Map<String, UserSessionKey> USER_SESSIONKEY_CACHE = new ConcurrentHashMap<>();// key 为sessionId
// value为用户的sessionkey和openid
private static ScheduledExecutorService swapExpiredPool = new ScheduledThreadPoolExecutor(1);// 2线程去
// 移除过期时间的map和queue数据
private static PriorityBlockingQueue<UserSessionKey> queue = new PriorityBlockingQueue<>();// 按生成时间排序的队列
public static synchronized UserSessionKeyCache initial() {
LOGGER.info("初始化任务");
if (singleton == null) {
singleton = new UserSessionKeyCache();
synchronized (UserSessionKeyCache.class) {
swapExpiredPool.scheduleWithFixedDelay(() -> {
LOGGER.info("执行任务");
long now = System.currentTimeMillis();
// TODO Auto-generated method stub
while (true) {
UserSessionKey keyInfo = queue.peek();
if (keyInfo == null || keyInfo.getCreateTime() + TIME_ONE_TEN_DAYS > now) {
return;
}
USER_SESSIONKEY_CACHE.remove(keyInfo.getPrivateSessionId());
UserSessionKey deleted = queue.poll();
LOGGER.info("删除" + deleted.getPrivateSessionId());
}
}, 1, 1, TimeUnit.DAYS);
}
}
return singleton;
}
public static void put(String key, UserSessionKey keyInfo) {
UserSessionKey oldKeyInfo = USER_SESSIONKEY_CACHE.put(key, keyInfo);
if (oldKeyInfo != null) {
queue.remove(oldKeyInfo);
}
queue.add(keyInfo);
}
public static UserSessionKey get(String key) {
UserSessionKey keyInfo = USER_SESSIONKEY_CACHE.get(key);
if (keyInfo != null && (keyInfo.getCreateTime() + TIME_ONE_WEEK >= System.currentTimeMillis())) {
return keyInfo;
}
return null;
}
public static void removeCache(String key) {
USER_SESSIONKEY_CACHE.remove(key);
}
}
缓存的对象
public class UserSessionKey implements Comparable<UserSessionKey> {
private Long id;
private String privateSessionId;
private String sessionKey;
private String openId;
private Long createTime;
。。。。省略getter setter
@Override
public int compareTo(UserSessionKey o) {
// TODO Auto-generated method stub
long r = this.createTime - o.createTime;
if (r > 0) {
return 1;
}
if (r < 0) {
return -1;
}
return 0;
}
登陆时去存用户信息
public String cacheSession(String openId, HttpServletRequest request) {
String currentSessionKey = uskDAO.queryUserSessionKeyByOpenId(openId);
// HttpSession session=request.getSession();
String privateSessionId = createSessionId(openId, currentSessionKey);
/*
* Map<String,String> sessionkeyMap=new HashMap<>();//存sessionkey和openid
* sessionkeyMap.put("sessionKey", currentSessionKey);
* sessionkeyMap.put("openId", openId);
*/
UserSessionKey keyInfo = new UserSessionKey();
keyInfo.setOpenId(openId);
keyInfo.setCreateTime(System.currentTimeMillis());
keyInfo.setPrivateSessionId(privateSessionId);
UserSessionKeyCache.put(privateSessionId, keyInfo);
System.out.println(privateSessionId);
// session.setAttribute(sessionId, sessionkeyMap);//session存 sessionid为key
// sessionkey openid为value
return privateSessionId;
}
登陆拦截器去取用户openid
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.util.StringUtils;
import com.alibaba.druid.support.json.JSONUtils;
@Component
public class SessionInterceptor implements HandlerInterceptor {
@Autowired
IUsersService uService;
@Autowired
UserHostHolder userHostHolder;
private final static Logger logger = LoggerFactory.getLogger(SessionInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
throws Exception {
String privateSessionId = httpServletRequest.getHeader("sessionId");
if (StringUtils.isEmpty(privateSessionId)) {
return true;
}
UserSessionKey sessionkeyMap = UserSessionKeyCache.get(privateSessionId);
if (sessionkeyMap != null) {
String openId = sessionkeyMap.getOpenId();
if (!StringUtils.isEmpty(openId)) {
Users currentUser = uService.queryUserIdByOpenId(openId);
if (currentUser != null && currentUser.getUserStatus().equals(USER_STATUS_ACTIVATED) ) {
userHostHolder.setUser(currentUser);
Map<String,String[]> m=httpServletRequest.getParameterMap();
JSONObject j=new JSONObject(m);
String headers=RequestHeaderUtils.getAllHeaders(httpServletRequest);
logger.debug("START: 用户: {} ,请求链接: {}, 请求方式:{}, 请求参数:{}, 请求头:{}",currentUser.getUserId(),httpServletRequest.getRequestURI(),httpServletRequest.getMethod(),
j.toString(),headers);
return true;
} else {
responseErrorMsg(httpServletResponse);
Map<String,String[]> m=httpServletRequest.getParameterMap();
JSONObject j=new JSONObject(m);
String headers=RequestHeaderUtils.getAllHeaders(httpServletRequest);
logger.debug("START:!!!用户被禁用/信息异常---用户: {} ,请求链接: {}, 请求方式:{} 请求参数:{}, 请求头:{}",currentUser.getUserId(),httpServletRequest.getRequestURI(),httpServletRequest.getMethod(),
j.toString(),headers);
return false;
}
}
} else {
responseReloginMsg(httpServletResponse);
return false;
}
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
try {
userHostHolder.clear();
} finally {
userHostHolder.clear();
}
}
private void responseErrorMsg(HttpServletResponse httpServletResponse) {
httpServletResponse.reset();// 设置编码格式
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json;charset=UTF-8");
PrintWriter pw = null;
try {
Map<String, Object> resultMap = new HashMap<>();
pw = httpServletResponse.getWriter();
resultMap.put("retDesc", "用户被禁用");
resultMap.put("retCode", RESPONSE_CODE1001);
pw.write(JSONUtils.toJSONString(resultMap));
pw.flush();
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
pw.close();
}
}
private void responseReloginMsg(HttpServletResponse httpServletResponse) {
httpServletResponse.reset();// 设置编码格式
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json;charset=UTF-8");
PrintWriter pw = null;
try {
Map<String, Object> resultMap = new HashMap<>();
pw = httpServletResponse.getWriter();
resultMap.put("retDesc", "登陆过期");
resultMap.put("retCode", RESPONSE_CODE1002);
pw.write(JSONUtils.toJSONString(resultMap));
pw.flush();
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
pw.close();
}
}
}
如有错误请指正!
相互学习