JAVA实现HASHMAP缓存 并定时清理

1 篇文章 0 订阅
1 篇文章 0 订阅

背景:需要记录小程序用户登陆的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();
		}
	}
}

如有错误请指正!
相互学习

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值