Sparkle’s Workshop

PageCacheFilter2

Posted on December 31, 2007 - Filed Under Uncategorized |

最近翻起一年多前在上一家公司写的代码,发现也有不少工具性质的类,于是整理一下都贴出来吧

/**
 * 2006-5-1
 * @author Sparkle
 */
public class PageCacheFilter2 implements Filter {
	private Set<String> cacheUrlSet = new HashSet<String>();
	private Set<String> scacheUrlSet = new HashSet<String>();
	private String baseCachePath, contentType;
 
	public void init(FilterConfig config) throws ServletException {
		String cacheUrl = config.getInitParameter("cacheUrl");
		if (cacheUrl != null) {
			StringTokenizer tk = new StringTokenizer(cacheUrl);
			while (tk.hasMoreTokens()) {
				String str = tk.nextToken().trim().toLowerCase();
				if (str.endsWith("?")) {
					str = str.substring(0, str.length() - 1);
					scacheUrlSet.add(str);
				}
				cacheUrlSet.add(str);
			}
		}
		baseCachePath = config.getInitParameter("cachePath");
		contentType = config.getInitParameter("contentType");
	}
 
	private int urlHashCode(HttpServletRequest request) {
		String uri = request.getRequestURI();
		String qStr = request.getQueryString();
		if (qStr != null) {
			uri += ('?' + qStr);
		}
		return Math.abs(uri.hashCode());
	}
 
	private String cacheFilePath(HttpServletRequest request) {
		String uri = request.getRequestURI();
		int hash = urlHashCode(request);
		if (scacheUrlSet.contains(uri.toLowerCase())) {
			String entityId = request.getParameter("entityId");
			if (StringUtils.isNotBlank(entityId)) {
				return baseCachePath + "/article/" + subDir(entityId)
						+ '/' + entityId + '/' + hash + ".wml";
			}
		}
		return baseCachePath + "/other/" + subDir2(String.valueOf(hash))
				+ '/' + hash + ".wml";
	}
 
	private String subDir(String str) {
		int length = str.length();
		if (length > 4) {
			return str.substring(0, length - 4);
		}
		return "0";
	}
 
	private String subDir2(String str) {
		int length = str.length();
		if (length > 4) {
			return str.substring(length - 4, length);
		}
		return str;
	}
 
	private void clearCache(HttpServletRequest request, File cacheFile) {
		if (scacheUrlSet.contains(request.getRequestURI().toLowerCase())) {
			File cacheDir = cacheFile.getParentFile();
			for (File file : cacheDir.listFiles()) {
				file.delete();
			}
			cacheDir.delete();
		} else {
			cacheFile.delete();
		}
	}
 
	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		if (!cacheUrlSet.contains(request.getRequestURI().toLowerCase())) {
			chain.doFilter(req, res);
			return;
		}
 
		HttpServletResponse response = (HttpServletResponse) res;
 
		File cacheFile = new File(cacheFilePath(request));
		if (cacheFile.isFile()) {
			if (request.getParameter("refresh") != null) {
				clearCache(request, cacheFile);
			} else {
				try {
					BufferedReader reader = new BufferedReader(
							new FileReader(cacheFile));
					response.setContentType(contentType);
					String line;
					PrintWriter printWriter = response.getWriter();
					while ((line = reader.readLine()) != null) {
						printWriter.println(line);
					}
					printWriter.close();
					return;
				} catch (IOException e) {
					// ignore
					response.reset();
					System.out.println("read cache file error");
				}
			}
 
		}
 
		StringWriter strWriter = new StringWriter();
		boolean[] support = new boolean[1];
		support[0] = true;
		chain.doFilter(req, new ContentResponseWrapper(response, strWriter,
				support));
		if (support[0] && !response.isCommitted()) {
			String content = strWriter.getBuffer().toString();
 
			PrintWriter printWriter = response.getWriter();
			printWriter.println(content);
			printWriter.close();
 
			File cacheDir = cacheFile.getParentFile();
			if (!cacheDir.exists()) {
				cacheDir.mkdirs();
			}
			PrintWriter writer = new PrintWriter(cacheFile);
			writer.println(content);
			writer.close();
		}
 
	}
 
	public void destroy() {
	}
 
}

代码点评:这段代码的作用是,对指定的url进行cache,用了ContentRewriteFilter一样的做法来获取内容,因为具体的细节有些区别,没有继承ContentRewriteFilter而是直接编写代码。先判断是否有cache文件,如果有就输出给用户,但是如果连接上有refresh参数的话,就会清掉cache文件,如果没有cache文件,就会获取Servlet or JSP输出的内容,原原本本保存到磁盘,供下次用户访问使用。如果设置URL的时候,最后一位是问号,就会进入scacheUrlSet,这个是用于文章类型,主要的不同点是有分页,如果要refresh的话,应该要把所有分页的cache文件都清除。至于类名后面有个2,是因为这个是第二个版本。

(最近在考虑用Squid+Etag来实现一样的功能)

Related Post

Comments

Leave a Reply