文档章节

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

龙之天空
 龙之天空
发布于 2015/04/21 13:21
字数 1368
阅读 170
收藏 0

最近项目有一个需求,就是用户在查询界面,输入很多查询条件之后,查询出了需要的信息,然后点击查看详细之后,希望查询列表页面时还能保存上一次的查询条件。经过同事之间的简单讨论之后,确定了实现方案。

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


本文转载自:http://mixer-b.iteye.com/blog/1563872

共有 人打赏支持
龙之天空
粉丝 7
博文 79
码字总数 18140
作品 0
宁波
私信 提问
ehcache 能取得缓存内容么?

问大家一个问题? 环境:mybatis +spring+ehcache 1.如何取得缓存后的内容呢? 2.如果缓存的对象(表) 在后台改变了数据 那怎么通过系统呢?

唐代de豆腐
2012/05/22
2.2K
4
关于Spring的缓存问题

项目中应用了Spring的Cacheable,按照Spring的文档配置的,怎么就不起作用了呢?大家都Spring的缓存有什么看法,用着怎么样?文档说可以与ehcache整合到一起用,有用过的话,谈谈你的想法。如...

IT_小翼
2012/09/29
465
2
spring+ehcache+注解的使用

spring+ehcache+注解的使用 为了提高系统的运行效率,引入缓存机制,减少数据库访问和磁盘IO。下面说明一下ehcache和spring整合配置。 总共需要四步,引入包,添加ehcache.xml文件,在sprin...

风中帆
2015/11/04
0
0
《深入理解mybatis原理》 MyBatis的一级缓存实现详解 及使用注意事项

MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓存机制上。MyBatis提供了一级缓存、二级缓存 这两个缓存机制,能够很好地处理和维护缓存,以提高系统的性能...

java梦想家01
2016/01/11
527
1
MyBatis实战缓存机制设计与原理解析

数据缓存设计结构 一级缓存 Session会话级别的缓存,位于表示一次数据库会话的对象之中,又被称之为 一级缓存是MyBatis内部实现的一个特性,,,一般用户没有定制它的权利 二级缓存 Applicat...

技术小能手
10/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

MySQL Replication 梳理详解

MySQL Replication 1 MySQL5.5以前的复制 异步、SQL线程串行化回放 MySQL内建的复制功能是构建大型,高性能应用程序的基础。主服务器将更新写入二进制日志文件,从服务器重新执行一遍来实现的...

PeakFang-BOK
今天
1
0
.NET Core & ConsoleApp & appsettings.json

准备 Visual Studio 2017 .NET Core 2.1 新建控制台应用(.NET Core) 默认的 Program.cs // Program.csusing System;namespace ConsoleApp1{ class Program { static voi......

taadis
今天
2
0
结合lucene谈谈日期的压缩问题

说起日期值的压缩,一般容易想到的办法是将日期转化成long类型,然后再通过变长整形进行压缩,我算了一下按照毫秒来算最多占用5个字节(可以通过“谈谈变长整型”中的表查看),确实节省了部...

FAT_mt
今天
1
0
导出私有函数与私有变量

在Go语言中, package中包含函数与变量通过identifier的首字母是否大写来决定它是否可以被其它package所访问。当一个函数或变量名称为小写字母时,默认是无法被其他package引用的. 有没有办法...

xtof
今天
2
0
new Date() 在Safari下的 Invalid Date问题

问题复现 var timeStr = '2018-11-11 00:00:00';var time = new Date(timeStr);// error: Invalid Date... 在safari浏览器下,time为Invalid Date, 导致后面代码执行错误; 其他浏览器诸...

会写代码的husky
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部