spring+ehcache實現的緩存查詢參數。

最近項目有一個需求,就是用戶在查詢界面,輸入不少查詢條件以後,查詢出了須要的信息,而後點擊查看詳細以後,但願查詢列表頁面時還能保存上一次的查詢條件。通過同事之間的簡單討論以後,肯定了實現方案。java

用spring的攔截器,攔截到用戶的全部list.do請求,保存下list.do,把裏面的request。paramaterMap轉換成字符串(注意中文轉碼),以ip+username+功能模塊url爲key,保存下來,用戶在詳細信息頁面點擊返回時,返回鏈接須要帶goback參數,攔截器監測到請求參數裏包含goback時,就用ip+username+功能模塊url把保存的值拿出來,以後response.sendRedirect(request.getRequestURL()+str).web

上面只是大致實現的歸納,下面看代碼。spring

定義spring攔截器,項目的spring版本是2.5的,不支持mvc:interceptors標籤訂義攔截器。apache

Html代碼 編程

  1. <util:list id="interceptors">  瀏覽器

  2.      <bean class="com.netqin.common.cache.SearchCacheInterceptor"/>    緩存

  3. </util:list>  mvc

  4.   

  5. <!-- 定義註解URL映射處理器 -->  app

  6. <bean id="urlMapping"  框架

  7.     class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">  

  8.     <property name="interceptors" ref="interceptors" />  

  9.     <property name="order" value="1"></property>  

  10. </bean>  

使用的是DefaultAnnotationHandlerMapping這個spring默認的基於註解的請求攔截器類。

ehcache用的是1.72版本,配置文件ehcache.xml爲:

Html代碼 

  1. <?xml version="1.0" encoding="UTF-8"?>  

  2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

  3.     xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"  

  4.     monitoring="autodetect">  

  5.     <diskStore path="F:/appstore/ehcache"/>  

  6.     <defaultCache  

  7.             maxElementsInMemory="10000"  

  8.             eternal="false"  

  9.             timeToIdleSeconds="1800"  

  10.             timeToLiveSeconds="1800"  

  11.             overflowToDisk="true"  

  12.             maxElementsOnDisk="10000000"  

  13.             diskPersistent="false"  

  14.             diskExpiryThreadIntervalSeconds="120"  

  15.             memoryStoreEvictionPolicy="LRU"  

  16.             />  

  17.      <cache name="UrlCache"  

  18.            maxElementsInMemory="8000"  

  19.            maxElementsOnDisk="10000000"  

  20.            eternal="false"  

  21.            overflowToDisk="true"  

  22.            diskSpoolBufferSizeMB="20"  

  23.            memoryStoreEvictionPolicy="LFU"  

  24.             />  

  25. </ehcache>  

而且對ehcache進行了簡單封裝(不是我封裝的):

Java代碼 

  1. package com.netqin.common.cache;  

  2.   

  3. import java.net.URL;  

  4. import java.util.HashMap;  

  5. import java.util.Map;  

  6.   

  7. import net.sf.ehcache.Cache;  

  8. import net.sf.ehcache.CacheManager;  

  9. import net.sf.ehcache.Element;  

  10.   

  11. /** 

  12.  * cache管理器 

  13.  *  

  14.  * @author HANQUNFENG 

  15.  *  

  16.  */  

  17. public class CacheStore {  

  18.     private static CacheManager manager;  

  19.     private static Cache cache;  

  20.     static {  

  21.         CacheStore cs = new CacheStore();  

  22.         cs.init();  

  23.     }  

  24.   

  25.     /** 

  26.      * 初試化cache 

  27.      */  

  28.     private void init() {  

  29.         URL url = getClass().getResource("/config/context/ehcache.xml");  

  30.         manager = new CacheManager(url);  

  31.         cache = manager.getCache("UrlCache");  

  32.     }  

  33.   

  34.     /** 

  35.      * 清除cache 

  36.      */  

  37.     @SuppressWarnings("unused")  

  38.     private void destory() {  

  39.         manager.shutdown();  

  40.     }  

  41.   

  42.     /** 

  43.      * 獲得某個key的cache值 

  44.      *  

  45.      * @param key 

  46.      * @return  

  47.      */  

  48.     public static Element get(String key) {  

  49.         return cache.get(key);  

  50.     }  

  51.   

  52.     /** 

  53.      * 清楚key的cache 

  54.      *  

  55.      * @param key 

  56.      */  

  57.     public static void remove(String key) {  

  58.         cache.remove(key);  

  59.     }  

  60.   

  61.     /** 

  62.      * 設置或更新某個cache值 

  63.      *  

  64.      * @param element 

  65.      */  

  66.     public static void put(Element element) {  

  67.         cache.put(element);  

  68.     }  

  69.       

  70.     public static void removeAll(){  

  71.         cache.removeAll();  

  72.     }  

  73.   

  74.       

  75.   

  76.     public static void main(String[] args) {  

  77.         Map m = new HashMap();  

  78.         m.put("1""1");  

  79.         m.put("2""2");  

  80.         m.put("3""3");  

  81.         Map m1 = new HashMap();  

  82.         m1.put("11""11");  

  83.         m1.put("21""21");  

  84.         m1.put("31""31");  

  85.         CacheStore.remove("1");  

  86.         System.out.println(CacheStore.get("1"));  

  87.         System.out.println(CacheStore.get("2"));  

  88.         System.out.println(CacheStore.get("2"));  

  89.         CacheStore.removeAll();  

  90.         System.out.println(CacheStore.get("2"));  

  91.         System.out.println(CacheStore.get("3"));  

  92.         System.out.println("------end-----");  

  93.     }  

  94. }  

