URL重写大部分都在http服务器端操作如apache,但是apache又不能根据参数的不同缓存不同的页面,所以大部分jsp页面都无法被缓存。Google之后发现有个urlrewrite可以在tomcat中重写url, 看过源码之后,决定改造一下,在重写url的同时将内容缓存至磁盘或内存,这样不是一举两得吗。
(后来又发现,原来还有更好的解决方法 http://ariesmonster.iteye.com/blog/807666)
主要代码如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String originalUrl = httpRequest.getRequestURI(); if (originalUrl.startsWith(contextPath)) { originalUrl = originalUrl.substring(contextPath.length()); } LOG.info("Handle request: {}", originalUrl); originalUrl = URLDecoder.decode(originalUrl, "UTF-8"); Cache cache = memoryCache.get(originalUrl); if (cache != null && cache.isValid()) { LOG.info("Hit memory cache for request {}", originalUrl); response.setContentType("text/html;charset=utf-8"); response.getWriter().print(cache.getContent()); return; } else if (cache != null) { CachedResponse cachedResponse = new CachedResponse(httpResponse); RequestDispatcher rd = request.getRequestDispatcher(cache .getTargetUrl()); rd.forward(httpRequest, cachedResponse); if (!cachedResponse.isCommitted() && cachedResponse.getStatus() == 200) { String responseBody = cachedResponse.getContent(); response.setContentType("text/html;charset=utf-8"); response.getWriter().print(responseBody); LOG.info("Update memory cache for request {}", cache .getTargetUrl()); cache.setContent(responseBody); memoryCache.put(originalUrl, cache); } return; } String targetUrl = null; Rule matchedRule = null; for (Rule rule : rules) { targetUrl = rule.execute(originalUrl); if (targetUrl != null) { matchedRule = rule; break; } } if (targetUrl == null) { LOG.info("No rule matched request: {}", originalUrl); chain.doFilter(request, response); return; } else { short cacheType = matchedRule.getCacheType(); if (cacheType == 0) { LOG.info("Rewrite request {} to {}", originalUrl, targetUrl); RequestDispatcher rd = request.getRequestDispatcher(targetUrl); rd.forward(request, response); return; } else if (cacheType == 1) { File cacheFile = new File(cacheDir, originalUrl); if (isValid(cacheFile, matchedRule.getTimeout())) { LOG.info("Hit disk cache for request {}", targetUrl); response.setContentType("text/html;charset=utf-8"); String cacheContent = FileUtils.readFileToString(cacheFile, "UTF-8"); response.getWriter().print(cacheContent); return; } else { CachedResponse cachedResponse = new CachedResponse( httpResponse); RequestDispatcher rd = request .getRequestDispatcher(targetUrl); rd.forward(httpRequest, cachedResponse); if (!response.isCommitted() && cachedResponse.getStatus() == 200) { String responseBody = cachedResponse.getContent(); response.setContentType("text/html;charset=utf-8"); response.getWriter().print(responseBody); LOG.info("Update disk cache for request {}", targetUrl); FileUtils.writeStringToFile(cacheFile, responseBody, "UTF-8"); } return; } } else if (cacheType == 2) { CachedResponse cachedResponse = new CachedResponse(httpResponse); RequestDispatcher rd = request.getRequestDispatcher(targetUrl); rd.forward(httpRequest, cachedResponse); if (!response.isCommitted() && cachedResponse.getStatus() == 200) { String responseBody = cachedResponse.getContent(); response.setContentType("text/html;charset=utf-8"); response.getWriter().print(responseBody); LOG.info("Create memory cache for request {}", targetUrl); Cache memCache = new Cache(); memCache.setTimeOut(matchedRule.getTimeout()); memCache.setContent(responseBody); memCache.setTargetUrl(targetUrl); memoryCache.put(originalUrl, memCache); } return; } } }
使用也很简单:
在web.xml中增加
<filter> <filter-name>HtmlCache</filter-name> <filter-class>com.hanvon.htmlcache.HtmlCacheFilter</filter-class> <init-param> <param-name>logLevel</param-name> <param-value>DEBUG</param-value> </init-param> <init-param> <param-name>cacheDir</param-name> <param-value>/data/htmlcache/</param-value> </init-param> </filter> <filter-mapping> <filter-name>HtmlCache</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在WEB-INF下新建配置文件htmlcache.xml
<?xml version="1.0" encoding="utf-8"?> <urlrewrite> <rule> <from>/index.html</from> <to>/home/index.html</to> <cache type="memory" timeout="30" /> <!--缓存至内存,刷新间隔30分钟--> </rule> <rule> <from>/category/([0-9]+).html</from> <to>/getBookListByCategory.action?clickedCategoryId=$1</to> <cache type="memory" timeout="60" /> <!--缓存至内存,刷新间隔60分钟--> </rule> <rule> <from>/book/([0-9]+).html</from> <to>/showBookDetail.action?bookId=$1</to> <cache type="disk" timeout="10" /> <!--缓存至磁盘,刷新间隔10分钟--> </rule> <rule> <from>/search/(.*)/(.*).html</from> <to>/searchBookByConditionLike.action?searchName=$2&searchType=$1</to> <cache type="disk" timeout="60" /> </rule> </urlrewrite>
改造之后的urlrewrite可以将/book/234.html映射为/book.jsp?id=234,并且缓存至磁盘或内存,测试结果还不错,简单实用