http://www.javashuo.com/article/p-xgswbwju-n.htmljava
例子是以本身在作的實際項目爲例,單服務實例。web
只是演示用,實際項目中不推薦使用。spring
單服務實例能夠用Guava等。分佈式服務能夠用Redis等。數組
package com.richfit.ruiche.common.simpleCache; import java.util.HashMap; import java.util.Map; /** * 簡單緩存管理類的實現:只是簡單封裝了 HashMap * * @author Administrator * */ public class SimpleCacheMgr { private static Map cacheMap = new HashMap(); private static SimpleCacheMgr cm = null; // 構造方法 private SimpleCacheMgr() { } public static SimpleCacheMgr getInstance() { if (cm == null) { cm = new SimpleCacheMgr(); } return cm; } /** * 增長緩存 * * @param key * @param value * @param ccm * 緩存對象 * @return */ public boolean addCache(Object key, Object value) { System.out.println("開始增長緩存-------------"); boolean flag = false; try { cacheMap.put(key, value); System.out.println("增長緩存結束-------------"); System.out.println("now addcache==" + cacheMap.size()); flag = true; } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 獲取緩存實體 */ public Object getValue(Object key) { Object ob = cacheMap.get(key); if (ob != null) { return ob; } else { return null; } } /** * 修改緩存實體 */ public Object setValue(Object key, Object value){ return cacheMap.put(key, value); } /** * 獲取緩存數據的數量 * * @return */ public int getSize() { return cacheMap.size(); } /** * 刪除緩存 * * @param key * @return */ public boolean removeCache(Object key) { boolean flag = false; try { cacheMap.remove(key); flag = true; } catch (Exception e) { e.printStackTrace(); } return flag; } }
package com.richfit.ruiche.Interceptor; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.richfit.ruiche.common.simpleCache.SimpleCacheMgr; import com.richfit.ruiche.common.specialUrl.SpecialUrl; import com.richfit.ruiche.util.LoginUtil; /** * * Description:登陸超時驗證及刷新最新登陸時間 * */ public class LoginTimeOutInterceptor extends HandlerInterceptorAdapter{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } String servletPath = request.getServletPath(); if (ifNeedCheck(servletPath)) { //驗證cookie try { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals("sec_login")) { String userName = LoginUtil.decUserName(cookie.getValue(),0); if (userName == null) { return false; } else { /** * 此處獲取登陸用戶名,從緩存中獲取並比對上次登陸時間,過時則沒法登陸;沒過時則更新最新登陸時間 */ // String loginName = DataAuthorityUtil.getLoginNameByCookies(request); SimpleCacheMgr cm= SimpleCacheMgr.getInstance(); if(cm.getValue(userName) == null){ return false; }else{ Long lastLoginTime = (Long) cm.getValue(userName); //超過了必定的時間值--這裏固定寫成了10s if(((new Date().getTime()) - lastLoginTime) > 10 * 1000){ System.out.println("======已通過期啦======"); return false; }else{ //更新最近登陸時間 cm.setValue(userName, new Date().getTime()); System.out.println("======更新登陸時間了======"); return true; } } /** * 此處獲取登陸用戶名,從緩存中獲取並比對上次登陸時間,過時則沒法登陸;沒過時則更新最新登陸時間 */ } } break; } } } catch (Exception ex) { return false; } } return true; } /** * * Description:是否須要驗證鏈接判斷。能夠經過的URL:web端除【登陸】和【獲取新密碼】外全部的鏈接 * @Version1.0 2017-2-16 上午11:38:36 by 丁兆寧 (dingzhaoning@cnpc.com.cn) * @param servletPath * @return */ private boolean ifNeedCheck(String servletPath){ List<String> noNeedCheckUrlList = getNoNeedCheckUrlList(); for(String s:noNeedCheckUrlList){ if(servletPath.matches(s)){ return false; } } return true; } private List<String> getNoNeedCheckUrlList(){ List<String> list = new ArrayList<String>(); list.addAll(SpecialUrl.getNoNeedCheckUrlList()); return list; } }
/** * * 在這個類裏註冊自定義的攔截器 */ @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.richfit.ruiche.Interceptor") public class WebAppConfig extends WebMvcConfigurerAdapter{ @Bean public ReturnMessageInterceptor returnMessageInterceptor(){ return new ReturnMessageInterceptor(); } @Bean public ReturnMessageTimeHandlerInterceptor returnMessageTimeHandlerInterceptor(){ return new ReturnMessageTimeHandlerInterceptor(); } /** * * Description:web端登陸攔截器 * @return */ @Bean public LoginInterceptor loginInterceptor(){ return new LoginInterceptor(); } /** * * Description:web端訪問路徑權限攔截器 * @return */ @Bean public AccessInterceptor accessInterceptor(){ return new AccessInterceptor(); } /** * * Description:公務車APP端登陸攔截器 * @return */ @Bean public OfficalLoginInterceptor officalLoginInterceptor(){ return new OfficalLoginInterceptor(); } /** * * Description:APP端SessionListener * @return */ @Bean public SessionListener sessionListener() { return new SessionListener(); } @Bean public LoginTimeOutInterceptor loginTimeOutInterceptor(){ return new LoginTimeOutInterceptor(); } /** * 1.這裏的攔截器在容器初始化時加載在 HandlerExecutionChain 的 interceptors 變量裏 * 2.interceptors 先加載用戶定義的攔截器,再加載 SpringMVC 默認的攔截器 * 3.用戶定義的攔截器數組數據標號跟下面的順序一致。pre前處理是正序來處理;post後處理是按倒序來處理 */ @Override public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor((HandlerInterceptor) returnMessageInterceptor()); // registry.addInterceptor((HandlerInterceptor) returnMessageTimeHandlerInterceptor()); registry.addInterceptor((HandlerInterceptor) loginInterceptor()); registry.addInterceptor((HandlerInterceptor) accessInterceptor()); // registry.addInterceptor((HandlerInterceptor) appLoginInterceptor()); registry.addInterceptor((HandlerInterceptor) officalLoginInterceptor()); registry.addInterceptor((HandlerInterceptor) loginTimeOutInterceptor()); } @Bean public TaskScheduler scheduledExecutorService() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(8); scheduler.setThreadNamePrefix("scheduled-thread-"); return scheduler; } }
/** * 登陸成功在緩存中寫入最新登陸時間 */ SimpleCacheMgr cm= SimpleCacheMgr.getInstance(); cm.addCache(name, new Date().getTime());
登陸成功,同時控制檯打印有如下語句,說明登陸成功後增長了緩存緩存
控制檯打印以下cookie
沒有返回由於已經被攔截,控制檯打印以下session
由於緩存的key、value都是用的Object,很簡單的一個方法就是直接用HashMap<String,HashMap<String,Long>>()這樣的結構存儲用戶過時時間,key起名爲」longinOutTime」,取的時候就根據key名爲」longinOutTime」獲取HashMap<String,Long>結構,而後再在HashMap<String,Long>結構中存儲每一個用戶名的過時時間。app
若是存別的數據,好比菜單,那麼key起名爲」menu」。value根據實際狀況存儲便可。框架
固然,這只是個思路而已,很low,實際項目不會那麼幹。並且受HashMap大小限制,存儲數據是有限的,應用中若是要存儲的數據量過大,就會爆掉。分佈式
package com.richfit.ruiche.common.cache; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * 緩存管理類 * 相對於 SimpleCacheMgr 增長了緩存屬性參數,會根據屬性參數的值按期清理緩存 * @author Administrator * */ public class CacheMgr { private static Map cacheMap = new HashMap(); private static Map cacheConfMap = new HashMap(); private static CacheMgr cm = null; // 構造方法 private CacheMgr() { } public static CacheMgr getInstance() { if (cm == null) { cm = new CacheMgr(); Thread t = new ClearCache(); t.start(); } return cm; } /** * 增長緩存 * * @param key * @param value * @param ccm * 緩存對象 * @return */ public boolean addCache(Object key, Object value, CacheConfModel ccm) { System.out.println("開始增長緩存-------------"); boolean flag = false; try { cacheMap.put(key, value); cacheConfMap.put(key, ccm); System.out.println("增長緩存結束-------------"); System.out.println("now addcache==" + cacheMap.size()); flag = true; } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 獲取緩存實體 */ public Object getValue(String key) { Object ob = cacheMap.get(key); if (ob != null) { return ob; } else { return null; } } /** * 獲取緩存數據的數量 * * @return */ public int getSize() { return cacheMap.size(); } /** * 刪除緩存 * * @param key * @return */ public boolean removeCache(Object key) { boolean flag = false; try { cacheMap.remove(key); cacheConfMap.remove(key); flag = true; } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 清除緩存的類 繼承Thread線程類 */ private static class ClearCache extends Thread { public void run() { while (true) { Set tempSet = new HashSet(); Set set = cacheConfMap.keySet(); Iterator it = set.iterator(); while (it.hasNext()) { Object key = it.next(); CacheConfModel ccm = (CacheConfModel) cacheConfMap.get(key); // 比較是否須要清除 if (!ccm.isForever()) { if ((new Date().getTime() - ccm.getBeginTime()) >= ccm .getDurableTime() * 60 * 1000) { // 能夠清除,先記錄下來 tempSet.add(key); } } } // 真正清除 Iterator tempIt = tempSet.iterator(); while (tempIt.hasNext()) { Object key = tempIt.next(); cacheMap.remove(key); cacheConfMap.remove(key); } System.out.println("now thread================>" + cacheMap.size()); // 休息 try { Thread.sleep(60 * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
package com.richfit.ruiche.common.cache; /** * 緩存屬性類 * * @author Administrator * */ public class CacheConfModel implements java.io.Serializable { /** * */ private static final long serialVersionUID = 1L; private long beginTime;// 緩存開始時間 private boolean isForever = false;// 是否持久 private int durableTime;// 持續時間 public long getBeginTime() { return beginTime; } public void setBeginTime(long beginTime) { this.beginTime = beginTime; } public boolean isForever() { return isForever; } public void setForever(boolean isForever) { this.isForever = isForever; } public int getDurableTime() { return durableTime; } public void setDurableTime(int durableTime) { this.durableTime = durableTime; } }
每次增長緩存數據時會帶上如下配置屬性:
private long beginTime;// 緩存開始時間 private boolean isForever = false;// 是否持久 private int durableTime;// 持續時間
而且緩存小框架帶有按期清除過時緩存的功能。結合上面例子,能夠將是否持久設置爲false,持續時間根據項目實際需求設置,每次訪問均可在攔截器中更新緩存開始時間。這樣,到了設置的持續時間,緩存小框架就自動把過時緩存自動清理掉了。
具體的還要實際調試代碼,看是否有須要改進的地方。