- 浏览: 137881 次
- 性别:
- 来自: 杭州
最新评论
-
Golden_Sky:
需要自己写代码来调用么?还是他自己如果有配置级别的错误时候他就 ...
log4j 邮件 配置 -
Golden_Sky:
luckaway 写道我想相信问一下,这个如果在配置文件中配置 ...
log4j 邮件 配置 -
Golden_Sky:
panda_eyes 写道我也试用过了 还用这个在工作交流会 ...
log4j 邮件 配置 -
Golden_Sky:
sealv 写道你这个是啥版本 为啥我这没有setSMTPUs ...
log4j 邮件 配置 -
Golden_Sky:
我想相信问一下,这个如果在配置文件中配置好了,比如我调整的级别 ...
log4j 邮件 配置
java有多个开源的缓存系统都支持页面缓存的,如OScache、Ehcache。
这个例子就是从Ehcache里挖出来的,并做了些改造和简化,但原理在此例子中都是完全体现出来了。该例子只供大家学习用,企业应用还是需要做一些修改的。因为页面数据只是直接存放到HashMap里。
CacheFilter.java
页面数据就是存放到HashMap里,key是url。
HttpServletResponseWrapper.java
用ResponseContent记录HttpServletResponse输出的信息
ResponseContent.java
响应后的内容,就是需要cache的对象,包含页面内容和Content-Type、Last-Modified、Content-Encoding等一些响应头的信息。
SplitServletOutputStream.java
这个例子就是从Ehcache里挖出来的,并做了些改造和简化,但原理在此例子中都是完全体现出来了。该例子只供大家学习用,企业应用还是需要做一些修改的。因为页面数据只是直接存放到HashMap里。
CacheFilter.java
页面数据就是存放到HashMap里,key是url。
public class CacheFilter implements Filter { public static final String HEADER_LAST_MODIFIED = "Last-Modified"; public static final String HEADER_CONTENT_TYPE = "Content-Type"; public static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; public static final String HEADER_EXPIRES = "Expires"; public static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since"; public static final String HEADER_CACHE_CONTROL = "Cache-Control"; public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; private static final String REQUEST_FILTERED = "cache_filter_" + CacheFilter.class.getName(); private final Map<String, ResponseContent> cache = new HashMap<String, ResponseContent>(); // Last Modified parameter private static final long LAST_MODIFIED_INITIAL = -1; // Expires parameter private static final long EXPIRES_ON = 1; private int time = 60 * 60; private long lastModified = LAST_MODIFIED_INITIAL; private long expires = EXPIRES_ON; private long cacheControlMaxAge = -60; @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; //避免重复调用 if (isFilteredBefore(request)) { chain.doFilter(request, res); return; } request.setAttribute(REQUEST_FILTERED, Boolean.TRUE); String key = getCacheKey(request); ResponseContent responseContent = cache.get(key); if (responseContent != null) {//如果当前的URL已经有对应的响应内容 responseContent.writeTo(res); return; } //用CacheHttpServletResponseWrapper来代替HttpServletResponse,用于记录HttpServletResponse输出的内容。 CacheHttpServletResponseWrapper cacheResponse = new CacheHttpServletResponseWrapper((HttpServletResponse) res, time * 1000L, lastModified, expires, cacheControlMaxAge); chain.doFilter(request, cacheResponse); cacheResponse.flushBuffer(); // Store as the cache content the result of the response cache.put(key, cacheResponse.getContent()); } private String getCacheKey(HttpServletRequest request) { StringBuilder builder = new StringBuilder(request.getRequestURI()); if (StringUtils.isNotEmpty(request.getQueryString())) { builder.append("_").append(request.getQueryString()); } return builder.toString(); } /** * Checks if the request was filtered before, so guarantees to be executed * once per request. You can override this methods to define a more specific * behaviour. * * @param request checks if the request was filtered before. * @return true if it is the first execution */ public boolean isFilteredBefore(ServletRequest request) { return request.getAttribute(REQUEST_FILTERED) != null; } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
HttpServletResponseWrapper.java
用ResponseContent记录HttpServletResponse输出的信息
import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Locale; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * 缓存的HttpServletResponseWrapper,它会把{@link HttpServletResponse}的部分数据记录到{@link ResponseContent}里。 */ public class CacheHttpServletResponseWrapper extends HttpServletResponseWrapper { private final Log log = LogFactory.getLog(this.getClass()); private PrintWriter cachedWriter = null; private ResponseContent result = null; private SplitServletOutputStream cacheOut = null; private int status = SC_OK; private long cacheControl = -60; public CacheHttpServletResponseWrapper(HttpServletResponse response) { this(response, Long.MAX_VALUE, CacheFilter.EXPIRES_ON, CacheFilter.LAST_MODIFIED_INITIAL, -60); } public CacheHttpServletResponseWrapper(HttpServletResponse response, long time, long lastModified, long expires, long cacheControl) { super(response); this.result = new ResponseContent(); this.cacheControl = cacheControl; // setting a default last modified value based on object creation and // remove the millis if (lastModified == CacheFilter.LAST_MODIFIED_INITIAL) { long current = System.currentTimeMillis(); current = current - (current % 1000); result.setLastModified(current); super.setDateHeader(CacheFilter.HEADER_LAST_MODIFIED, result.getLastModified()); } // setting the expires value if (expires == CacheFilter.EXPIRES_TIME) { result.setExpires(result.getLastModified() + time); super.setDateHeader(CacheFilter.HEADER_EXPIRES, result.getExpires()); } // setting the cache control with max-age if (this.cacheControl == CacheFilter.MAX_AGE_TIME) { // set the count down long maxAge = System.currentTimeMillis(); maxAge = maxAge - (maxAge % 1000) + time; result.setMaxAge(maxAge); super.addHeader(CacheFilter.HEADER_CACHE_CONTROL, "max-age=" + time / 1000); } else if (this.cacheControl != CacheFilter.MAX_AGE_NO_INIT) { result.setMaxAge(this.cacheControl); super.addHeader(CacheFilter.HEADER_CACHE_CONTROL, "max-age=" + (-this.cacheControl)); } else if (this.cacheControl == CacheFilter.MAX_AGE_NO_INIT) { result.setMaxAge(this.cacheControl); } } /** * Get a response content * * @return The content */ public ResponseContent getContent() { // Flush the buffer try { flush(); } catch (IOException ignore) { } // Create the byte array result.commit(); // Return the result from this response return result; } /** * Set the content type * * @param value The content type */ public void setContentType(String value) { if (log.isDebugEnabled()) { log.debug("ContentType: " + value); } super.setContentType(value); result.setContentType(value); } /** * Set a header field * * @param name The header name * @param value The header value */ public void setHeader(String name, String value) { if (log.isDebugEnabled()) { log.debug("header: " + name + ": " + value); } if (CacheFilter.HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) { result.setContentType(value); } if (CacheFilter.HEADER_CONTENT_ENCODING.equalsIgnoreCase(name)) { result.setContentEncoding(value); } super.setHeader(name, value); } /** * Add a header field * * @param name The header name * @param value The header value */ public void addHeader(String name, String value) { if (log.isDebugEnabled()) { log.debug("header: " + name + ": " + value); } if (CacheFilter.HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) { result.setContentType(value); } if (CacheFilter.HEADER_CONTENT_ENCODING.equalsIgnoreCase(name)) { result.setContentEncoding(value); } super.addHeader(name, value); } /** * We override this so we can catch the response status. Only responses with * a status of 200 (<code>SC_OK</code>) will be cached. */ public void setStatus(int status) { super.setStatus(status); this.status = status; } /** * We override this so we can catch the response status. Only responses with * a status of 200 (<code>SC_OK</code>) will be cached. */ public void sendError(int status, String string) throws IOException { super.sendError(status, string); this.status = status; } /** * We override this so we can catch the response status. Only responses with * a status of 200 (<code>SC_OK</code>) will be cached. */ public void sendError(int status) throws IOException { super.sendError(status); this.status = status; } /** * We override this so we can catch the response status. Only responses with * a status of 200 (<code>SC_OK</code>) will be cached. */ public void setStatus(int status, String string) { super.setStatus(status, string); this.status = status; } /** * We override this so we can catch the response status. Only responses with * a status of 200 (<code>SC_OK</code>) will be cached. */ public void sendRedirect(String location) throws IOException { this.status = SC_MOVED_TEMPORARILY; super.sendRedirect(location); } /** * Retrieves the captured HttpResponse status. */ public int getStatus() { return status; } /** * Set the locale * * @param value The locale */ public void setLocale(Locale value) { super.setLocale(value); result.setLocale(value); } /** * Get an output stream * * @throws IOException */ public ServletOutputStream getOutputStream() throws IOException { // Pass this faked servlet output stream that captures what is sent if (cacheOut == null) { cacheOut = new SplitServletOutputStream(result.getOutputStream(), super.getOutputStream()); } return cacheOut; } /** * Get a print writer * * @throws IOException */ public PrintWriter getWriter() throws IOException { if (cachedWriter == null) { String encoding = getCharacterEncoding(); if (encoding != null) { cachedWriter = new PrintWriter(new OutputStreamWriter(getOutputStream(), encoding)); } else { // using the default character encoding cachedWriter = new PrintWriter(new OutputStreamWriter(getOutputStream())); } } return cachedWriter; } /** * Flushes all streams. * * @throws IOException */ private void flush() throws IOException { if (cacheOut != null) { cacheOut.flush(); } if (cachedWriter != null) { cachedWriter.flush(); } } public void flushBuffer() throws IOException { super.flushBuffer(); flush(); } }
ResponseContent.java
响应后的内容,就是需要cache的对象,包含页面内容和Content-Type、Last-Modified、Content-Encoding等一些响应头的信息。
import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; import java.util.Locale; import java.util.zip.GZIPInputStream; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; /** * Holds the servlet response in a byte array so that it can be held in the * cache (and, since this class is serializable, optionally persisted to disk). * * @version $Revision: 362 $ * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a> */ public class ResponseContent implements Serializable { private static final long serialVersionUID = 1L; private transient ByteArrayOutputStream bout = new ByteArrayOutputStream(1000); private Locale locale = null; private String contentEncoding = null; private String contentType = null; private byte[] content = null; private long expires = Long.MAX_VALUE; private long lastModified = -1; private long maxAge = -60; public String getContentType() { return contentType; } /** * Set the content type. We capture this so that when we serve this data * from cache, we can set the correct content type on the response. */ public void setContentType(String value) { contentType = value; } public long getLastModified() { return lastModified; } public void setLastModified(long value) { lastModified = value; } public String getContentEncoding() { return contentEncoding; } public void setContentEncoding(String contentEncoding) { this.contentEncoding = contentEncoding; } /** * Set the Locale. We capture this so that when we serve this data from * cache, we can set the correct locale on the response. */ public void setLocale(Locale value) { locale = value; } /** * @return the expires date and time in miliseconds when the content will be * stale */ public long getExpires() { return expires; } /** * Sets the expires date and time in miliseconds. * * @param value time in miliseconds when the content will expire */ public void setExpires(long value) { expires = value; } /** * Returns the max age of the content in miliseconds. If expires header and * cache control are enabled both, both will be equal. * * @return the max age of the content in miliseconds, if -1 max-age is * disabled */ public long getMaxAge() { return maxAge; } /** * Sets the max age date and time in miliseconds. If the parameter is -1, * the max-age parameter won't be set by default in the Cache-Control * header. * * @param value sets the intial */ public void setMaxAge(long value) { maxAge = value; } /** * Get an output stream. This is used by the * {@link SplitServletOutputStream} to capture the original (uncached) * response into a byte array. * * @return the original (uncached) response, returns null if response is * already committed. */ public OutputStream getOutputStream() { return bout; } /** * Gets the size of this cached content. * * @return The size of the content, in bytes. If no content exists, this * method returns <code>-1</code>. */ public int getSize() { return (content != null) ? content.length : (-1); } /** * Called once the response has been written in its entirety. This method * commits the response output stream by converting the output stream into a * byte array. */ public void commit() { if (bout != null) { content = bout.toByteArray(); bout = null; } } /** * Writes this cached data out to the supplied <code>ServletResponse</code>. * * @param response The servlet response to output the cached content to. * @throws IOException */ public void writeTo(ServletResponse response) throws IOException { writeTo(response, false, false); } /** * Writes this cached data out to the supplied <code>ServletResponse</code>. * * @param response The servlet response to output the cached content to. * @param fragment is true if this content a fragment or part of a page * @param acceptsGZip is true if client browser supports gzip compression * @throws IOException */ public void writeTo(ServletResponse response, boolean fragment, boolean acceptsGZip) throws IOException { // Send the content type and data to this response if (contentType != null) { response.setContentType(contentType); } if (fragment) { // Don't support gzip compression if the content is a fragment of a // page acceptsGZip = false; } else { // add special headers for a complete page if (response instanceof HttpServletResponse) { HttpServletResponse httpResponse = (HttpServletResponse) response; // add the last modified header if (lastModified != -1) { httpResponse.setDateHeader(CacheFilter.HEADER_LAST_MODIFIED, lastModified); } // add the expires header if (expires != Long.MAX_VALUE) { httpResponse.setDateHeader(CacheFilter.HEADER_EXPIRES, expires); } // add the cache-control header for max-age if (maxAge == CacheFilter.MAX_AGE_NO_INIT || maxAge == CacheFilter.MAX_AGE_TIME) { // do nothing } else if (maxAge > 0) { // set max-age based on life time long currentMaxAge = maxAge / 1000 - System.currentTimeMillis() / 1000; if (currentMaxAge < 0) { currentMaxAge = 0; } httpResponse.addHeader(CacheFilter.HEADER_CACHE_CONTROL, "max-age=" + currentMaxAge); } else { httpResponse.addHeader(CacheFilter.HEADER_CACHE_CONTROL, "max-age=" + (-maxAge)); } } } if (locale != null) { response.setLocale(locale); } OutputStream out = new BufferedOutputStream(response.getOutputStream()); if (isContentGZiped()) { if (acceptsGZip) { ((HttpServletResponse) response).addHeader(CacheFilter.HEADER_CONTENT_ENCODING, "gzip"); response.setContentLength(content.length); out.write(content); } else { // client doesn't support, so we have to uncompress it ByteArrayInputStream bais = new ByteArrayInputStream(content); GZIPInputStream zis = new GZIPInputStream(bais); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int numBytesRead = 0; byte[] tempBytes = new byte[4196]; while ((numBytesRead = zis.read(tempBytes, 0, tempBytes.length)) != -1) { baos.write(tempBytes, 0, numBytesRead); } byte[] result = baos.toByteArray(); response.setContentLength(result.length); out.write(result); } } else { // the content isn't compressed // regardless if the client browser supports gzip we will just // return the content response.setContentLength(content.length); out.write(content); } out.flush(); } /** * @return true if the content is GZIP compressed */ public boolean isContentGZiped() { return "gzip".equals(contentEncoding); }
SplitServletOutputStream.java
package com.dukuai.metis.search.servlet; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletOutputStream; /** * Extends the base <code>ServletOutputStream</code> class so that the stream * can be captured as it gets written. This is achieved by overriding the * <code>write()</code> methods and outputting the data to two streams - the * original stream and a secondary stream that is designed to capture the * written data. * * @version $Revision: 393 $ * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a> */ public class SplitServletOutputStream extends ServletOutputStream { OutputStream captureStream = null; OutputStream passThroughStream = null; /** * Constructs a split output stream that both captures and passes through * the servlet response. * * @param captureStream The stream that will be used to capture the data. * @param passThroughStream The pass-through * <code>ServletOutputStream</code> that will write the * response to the client as originally intended. */ public SplitServletOutputStream(OutputStream captureStream, OutputStream passThroughStream) { this.captureStream = captureStream; this.passThroughStream = passThroughStream; } /** * Writes the incoming data to both the output streams. * * @param value The int data to write. * @throws IOException */ public void write(int value) throws IOException { captureStream.write(value); passThroughStream.write(value); } /** * Writes the incoming data to both the output streams. * * @param value The bytes to write to the streams. * @throws IOException */ public void write(byte[] value) throws IOException { captureStream.write(value); passThroughStream.write(value); } /** * Writes the incoming data to both the output streams. * * @param b The bytes to write out to the streams. * @param off The offset into the byte data where writing should begin. * @param len The number of bytes to write. * @throws IOException */ public void write(byte[] b, int off, int len) throws IOException { captureStream.write(b, off, len); passThroughStream.write(b, off, len); } /** * Flushes both the output streams. * * @throws IOException */ public void flush() throws IOException { super.flush(); captureStream.flush(); // why not? passThroughStream.flush(); } /** * Closes both the output streams. * * @throws IOException */ public void close() throws IOException { super.close(); captureStream.close(); passThroughStream.close(); } }
相关推荐
在本篇文章中,我们将深入探讨如何使用Servlet过滤器来实现缓存机制,以此提高Web应用的性能。 首先,我们需要了解什么是缓存。缓存是一种存储技术,用于临时存储频繁访问的数据,以便快速检索。在Web应用中,通过...
Java Servlet Filter实现全站动态转静态是一种常见的优化网站性能的技术,它通过在服务器端拦截请求,将原本需要动态生成的页面转换为预先生成的静态HTML文件进行返回,从而减轻服务器负担,提高页面加载速度,提升...
在Servlet规范中,Filter通过实现`javax.servlet.Filter`接口来创建。这个接口定义了三个方法:`init()`, `doFilter()`, 和 `destroy()`。`init()`方法在Filter实例被创建并添加到Filter链中时调用,用于初始化...
"servlet filter大全"这个主题涵盖了多种常见的过滤器设置,旨在提高应用的功能性和安全性。下面我们将详细探讨这些过滤器及其用途。 1. **字符集过滤器**: 这种过滤器的主要任务是确保请求和响应中的字符集正确...
(2)有3个http响应头字段可以禁止浏览器缓存当前页面,它们在Servlet中的示例代码如下。 response.setDateHeader("Expires",-1); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma",...
综上所述,通过使用Java的Servlet Filter,我们可以实现对用户session的有效验证,防止未授权访问,并且可以控制页面不被浏览器缓存,提高系统的安全性。在实际开发中,我们可能还需要结合其他安全措施,如CSRF防护...
在本实例中,我们将深入探讨Servlet过滤器(Filter)的使用和实现,以及它在实际应用中的重要性。 一、Servlet过滤器简介 Servlet过滤器遵循Java Servlet规范,通过实现`javax.servlet.Filter`接口来创建自定义过滤...
本文将详细介绍如何使用filter来对servlet和jsp页面的内容进行过滤,并在过滤后输出。 首先,了解Servlet Filter的基本概念。Filter是Java Servlet API的一部分,它允许开发者在请求到达目标Servlet或JSP之前以及...
标题 "OSCACHE配置URL实现页面缓存的Filter(修改配置无需重启)" 提示我们讨论的是一个使用OSCache(OpenSymphony Cache)库来缓存Web应用程序中特定URL页面的过滤器配置。OSCache是一个开源的Java缓存框架,用于提高...
这时,可以使用Servlet Filter或自定义Tag Library来拦截请求,根据条件判断是否从缓存中读取数据,或者在数据更新后更新缓存。例如,我们可以使用Spring框架的`Cache`抽象层来管理缓存,或者使用第三方库如Ehcache...
本教程将探讨如何使用Servlet来实现一个高效的分页效果,类似于百度搜索引擎的展示方式。分页是网页应用中常见的功能,它能帮助用户浏览大量数据而无需一次性加载所有内容,从而提高用户体验。 首先,我们需要理解...
总结,Filter是Java Web开发中的强大工具,它可以用于实现多种功能,包括用户认证、数据验证、字符编码管理和页面缓存控制等。熟练掌握Filter的使用,能帮助我们构建更加安全、高效和灵活的Web应用程序。通过实践和...
同样,Filter也可以在Servlet响应后对响应内容进行操作,如添加缓存控制头,加密敏感信息等。 在实际开发中,Filter的使用可以提高代码的可维护性和复用性,因为它们将通用的逻辑从Servlet中分离出来。例如,通过...
* 缓存处理:可以使用 Filter 来实现缓存处理,例如缓存常用的静态资源。 * 数据压缩:可以使用 Filter 来实现数据压缩,例如压缩 HTML、CSS 和 JavaScript 文件。 Filter 是 Java EE 中的一种强大且灵活的组件,...
这里没有给出具体的缓存清理代码,因为实际应用中可能涉及不同的缓存实现(如 Redis、Memcached 或 Ehcache),清理缓存的方法会因缓存技术而异。 总之,通过扩展 Shiro 的 `LogoutFilter`,我们可以在用户登出时...
2. **JSP(JavaServer Pages)**:JSP是Java Web开发中的视图技术,与Servlet配合使用,负责生成动态网页内容。在本系统中,JSP用于创建用户界面,如登录页面、图书列表、借阅操作等,通过内置的Java表达式和脚本...
Servlet3.1引入了预定义的Filter和Servlet,例如`ContainerLoginService`和`ErrorPage`,这些预定义的组件可以帮助开发者更快地实现常见的功能,如用户认证和错误页面处理。 4. **WebSocket支持**: 该版本添加了...
了解缓存机制、减少不必要的数据库查询、使用高效的模板技术等都是提升JSP Servlet应用性能的关键。 通过学习和实践这些知识点,开发者不仅能掌握JSP Servlet的基本用法,还能深入理解Web开发的原理,为构建高效、...