下載ehcache.jar

 


攔截器代碼:

Java代碼 

  1. package com.netqin.common.cache;  

  2.   

  3. import java.io.UnsupportedEncodingException;  

  4. import java.util.Arrays;  

  5. import java.util.Map;  

  6.   

  7. import javax.servlet.http.HttpServletRequest;  

  8. import javax.servlet.http.HttpServletResponse;  

  9.   

  10. import net.sf.ehcache.Element;  

  11.   

  12. import org.apache.log4j.Logger;  

  13. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  

  14.   

  15. import com.netqin.common.util.AuthenticationUtils;  

  16.   

  17. /** 

  18.  * 查詢條件緩存的攔截器 

  19.  *  

  20.  * @author KingViker 

  21.  *  

  22.  */  

  23. public class SearchCacheInterceptor extends HandlerInterceptorAdapter  

  24. {  

  25.     private static final Logger logger = Logger  

  26.             .getLogger(SearchCacheInterceptor.class);  

  27.   

  28.     @SuppressWarnings("unchecked")  

  29.     @Override  

  30.     public boolean preHandle(HttpServletRequest request,  

  31.             HttpServletResponse response, Object handler)throws Exception {  

  32.         logger.info("記錄查詢參數攔截器******begin");  

  33.         String url = request.getServletPath();  

  34.         String ip = request.getRemoteAddr();  

  35.         Map<String, String[]> paramsMap = request.getParameterMap();  

  36.         String userName = AuthenticationUtils.getUsername();  

  37.         if (url.indexOf("list.do") != -1) {  

  38.             if (paramsMap.get("goBack") != null) {  

  39.                 Element e = CacheStore.get(ip  

  40.                 + userName + url);  

  41.                 if (e != null) {  

  42.                     logger.info("取出緩存的查詢參數,重定向鏈接");  

  43.                     response.sendRedirect(request.getRequestURL()+(String)e.getValue());  

  44.                     return false;  

  45.                 }  

  46.             } else {  

  47.                 logger.info("更新查詢參數");  

  48.                 CacheStore.put(new Element(ip+ userName + url, changeMapToString(paramsMap)));  

  49.             }  

  50.         }  

  51.         logger.info("記錄查詢參數攔截器******begin");  

  52.         return true;  

  53.     }  

  54.   

  55.     private String changeMapToString(Map<String, String[]> paramsMap) {  

  56.         StringBuffer url = new StringBuffer();  

  57.         url.append("?");  

  58.         for(Map.Entry<String, String[]> entry :paramsMap.entrySet()){  

  59.             String key = entry.getKey();  

  60.             String [] value = entry.getValue();  

  61.             url.append(key+"="+encodeUrl(Arrays.toString(value)));  

  62.             url.append("&");  

  63.         }  

  64.         System.out.println(url);  

  65.         return url.toString();  

  66.     }  

  67.     private String encodeUrl(String value) {  

  68.         String result = "";  

  69.         result = value.replaceAll("\\[""").replaceAll("\\]""");  

  70.         try {  

  71.             byte temp[]=result.getBytes("UTF-8");  

  72.             result=new String(temp,"ISO-8859-1");      

  73.         } catch (UnsupportedEncodingException e) {  

  74.             e.printStackTrace();  

  75.         }      

  76.         return result;  

  77.     }  

  78. }  

攔截器類繼承自HandlerInterceptorAdapter,重寫了prehandle方法。prehandle是在請求前執行,還能夠重寫afterCompletion和postHandle兩個方法,分別是請求後和請求先後執行。


個人攔截器的代碼原先的邏輯不是這樣。我原先的邏輯是利用反射直接更改request的parameterMap保存的值,不須要其餘的操做很簡單,也不須要重定向。可是這個思路有兩個問題:

1.我用ehcache保存時直接保存的是parameterMap的引用,每次請求過來以後spring都會清空而且從新初始化這個map,致使ehcache未能緩存到真正的數據。

2.在測試時發現,spring框架從請求接受參數後而且封裝到了bean裏面以後請求才能攔截到,也就是說我更改了parameterMap的值,controller收到的請求仍是未更改的數據。

因此我改變了思路,把每次請求的parameterMap對象封裝成字符串而後在緩存,須要使用緩存時,直接取出並重定向sendredirectt。

可是sendreditect是get方式的請求,瀏覽器通常會把請求鏈接中的中文參數進行轉碼,轉成ISO-8859-1,產生了亂碼問題,因此須要在連接後面拼接參數時須要對中文轉碼。這也就是上面的encodeUrl函數的做用。


寫這篇文章的目的只是介紹一下實現思路和用到的一些現有框架,以及其中遇到的一些問題。給一些須要實現相似功能的道友一個實現思路而已。這裏不提供源碼,我我的是很不喜歡伸手黨的。就是由於編程界有太多的伸手黨,致使了不少人能作一些項目,可是出現問題就不知道怎麼改,或者明明性能上只須要1各單位,恰恰不知因此然的用了10各單位來實現功能。我我的提倡,用框架的時候多想一想實現,別一味的用,要否則用到老,仍是在用別人的框架,永遠寫不出本身的框架。

相關文章
相關標籤/搜索