读书人

spring+ehcache实现的缓存查询参数

发布时间: 2012-09-13 09:51:53 作者: rapoo

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="com.netqin.common.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="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各单位来实现功能。我个人提倡,用框架的时候多想想实现,别一味的用,要不然用到老,还是在用别人的框架,永远写不出自己的框架。

读书人网 >编程

热点推荐