spring+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标签定义拦截器。
   
    Html代码
   
    1.<util:list id="interceptors">
   
    2.     <bean class="mon.cache.SearchCacheInterceptor"/>
   
    3.</util:list>
   
    4.
   
    5.<!-- 定义注解URL映射处理器 -->
   
    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="-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 mon.cache;
   
    2.
   
    3.import .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 mon.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 mon.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.        ("记录查询参数拦截器******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.                    ("取出缓存的查询参数,重定向连接");
   
    43.                    response.sendRedirect(request.getRequestURL()+(String)e.getValue());
   
    44.                    return false;
   
    45.                }
   
    46.            } else {
   
    47.                ("更新查询参数");
   
    48.                CacheStore.put(new Element(ip+ userName + url, changeMapToString(paramsMap)));
   
    49.            }
   
    50.        }
   
    51.        ("记录查询参数拦截器******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各单位来实现功能。我个人提倡,用框架的时候多想想实现,别一味的用,要不然用到老,还是在用别人的框架,永远写不出自己的框架。

你可能感兴趣的:(ehcache)