web.xml配置
<filter>
<filter-name>pageCacheFilter</filter-name>
<filter-class>com.shangpin.web.filter.PageCacheFilter</filter-class>
<init-param>
<param-name>suppressStackTrace</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cacheName</param-name>
<param-value>pageCachingFilter</param-value>
</init-param>
</filter>
<filter>
<filter-name>pageFragmentCachingFilter</filter-name>
<filter-class>com.shangpin.web.filter.PageFragmentCacheFilter</filter-class>
<init-param>
<param-name>suppressStackTrace</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cacheName</param-name>
<param-value>pageFragmentCachingFilter</param-value>
</init-param>
<init-param>
<param-name>patterns</param-name>
<param-value>/index/focus,/index/category,/index/hot,/index/promotion</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>pageFragmentCachingFilter</filter-name>
<url-pattern>/index/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<!-- 测试缓存 -->
<!-- <filter-mapping>
<filter-name>pageCacheFilter</filter-name>
<url-pattern>/cache/index</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping> -->
<filter>
<filter-name>testPageFragmentCachingFilter</filter-name>
<filter-class>com.shangpin.web.filter.PageFragmentCacheFilter</filter-class>
<init-param>
<param-name>suppressStackTrace</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cacheName</param-name>
<param-value>testPageFragmentCachingFilter</param-value>
</init-param>
<init-param>
<param-name>patterns</param-name>
<param-value>/cache/color,/cache/datetime,/cache/random</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>testPageFragmentCachingFilter</filter-name>
<url-pattern>/cache/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<!-- 测试缓存 结束 -->
<!-- 配置ehcache缓存响应filter结束 -->
filter
package com.shangpin.web.filter;
import javax.servlet.http.HttpServletRequest;
import net.sf.ehcache.Element;
import net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter;
import com.shangpin.utils.CacheOption;
import com.shangpin.utils.RequestUtils;
import com.shangpin.utils.ThreadVariableGlobal;
/**
* 页面缓存过滤器用于缓存整个请求资源
*
* @author zghw
*
*/
public class PageCacheFilter extends SimplePageCachingFilter {
/**
* The name of the filter. This should match a cache name in ehcache.xml
*/
public static final String NAME = "PageCacheFilter";
/**
* 配置页面缓存操作
*/
protected boolean filterNotDisabled(final HttpServletRequest request) {
// 线程中取出缓存参数设置
CacheOption cp = ThreadVariableGlobal.getCacheOption();
if (cp != null) {
switch (cp) {
case MISS:
// 跳过不缓存
return false;
case REFRESH:
// 清空再缓存
blockingCache.put(new Element(calculateKey(request), null));
return true;
case HIT:
return true;
default:
return true;
}
}
return true;
}
/**
* 复写生成缓存的key,主要过滤OPT参数
*/
protected String calculateKey(HttpServletRequest httpRequest) {
StringBuffer stringBuffer = new StringBuffer();
String queryString = RequestUtils.queryStringFilterOPT(httpRequest.getQueryString());
stringBuffer.append(httpRequest.getMethod()).append(httpRequest.getRequestURI()).append(queryString);
String key = stringBuffer.toString();
return key;
}
}
package com.shangpin.web.filter;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Element;
import net.sf.ehcache.constructs.blocking.LockTimeoutException;
import net.sf.ehcache.constructs.web.AlreadyCommittedException;
import net.sf.ehcache.constructs.web.AlreadyGzippedException;
import net.sf.ehcache.constructs.web.filter.FilterNonReentrantException;
import net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.WebUtils;
import com.shangpin.utils.CacheOption;
import com.shangpin.utils.RequestUtils;
import com.shangpin.utils.ThreadVariableGlobal;
/**
* 页面片段缓存过滤器主要用于一个页面中使用引入了其他页面,比如首页引入轮播图、热门、特卖等。对引入的页面片段进行缓存操作。
*
* @author zghw
*
*/
public class PageFragmentCacheFilter extends SimplePageFragmentCachingFilter {
/**
* The name of the filter. This should match a cache name in ehcache.xml
*/
public static final String NAME = "PageFragmentCacheFilter";
private static final Logger LOG = LoggerFactory.getLogger(PageFragmentCacheFilter.class);
/**
* 在web.xml中定义,用来定义需要缓存的页面片段URI集合.URI不需要带参数 主要为了节约空间web.xml的空间,方便定义页面片段URL.
* 例如:
* <p/>
* <init-param>
* <p/>
* <param-name>patterns</param-name>
* <p/>
* <param-value>/index/focus,/index/category,/index/hot</param-value>
* <p/>
* </init-param>
*/
private final static String FILTER_URL_PATTERNS = "patterns";
/**
* 页面片段URL集合.
*/
private static String[] cacheURLs;
/**
* 初始化需要缓存的页面片段URI集合
*
* @throws CacheException
*/
private void initUrl() throws CacheException {
String patterns = filterConfig.getInitParameter(FILTER_URL_PATTERNS);
cacheURLs = StringUtils.split(patterns, ",");
}
@Override
protected void doFilter(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws AlreadyCommittedException,
AlreadyGzippedException, FilterNonReentrantException, LockTimeoutException, Exception {
initUrl();
String url = request.getRequestURI();
if (useInclude(request)) {
url = getRequestIncludeURI(request);
LOG.debug("The current include url : {}", url);
}
// 如果包含我们要缓存的url 就缓存该页面,否则执行其他过滤器
if (supportCache(url)) {
LOG.debug("The current request cache key = {}", calculateKey(request));
super.doFilter(request, response, chain);
} else {
chain.doFilter(request, response);
}
}
/**
* 判断当前请求是否是需要缓存的url
*
* @param url
* @return
*/
private boolean supportCache(String url) {
boolean flag = false;
if (cacheURLs != null && cacheURLs.length > 0) {
for (String cacheURL : cacheURLs) {
if (url.contains(cacheURL.trim())) {
flag = true;
break;
}
}
}
return flag;
}
/**
* 确定给定的请求是一个包含请求,也就是说,不是一个从外面进来顶级HTTP请求
* <p/>
* 比如进来顶级HTTP请求是/index,其实包含的请求可能就是 /index/focus
*
* @param request
* @return
*/
protected boolean useInclude(HttpServletRequest request) {
return WebUtils.isIncludeRequest(request);
}
/**
* 确定给定的请求是一个包含请求参数,也就是说,不是一个从外面进来顶级HTTP请求参数
*
* @param request
* @return
*/
protected boolean useQueryString(HttpServletRequest request) {
// 如果使用页面包含的方式进行请求转发,当前的资源请求为你原始的请求,你必须从request.getAttribute("javax.servlet.include.query_string")来取得参数
return (getRequestIncludeQueryString(request) != null);
}
/**
* 计算一个包含请求对应的key
*
* @param httpRequest
* @return the key, included the URL plus request parameters
*/
@Override
protected String calculateKey(HttpServletRequest request) {
StringBuffer keyBuffer = new StringBuffer();
if (useInclude(request)) {
String url = getRequestIncludeURI(request);
keyBuffer.append(url);
if (useQueryString(request)) {
String query = getRequestIncludeQueryString(request);
query = RequestUtils.queryStringFilterOPT(query);
keyBuffer.append(query);
}
}
return keyBuffer.toString();
}
/**
* 取得给定的请求是一个包含请求 如果使用页面包含的方式进行请求转发,当前的资源请求为你原始的请求,你必须从request.getAttribute(
* "javax.servlet.include.servlet_path")来取得自己的uri
*
* @param request
* @return
*/
private String getRequestIncludeURI(final HttpServletRequest request) {
if (useInclude(request)) {
return request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE).toString();
}
return null;
}
/**
* 取得给定的请求是一个包含请求参数
*
* @param request
* @return
*/
private String getRequestIncludeQueryString(HttpServletRequest request) {
if (request.getAttribute(WebUtils.INCLUDE_QUERY_STRING_ATTRIBUTE) != null) {
return request.getAttribute(WebUtils.INCLUDE_QUERY_STRING_ATTRIBUTE).toString();
}
return null;
}
/**
* 空实现,再次进入缓存数据成为可能
*/
@Override
protected void checkNoReentry(final HttpServletRequest httpRequest) throws FilterNonReentrantException {
}
/**
* 配置页面缓存操作
*/
protected boolean filterNotDisabled(final HttpServletRequest request) {
// 线程中取出缓存参数设置
CacheOption cp = ThreadVariableGlobal.getCacheOption();
if (cp != null) {
switch (cp) {
case MISS:
// 跳过不缓存
return false;
case REFRESH:
// 清空再缓存
blockingCache.put(new Element(calculateKey(request), null));
return true;
case HIT:
return true;
default:
return true;
}
}
return true;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false">
<diskStore path="java.io.tmpdir/hibernate/mshangpin" />
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446,timeToLive=32,hostName=localhost" />
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="port=40001,hostName=localhost" />
<!-- DefaultCache setting. -->
<defaultCache maxEntriesLocalHeap="10000" eternal="false"
timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"
maxEntriesLocalDisk="100000" memoryStoreEvictionPolicy="LFU" />
<!-- security entity <cache name="com.shangpin.core.entity.Account" maxEntriesLocalHeap="1000"
eternal="false" overflowToDisk="true" maxEntriesLocalDisk="10000" /> -->
<!-- ehcache web缓存 -->
<cache name="pageCachingFilter" maxElementsInMemory="10"
maxElementsOnDisk="10" eternal="false" overflowToDisk="true"
timeToIdleSeconds="10" timeToLiveSeconds="10"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</cache>
<cache name="pageFragmentCachingFilter" maxElementsInMemory="10"
maxElementsOnDisk="10" eternal="false" overflowToDisk="true"
timeToIdleSeconds="10" timeToLiveSeconds="10"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</cache>
<cache name="testPageFragmentCachingFilter" maxElementsInMemory="100"
maxElementsOnDisk="100" eternal="false" overflowToDisk="true"
timeToIdleSeconds="30" timeToLiveSeconds="30"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</cache>
</ehcache>
controller
package com.shangpin.web.controller;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.constructs.blocking.BlockingCache;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 缓存测试controller
*
* @author zghw
*/
@Controller
public class CacheController extends BaseController {
public static Logger logger = LoggerFactory.getLogger(CacheController.class);
/** 缓存测试首页 */
private static final String CACHE_INDEX = "cache/index";
/** 颜色 */
private static final String CACHE_COLOR = "cache/color";
/** 时间 */
private static final String CACHE_DATETIME = "cache/datetime";
/** 随机数 */
private static final String CACHE_RANDOM = "cache/random";
/** 缓存列表 */
private static final String CACHE_LIST = "cache/list";
@RequestMapping(value = "/cache/index")
public String cacheIndex(HttpServletRequest request, ModelMap model) {
String ip = request.getLocalAddr();
String color = getRandColorCode();
model.addAttribute("IP", ip);
model.addAttribute("color", color);
return CACHE_INDEX;
}
@RequestMapping(value = "/cache/color")
public String cacheColor(HttpServletRequest request, ModelMap model, String color) {
if (StringUtils.isBlank(color)) {
color = getRandColorCode();
}
model.addAttribute("color", color);
return CACHE_COLOR;
}
@RequestMapping(value = "/cache/datetime")
public String cacheDateTime(HttpServletRequest request, ModelMap model) {
Long t = System.currentTimeMillis();
Date now = new Date(t);
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ").format(now);
model.addAttribute("t", t);
model.addAttribute("currentTime", currentTime);
return CACHE_DATETIME;
}
@RequestMapping(value = "/cache/random")
public String cacheRandom(HttpServletRequest request, ModelMap model) {
Random random = new Random();
Integer num = random.nextInt() * 1000;
model.addAttribute("num", num);
return CACHE_RANDOM;
}
@RequestMapping("/cache/list")
public String cacheList(HttpServletRequest request, ModelMap model) {
CacheManager manager = CacheManager.getInstance();
String[] cacheNames = manager.getCacheNames();
List<String> cacheNameList = Arrays.asList(cacheNames);
List<BlockingCache> cacheList = new ArrayList<BlockingCache>();
BlockingCache cache = new BlockingCache(manager.getEhcache("testPageFragmentCachingFilter"));
cacheList.add(cache);
model.addAttribute("cacheList", cacheList);
model.addAttribute("cacheNameList", cacheNameList);
return CACHE_LIST;
}
/**
* 获取十六进制的颜色代码.例如 "#6E36B4" , For HTML ,
*
* @return String
*/
private static String getRandColorCode() {
String r, g, b;
Random random = new Random();
r = Integer.toHexString(random.nextInt(256)).toUpperCase();
g = Integer.toHexString(random.nextInt(256)).toUpperCase();
b = Integer.toHexString(random.nextInt(256)).toUpperCase();
r = r.length() == 1 ? "0" + r : r;
g = g.length() == 1 ? "0" + g : g;
b = b.length() == 1 ? "0" + b : b;
return r + g + b;
}
}
页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
trimDirectiveWhitespaces="true" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/pages/common/include.inc.jsp"%>
<rapid:override name="content">
<div style="background-color:#${color};height:100px;margin:10px;" >
IP : ${IP } (此IP来判断分布式中的serverIP来源,通过多个页面来看数据是否在不同的server IP中数据是否同步缓存)<br/>
颜色值: #${color} (此颜色值为当前主页面中的数据值,用来判断当前的主页面除了引入需要缓存页面,其他部分并未缓存)
</div>
<%-- 颜色页面 --%>
<c:import url="/cache/color?color=${color }" />
<%-- 颜色页面 --%>
<c:import url="/cache/color" />
<%-- 时间页面 --%>
<c:import url="/cache/datetime" />
<%-- 随机数页面 --%>
<c:import url="/cache/random" />
</rapid:override>
<%@ include file="/WEB-INF/pages/common/base.jsp"%>