importcom.xxxxxx.platform.common.redis.RedisUtil;importorg.apache.commons.lang.StringUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;import javax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.concurrent.Semaphore;public class RedisPageCacheFilter implementsFilter {private static final Logger log = LoggerFactory.getLogger(RedisPageCacheFilter.class);private final static String FILTER_URL_PATTERNS = "patterns";private staticString[] cacheURLs;private static inttimeOut;//加入信号量防止缓存穿透,缓存失效时只能同时1个用户访问数据库,防止数据库被顶爆
private static final Semaphore semp = new Semaphore(1);
@Overridepublic void init(FilterConfig config) throwsServletException {
String patterns=config.getInitParameter(FILTER_URL_PATTERNS);
timeOut= Integer.parseInt(config.getInitParameter("expireTime"));
cacheURLs= StringUtils.split(patterns, ",");
}
@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throwsIOException, ServletException {
HttpServletResponse resp=(HttpServletResponse) servletResponse;
HttpServletRequest request=(HttpServletRequest) servletRequest;
String url=request.getRequestURI();boolean flag = false;if (cacheURLs != null && cacheURLs.length > 0) {for(String cacheURL : cacheURLs) {if (url.contains(cacheURL.trim()) ||url.matches(cacheURL)) {
flag= true;break;
}
}
}//如果包含我们要缓存的url 就缓存该页面,否则执行正常的页面转向
if(flag) {
String query=request.getQueryString();if (query != null) {
query= "?" +query;
}final String key = "REDISCACHE:" + url +query;
log.info("当前请求缓存为:" + url +query);//从缓存中得到主页html
String html =getHtmlFromCache(key);if (null ==html) {try{
semp.acquire(); //这里做第二道redis读缓存操作,因为同时等待不只一个请求,第一个请求读完db,就把数据写到redis里面了,那么第二个进来就不用读db了
html=getHtmlFromCache(key);if(StringUtils.isEmpty(html)) {//截取生成的html并放入缓存
log.info("缓存不存在,生成缓存1");
ResponseWrapper wrapper= newResponseWrapper(resp);
filterChain.doFilter(servletRequest, wrapper);//放入缓存
html =wrapper.getResult();
putIntoCache(key, html);
}else{
log.info("缓存已经生成,直接用缓存2");
}
}catch(InterruptedException e) {
e.printStackTrace();
}finally{//访问完后,释放
semp.release();
}
}//返回响应
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().print(html);
}else{
filterChain.doFilter(servletRequest, resp);return;
}
}
@Overridepublic voiddestroy() {
}privateString getHtmlFromCache(String redisKey) {returnRedisUtil.get(redisKey);
}private voidputIntoCache(String redisKey, String html) {
RedisUtil.set(redisKey, html, timeOut* 60);
}
}