ehcache 缓存包含页面配置

本文深入解析web.xml配置中的过滤器及ehcache缓存设置,包括页面缓存过滤器和页面片段缓存过滤器的具体实现,以及ehcache缓存配置的详细步骤。同时展示了如何在控制器中实现缓存测试,并通过页面展示缓存效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
    }
}




ehcache.xml

<?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"%>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值