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

openkk 12年前發布 | 33K 次閱讀 JEE框架 Ehcache

最近項目有一個需求,就是用戶在查詢界面,輸入很多查詢條件之后,查詢出了需要的信息,然后點擊查看詳細之后,希望查詢列表頁面時還能保存上一次的查詢條件。經過同事之間的簡單討論之后,確定了實現方案。

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

上面只是大體實現的概括,下面看代碼。

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

  <util:list id="interceptors">
         <bean class="com.netqin.common.cache.SearchCacheInterceptor"/>  
    </util:list>

    <!-- 定義注解URL映射處理器 -->
    <bean id="urlMapping"
        class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="interceptors" ref="interceptors" />
        <property name="order" value="1"></property>
    </bean>

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

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

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
    monitoring="autodetect">
    <diskStore path="F:/appstore/ehcache"/>
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
     <cache name="UrlCache"
           maxElementsInMemory="8000"
           maxElementsOnDisk="10000000"
           eternal="false"
           overflowToDisk="true"
           diskSpoolBufferSizeMB="20"
           memoryStoreEvictionPolicy="LFU"
            />
</ehcache>
并且對ehcache進行了簡單封裝(不是我封裝的):
package com.netqin.common.cache;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

/**
 * cache管理器
 * 
 * @author HANQUNFENG
 * 
 */
public class CacheStore {
    private static CacheManager manager;
    private static Cache cache;
    static {
        CacheStore cs = new CacheStore();
        cs.init();
    }

    /**
     * 初試化cache
     */
    private void init() {
        URL url = getClass().getResource("/config/context/ehcache.xml");
        manager = new CacheManager(url);
        cache = manager.getCache("UrlCache");
    }

    /**
     * 清除cache
     */
    @SuppressWarnings("unused")
    private void destory() {
        manager.shutdown();
    }

    /**
     * 得到某個key的cache值
     * 
     * @param key
     * @return
     */
    public static Element get(String key) {
        return cache.get(key);
    }

    /**
     * 清楚key的cache
     * 
     * @param key
     */
    public static void remove(String key) {
        cache.remove(key);
    }

    /**
     * 設置或更新某個cache值
     * 
     * @param element
     */
    public static void put(Element element) {
        cache.put(element);
    }

    public static void removeAll(){
        cache.removeAll();
    }



    public static void main(String[] args) {
        Map m = new HashMap();
        m.put("1", "1");
        m.put("2", "2");
        m.put("3", "3");
        Map m1 = new HashMap();
        m1.put("11", "11");
        m1.put("21", "21");
        m1.put("31", "31");
        CacheStore.remove("1");
        System.out.println(CacheStore.get("1"));
        System.out.println(CacheStore.get("2"));
        System.out.println(CacheStore.get("2"));
        CacheStore.removeAll();
        System.out.println(CacheStore.get("2"));
        System.out.println(CacheStore.get("3"));
        System.out.println("------end-----");
    }
}
下載ehcache.jar


攔截器代碼:

package com.netqin.common.cache;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.ehcache.Element;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.netqin.common.util.AuthenticationUtils;

/**
 * 查詢條件緩存的攔截器
 * 
 * @author KingViker
 * 
 */
public class SearchCacheInterceptor extends HandlerInterceptorAdapter
{
    private static final Logger logger = Logger
            .getLogger(SearchCacheInterceptor.class);

    @SuppressWarnings("unchecked")
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler)throws Exception {
        logger.info("記錄查詢參數攔截器******begin");
        String url = request.getServletPath();
        String ip = request.getRemoteAddr();
        Map<String, String[]> paramsMap = request.getParameterMap();
        String userName = AuthenticationUtils.getUsername();
        if (url.indexOf("list.do") != -1) {
            if (paramsMap.get("goBack") != null) {
                Element e = CacheStore.get(ip
                + userName + url);
                if (e != null) {
                    logger.info("取出緩存的查詢參數,重定向連接");
                    response.sendRedirect(request.getRequestURL()+(String)e.getValue());
                    return false;
                }
            } else {
                logger.info("更新查詢參數");
                CacheStore.put(new Element(ip+ userName + url, changeMapToString(paramsMap)));
            }
        }
        logger.info("記錄查詢參數攔截器******begin");
        return true;
    }

    private String changeMapToString(Map<String, String[]> paramsMap) {
        StringBuffer url = new StringBuffer();
        url.append("?");
        for(Map.Entry<String, String[]> entry :paramsMap.entrySet()){
            String key = entry.getKey();
            String [] value = entry.getValue();
            url.append(key+"="+encodeUrl(Arrays.toString(value)));
            url.append("&");
        }
        System.out.println(url);
        return url.toString();
    }
    private String encodeUrl(String value) {
        String result = "";
        result = value.replaceAll("\\[", "").replaceAll("\\]", "");
        try {
            byte temp[]=result.getBytes("UTF-8");
            result=new String(temp,"ISO-8859-1");    
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }    
        return result;
    }
}
攔截器類繼承自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各單位來實現功能。我個人提倡,用框架的時候多想想實現,別一味的用,要不然用到老,還是在用別人的框架,永遠寫不出自己的框架。
轉自:http://blog.csdn.net/qq413041153/article/details/7631676

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!