1、部署oscache到web项目中,本案例下载oscache的版本是oscache-2.4.1-full.zip,
步骤:
1)将oscache-2.4.1.jar 、commons-logging.jar、jgroups-all.jar 包放到项目的 WEB-INF/lib 目录下
2)将oscache.properties 文件放到项目的src目录下
3)修改项目 WEB-INF/web.xml文件,添加以下内容
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
<init-param>
<description>缓存有效时间,单位秒,这里设置了7天</description>
<param-name>time</param-name>
<param-value>604800</param-value>
</init-param>
<init-param>
<description>缓存的范围,只能是session或application</description>
<param-name>scope</param-name>
<param-value>application</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>/oscache/*</url-pattern>
</filter-mapping>
2、其实,按照步骤1 部署之后,就可以缓存 /oscache/* 路径下的页面。但是这样存在着一个问题,那就是怎么强制清除缓存?上述的web.xml代码可以看到,通过CacheFilter过滤器只是配置了缓存的有效时间,没法强制清楚缓存。在实际的应用中,却经常会碰到要删除缓存的情况,例如,菜单管理页面,基本上这个页面上的数据会不变,改动少,但也会存在改动的情况,像这种情况就需要改动了之后立即清除缓存,否则用户看到的还是旧的菜单!!我找了下oscache的api文档,发下可以通过以下代码去清除缓存:
Cache cache = ServletCacheAdministrator.getInstance(request.getSession().getServletContext()).getCache(request,
scopetype);
cache.flushEntry(key);
这段代码,有个问题是,必须要知道缓存的key才能够删除对应的缓存!接着,查看了com.opensymphony.oscache.web.filter.CacheFilter 源代码,发现了以下这段代码:
/**
* {@link ICacheKeyProvider}
* @see com.opensymphony.oscache.web.filter.ICacheKeyProvider#createCacheKey(javax.servlet.http.HttpServletRequest, ServletCacheAdministrator, Cache)
*/
public String createCacheKey(HttpServletRequest httpRequest, ServletCacheAdministrator scAdmin, Cache cache) {
return scAdmin.generateEntryKey(null, httpRequest, cacheScope);
}
这段代码,是缓存的key的生成算法。可以看到oscache有自己的key生成规则,但是如果换成自己的key生成规则,不就可以知道,项目中所有页面对应的缓存的key么?所以自己就写了一个CacheFilter,代码如下:
package edu.filter;
import javax.servlet.http.HttpServletRequest;
import com.opensymphony.oscache.base.Cache;
import com.opensymphony.oscache.web.ServletCacheAdministrator;
import com.opensymphony.oscache.web.filter.CacheFilter;
/**
* Title: CustomOscacheFilter.java
* Description: 自定义oscache缓存的filter
* 修改了key的生成规则,让页面路径(相对于 Webapp 的路径)作为key
* @author yh.zeng
* @date 2017-6-16
*/
public class CustomOscacheFilter extends CacheFilter{
private String getQueryString(HttpServletRequest httpRequest){
String queryString = httpRequest.getQueryString();
if(queryString == null || queryString.equals("")){
return "";
}else{
return "?" + queryString;
}
}
@Override
public String createCacheKey(HttpServletRequest httpRequest,
ServletCacheAdministrator scAdmin, Cache cache) {
return httpRequest.getServletPath() + getQueryString(httpRequest) ;
}
}
修改WEB-INF/web.xml,过滤器CacheFilter的类名改成自己写的filter类,代码如下:
<filter>
<filter-name>CacheFilter</filter-name>
<!-- <filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class> -->
<filter-class>edu.filter.CustomOscacheFilter</filter-class>
<init-param>
<description>缓存有效时间,单位秒,这里设置了7天</description>
<param-name>time</param-name>
<param-value>604800</param-value>
</init-param>
<init-param>
<description>缓存的范围,只能是session或application</description>
<param-name>scope</param-name>
<param-value>application</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>/oscache/*</url-pattern>
</filter-mapping>
接着,也将强制删除缓存的代码也封装成一个工具类,如下:
package utils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.PageContext;
import com.opensymphony.oscache.base.Cache;
import com.opensymphony.oscache.web.ServletCacheAdministrator;
/**
* Title: OscacheUtils.java
* Description: Oscache缓存工具类
* @author yh.zeng
* @date 2017-6-16
*/
public class OscacheUtils {
public enum CACHE_SCOPE{
APPLICATION_SCOPE,
SESSION_SCOPE
}
/**
* 强制刷新(即清除)OSCACHE的缓存数据
* @param request 请求对象
* @param key 缓存的KEY
* @param scope 缓存的作用域
*/
public static void flushCacheByKey(HttpServletRequest request, String key, CACHE_SCOPE scope){
int scopetype = 0;
switch(scope){
case APPLICATION_SCOPE:
scopetype = PageContext.APPLICATION_SCOPE;
break;
case SESSION_SCOPE:
scopetype = PageContext.SESSION_SCOPE;
break;
}
Cache cache = ServletCacheAdministrator.getInstance(request.getSession().getServletContext()).getCache(request,
scopetype);
cache.flushEntry(key);
}
}
3、写一个测试的页面/oscache/test.jsp,测试缓存功能
<%@ page language="java" import="java.util.Date" pageEncoding="utf-8"%>
<html>
<head>
</head>
<body>
时间:<%=new Date()%>
</body>
</html>
大家会发现不管怎么刷新重新打开test.jsp页面,时间还是不会变!这是因为这个页面第一次被打开的时候,页面被oscache缓存起来了,下次重新打开这个页面的时候,会从缓存中读取页面数据,服务器不会重新解析这个页面。大家看下面的后台日志就会发现:
[INFO][2017-06-17 00:35:55][CacheFilter:116] - OSCache: filter in scope 4
[INFO][2017-06-17 00:35:55][CacheFilter:171] - OSCache: New cache entry, cache stale or cache scope flushed for /oscache/test.jsp
[INFO][2017-06-17 00:35:56][CacheFilter:186] - OSCache: New entry added to the cache with key /oscache/test.jsp
[INFO][2017-06-17 00:35:59][CacheFilter:116] - OSCache: filter in scope 4
[INFO][2017-06-17 00:35:59][CacheFilter:146] - OSCache: Using cached entry for /oscache/test.jsp
[INFO][2017-06-17 00:35:59][CacheFilter:116] - OSCache: filter in scope 4
[INFO][2017-06-17 00:35:59][CacheFilter:146] - OSCache: Using cached entry for /oscache/test.jsp
[INFO][2017-06-17 00:36:00][CacheFilter:116] - OSCache: filter in scope 4
上面的日志,同时也可以看出,/oscache/test.jsp 这个页面对应的缓存的key为/oscache/test.jsp。大家可能会提问 这个页面访问路径后加请求参数是否会刷新时间呢?答案,是会的。例如,你访问http://localhost:8080/OscacheTestProj/oscache/test.jsp?a=1 ,页面的时间就会改变,因为这个时候,这个页面对应的缓存KEY=/oscache/test.jsp?a=1,刚好oscache缓存中没有存KEY=/oscache/test.jsp?a=1的缓存数据,所以服务器会重新解析这个页面,并创建KEY=/oscache/test.jsp?a=1的缓存数据!大家看后台日志可以看到:
[INFO][2017-06-17 00:44:02][CacheFilter:116] - OSCache: filter in scope 4
[INFO][2017-06-17 00:44:02][CacheFilter:146] - OSCache: Using cached entry for /oscache/test.jsp
[INFO][2017-06-17 00:44:03][CacheFilter:116] - OSCache: filter in scope 4
[INFO][2017-06-17 00:44:03][CacheFilter:146] - OSCache: Using cached entry for /oscache/test.jsp
[INFO][2017-06-17 00:44:31][CacheFilter:116] - OSCache: filter in scope 4
[INFO][2017-06-17 00:44:31][CacheFilter:171] - OSCache: New cache entry, cache stale or cache scope flushed for /oscache/test.jsp?a=1
[INFO][2017-06-17 00:44:31][CacheFilter:186] - OSCache: New entry added to the cache with key /oscache/test.jsp?a=1
4、大家会发现测试的页面/oscache/test.jsp没有【清除缓存】的功能,这个功能确实很实用!大家肯定还记得我在前面提到的OscacheUtils.java工具类,可以用来清除缓存。这个是手动清除的功能,肯定是前端和后端交互实现的功能,因此前端我考虑用jquery的ajax,后端的话,写个Servlet调用OscacheUtils.java工具类去实现,代码如下:
package edu.servlet;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import utils.OscacheUtils;
import utils.StringUtils;
/**
* Title: ClearCacheServlet.java
* Description: 清除KEY对应的OSCACHE缓存
* @author yh.zeng
* @date 2017-6-16
*/
public class ClearCacheServlet extends HttpServlet {
private static final long serialVersionUID = -3266620619413471751L;
private Logger logger = Logger.getLogger(ClearCacheServlet.class);
private OscacheUtils.CACHE_SCOPE CACHE_SCOPE = OscacheUtils.CACHE_SCOPE.APPLICATION_SCOPE; //缓存作用域
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
String scope = config.getInitParameter("scope");
if(scope != null){
if(!scope.equals("application") && !scope.equals("session")){
logger.error("init-param参数scope的值必须是application或session!");
throw new ServletException("init-param参数scope的值必须是application或session!");
}else{
if(scope.equals("application")){
CACHE_SCOPE = OscacheUtils.CACHE_SCOPE.APPLICATION_SCOPE;
}else{
CACHE_SCOPE = OscacheUtils.CACHE_SCOPE.SESSION_SCOPE;
}
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String cachekey = req.getParameter("cachekey"); //缓存的key
boolean success = true;
try{
OscacheUtils.flushCacheByKey(req, cachekey, CACHE_SCOPE);
}catch (Exception e){
e.printStackTrace();
logger.error(StringUtils.getExceptionMessage(e));
success = false;
}
if(success){
resp.getWriter().write("success");
}else{
resp.getWriter().write("fail");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
修改WEB-INF/web.xml,添加ClearCacheServlet的配置,如下:
<servlet>
<servlet-name>clearCacheServlet</servlet-name>
<servlet-class>edu.servlet.ClearCacheServlet</servlet-class>
<init-param>
<param-name>scope</param-name>
<param-value>application</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>clearCacheServlet</servlet-name>
<url-pattern>/servlet/clearCacheServlet</url-pattern>
</servlet-mapping>
/oscache/test.jsp也进行了修改,代码如下:
<%@ page language="java" import="java.util.Date" pageEncoding="utf-8"%>
<html>
<head>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
function clearCache(){
$.post("${pageContext.request.contextPath}/servlet/clearCacheServlet",{cachekey:"/oscache/test.jsp"},function(result){
if(result == "success"){
alert("删除缓存成功!");
}else{
alert("删除缓存失败!");
}
});
return false;
}
</script>
</head>
<body>
时间:<%=new Date()%>
<br>
<a href="javascript:void(0)" onclick="clearCache()">清除缓存</a>
</body>
</html>
效果:
点击【清除缓存】之后,再重新刷新页面或打开页面就会发现页面显示的时间会改变了!
最终,项目的资源结构如下图:
oscache-2.4.1-full.zip 下载地址: http://download.youkuaiyun.com/detail/yh_zeng2/9870218
此次案例的demo下载地址:https://github.com/zengyh/OscacheTestProj.git