通过filter过滤器拦截返回给客户端的页面内容,分析页面内容,写入缓存或者重新设计页面内容返回给客户端。要截获页面返回的内容,整体的思路是先把原始返回的页面内容写入到一个字符Writer,然后再组装成字符串并进行分析,最后再返回给客户端。

  • 建立一个响应包装器。扩展javax.servlet.http.HttpServletResponseWrapper。
  • 提供一个缓存输出的PrintWriter。重载getWriter方法,返回一个保存发送给它的所有东西的PrintWriter,并把结果存进一个可以稍后访问的字段中。
  • 传递该包装器给doFilter。此调用是合法的,因为HttpServletResponseWrapper实现HttpServletResponse。
  • 提取和修改输出。在调用FilterChain的doFilter方法后,原资源的输出只要利用步骤2中提供的机制就可以得到。只要对你的应用适合,就可以修改或替换它。
  • 发送修改过的输出到客户机。因为原资源不再发送输出到客户机(这些输出已经存放到你的响应包装器中了),所以必须发送这些输出。这样,你的过滤器需要从原响应对象中获得PrintWriter或OutputStream,并传递修改过的输出到该流中。(2).GZipFilter类 (3).GZipUtil类 (4).在web.xml中配置 GZipFilter


第一步:重写HttpServletResponseWrapper类,自定义一个响应结果包装器,将在这里提供一个基于内存的输出器来存储所有返回给客户端的原始HTML代码

package com.superscene.streetview.memcache;
 
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
 
import org.apache.log4j.Logger;
 
/**
 * <p>监听器:获取页面返回的HTML内容</p>
 * @author shma1664
 * @date 2014-04-23 16:37:54
 *
 */
public class SphinxResponseWrapper extends HttpServletResponseWrapper {
 
    private static Logger logger = Logger.getLogger(SphinxResponseWrapper.class);
 
    //控制输出状态
    public static final int OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2;
 
    private int outputType = OT_NONE;
    private ServletOutputStream output = null; 
    private PrintWriter pWriter = null; 
    private ByteArrayOutputStream buffer = null;
 
    public SphinxResponseWrapper(HttpServletResponse response) {
        super(response);
        buffer = new ByteArrayOutputStream();
    }
 
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (outputType == OT_WRITER) 
            throw new IllegalStateException(); 
        else if (outputType == OT_STREAM) 
            return output; 
        else { 
            outputType = OT_STREAM; 
            output = new WrappedOutputStream(buffer); 
            return output; 
        }
    }
 
    @Override
    public PrintWriter getWriter() throws IOException {
 
        if (outputType == OT_STREAM) 
            throw new IllegalStateException();
        else if (outputType == OT_WRITER) 
            return pWriter; 
        else { 
            outputType = OT_WRITER; 
            logger.info("监听器编码格式为:" + this.getCharacterEncoding());
            pWriter = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding())); 
            return pWriter;
        }
    }
 
    @Override
    public void reset() {
        outputType = OT_NONE; 
        buffer.reset();
    }
 
    @Override
    public void flushBuffer() throws IOException { 
        if (outputType == OT_WRITER) {
            pWriter.flush();
        }
 
        if (outputType == OT_STREAM) {
            output.flush();
        }   
    }
 
    public byte[] getResponseData() throws IOException { 
        flushBuffer(); 
        return buffer.toByteArray(); 
    } 
 
    private class WrappedOutputStream extends ServletOutputStream { 
 
        private ByteArrayOutputStream bos; 
 
        public WrappedOutputStream(ByteArrayOutputStream buffer) { 
            this.bos = buffer; 
        } 
 
        public void write(int b) throws IOException { 
            bos.write(b); 
        } 
 
        public byte[] toByteArray() { 
            return bos.toByteArray(); 
        } 
    }
 
}
package com.superscene.streetview.memcache;
 
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
 
import org.apache.log4j.Logger;
 
/**
 * <p>监听器:获取页面返回的HTML内容</p>
 * @author shma1664
 * @date 2014-04-23 16:37:54
 *
 */
public class SphinxResponseWrapper extends HttpServletResponseWrapper {
 
    private static Logger logger = Logger.getLogger(SphinxResponseWrapper.class);
 
    //控制输出状态
    public static final int OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2;
 
    private int outputType = OT_NONE;
    private ServletOutputStream output = null; 
    private PrintWriter pWriter = null; 
    private ByteArrayOutputStream buffer = null;
 
    public SphinxResponseWrapper(HttpServletResponse response) {
        super(response);
        buffer = new ByteArrayOutputStream();
    }
 
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (outputType == OT_WRITER) 
            throw new IllegalStateException(); 
        else if (outputType == OT_STREAM) 
            return output; 
        else { 
            outputType = OT_STREAM; 
            output = new WrappedOutputStream(buffer); 
            return output; 
        }
    }
 
    @Override
    public PrintWriter getWriter() throws IOException {
 
        if (outputType == OT_STREAM) 
            throw new IllegalStateException();
        else if (outputType == OT_WRITER) 
            return pWriter; 
        else { 
            outputType = OT_WRITER; 
            logger.info("监听器编码格式为:" + this.getCharacterEncoding());
            pWriter = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding())); 
            return pWriter;
        }
    }
 
    @Override
    public void reset() {
        outputType = OT_NONE; 
        buffer.reset();
    }
 
    @Override
    public void flushBuffer() throws IOException { 
        if (outputType == OT_WRITER) {
            pWriter.flush();
        }
 
        if (outputType == OT_STREAM) {
            output.flush();
        }   
    }
 
    public byte[] getResponseData() throws IOException { 
        flushBuffer(); 
        return buffer.toByteArray(); 
    } 
 
    private class WrappedOutputStream extends ServletOutputStream { 
 
        private ByteArrayOutputStream bos; 
 
        public WrappedOutputStream(ByteArrayOutputStream buffer) { 
            this.bos = buffer; 
        } 
 
        public void write(int b) throws IOException { 
            bos.write(b); 
        } 
 
        public byte[] toByteArray() { 
            return bos.toByteArray(); 
        } 
    }
 
}


第二步 写过滤器 拦截内容并处理

package com.superscene.streetview.memcache;
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.log4j.Logger;
 
/**
 * <p>memcache缓存配置</p>
 * @author shma1664
 * @date 2013-12-20 10:00:05
 *
 */
public class MemcachedManagerFilter implements Filter {
 
    private MemcacheClientManagerFactory memcacheManager = null;
 
    //默认js接口部分人工读取路径
    private String[] interFilterPath = null;
 
    //当文件在tomcat找不到时,默认的nginx静态文件手工读取路径
    private String defaultNginxPath = "/usr/local/nginx/test";
    private String defaultTomcatPath = "/data/deploy/apache-tomcat-6.0.36/webapps";
 
    private static Logger logger = Logger.getLogger(MemcachedManagerFilter.class);
 
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
 
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
 
        HttpServletRequest inRequest = (HttpServletRequest) request;
        HttpServletResponse inResponse = (HttpServletResponse) response;
 
        inRequest.setCharacterEncoding("UTF-8");
        inResponse.setCharacterEncoding("UTF-8"); 
        inResponse.setContentType("text/html;charset=UTF-8");
 
        String urlPath = inRequest.getHeader("memcached_key");
//      String urlPath = inRequest.getRequestURL().toString();
        logger.info("memcached_key : " + urlPath);
 
        if(urlPath == null || urlPath.equals("")) {
            chain.doFilter(inRequest, inResponse);
            return;
        }
 
        boolean isWriteToMemcache = true;
 
        byte[] context = null;
 
        //JS接口部分Nginx写入memcache
        boolean isInter = false;
        for(String filterPath : interFilterPath) {
            if(urlPath.indexOf(filterPath) >= 0) {
                //从nginx读取
                isInter = true;
                context = getReadData(defaultNginxPath, urlPath);
                break;
            }
        }
 
        //Tomcat读取
        if(!isInter) {
//          MonitorResponseWrapper wrapper = new MonitorResponseWrapper((HttpServletResponse) response);
            SphinxResponseWrapper wrapper = new SphinxResponseWrapper(inResponse);
            try {
                chain.doFilter(request, wrapper);
            } catch(Throwable t) {
                logger.info("读取页面内容时报错...");
                logger.info(t.getMessage());
                t.printStackTrace();
                String redirectUrl = "http://"+inRequest.getHeader("Host")+"/panosys/views/login.jsp";
                logger.info("页面异常跳转,跳转到:" + redirectUrl);
                inResponse.sendRedirect(redirectUrl);
                return;
            }
 
            context = wrapper.getResponseData();
 
//            if(urlPath.equals("/panosys/") || urlPath.equals("/panosys")) {
//              isWriteToMemcache = false;
//            }
 
            //POST过滤,不在写入缓存中
            if(inRequest.getMethod().equalsIgnoreCase("POST")) {
                isWriteToMemcache = false;
            }
 
            //获取验证码请求不写入缓存中
            if(urlPath.indexOf("getCheckCode") >= 0) {
                isWriteToMemcache = false;
            }
 
            if(context == null || context.length <= 0) {
                context = getReadData(defaultTomcatPath, urlPath);
            }
        }
 
        //modify by shma1664 2014-05-05 16:48:38
        if(context == null || context.length <= 0) {
            String redirectUrl = "http://"+inRequest.getHeader("Host")+"/panosys/views/login.jsp";
            logger.info("页面回调内容为空!页面异常跳转,跳转到:" + redirectUrl);
            inResponse.sendRedirect(redirectUrl);
        }
 
        String key = urlPath;
 
        if(isWriteToMemcache) {
            if(context != null && context.length > 0) {
                memcacheManager.put(key, context);
            }
        }
 
        // 重置响应输出的内容长度
        response.setContentLength(-1);
 
        ServletOutputStream myServletOutputStream = null;
 
        try {
            myServletOutputStream = response.getOutputStream();
            myServletOutputStream.write(context);
            myServletOutputStream.flush();
        } finally {
            if(myServletOutputStream != null) {
                myServletOutputStream.close();
                myServletOutputStream = null;
            }
        }  
 
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
//      memcacheManager = MemcacheManager.getInstance();
        memcacheManager = MemcacheClientManagerFactory.getMemcacheClientManagerFactory();
//      memcacheManager = XMemcacheManager.getInstance();
 
        interFilterPath = memcacheManager.getInterFilterPath();
        defaultNginxPath = memcacheManager.getDefaultNginxPath();
        defaultTomcatPath = memcacheManager.getDefaultTomcatPath();
 
        memcacheManager.put("key", "123456");
        logger.info(memcacheManager.get("key"));
    }
 
    public static byte[] readInputStream(InputStream inStream) throws Exception {   
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();   
        byte[] buffer = new byte[2048 * 1024];   
        int len = 0;   
        while( (len=inStream.read(buffer)) != -1 ){   
            outStream.write(buffer, 0, len);   
        }   
        inStream.close();   
        return outStream.toByteArray(); 
    } 
 
    private byte[] getReadData(String urlPath, String key) throws IOException {
        byte[] context = null;
        InputStream inStream = null;
        try {  
            String imgPath = urlPath + key;
            logger.info(imgPath);
            File fileImage = new File(imgPath);
            if(fileImage.isFile()) {
                inStream = new FileInputStream(fileImage);
                context = readInputStream(inStream);         
            } else {
                logger.error(imgPath + " 不存在!");
            }
 
        } catch (Exception e) {   
            e.printStackTrace();   
        } finally {
            if(inStream != null) {
                inStream.close();
                inStream = null;
            }
        }
 
        return context;
    }
 
}
package com.superscene.streetview.memcache;
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.log4j.Logger;
 
/**
 * <p>memcache缓存配置</p>
 * @author shma1664
 * @date 2013-12-20 10:00:05
 *
 */
public class MemcachedManagerFilter implements Filter {
 
    private MemcacheClientManagerFactory memcacheManager = null;
 
    //默认js接口部分人工读取路径
    private String[] interFilterPath = null;
 
    //当文件在tomcat找不到时,默认的nginx静态文件手工读取路径
    private String defaultNginxPath = "/usr/local/nginx/test";
    private String defaultTomcatPath = "/data/deploy/apache-tomcat-6.0.36/webapps";
 
    private static Logger logger = Logger.getLogger(MemcachedManagerFilter.class);
 
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
 
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
 
        HttpServletRequest inRequest = (HttpServletRequest) request;
        HttpServletResponse inResponse = (HttpServletResponse) response;
 
        inRequest.setCharacterEncoding("UTF-8");
        inResponse.setCharacterEncoding("UTF-8"); 
        inResponse.setContentType("text/html;charset=UTF-8");
 
        String urlPath = inRequest.getHeader("memcached_key");
//      String urlPath = inRequest.getRequestURL().toString();
        logger.info("memcached_key : " + urlPath);
 
        if(urlPath == null || urlPath.equals("")) {
            chain.doFilter(inRequest, inResponse);
            return;
        }
 
        boolean isWriteToMemcache = true;
 
        byte[] context = null;
 
        //JS接口部分Nginx写入memcache
        boolean isInter = false;
        for(String filterPath : interFilterPath) {
            if(urlPath.indexOf(filterPath) >= 0) {
                //从nginx读取
                isInter = true;
                context = getReadData(defaultNginxPath, urlPath);
                break;
            }
        }
 
        //Tomcat读取
        if(!isInter) {
//          MonitorResponseWrapper wrapper = new MonitorResponseWrapper((HttpServletResponse) response);
            SphinxResponseWrapper wrapper = new SphinxResponseWrapper(inResponse);
            try {
                chain.doFilter(request, wrapper);
            } catch(Throwable t) {
                logger.info("读取页面内容时报错...");
                logger.info(t.getMessage());
                t.printStackTrace();
                String redirectUrl = "http://"+inRequest.getHeader("Host")+"/panosys/views/login.jsp";
                logger.info("页面异常跳转,跳转到:" + redirectUrl);
                inResponse.sendRedirect(redirectUrl);
                return;
            }
 
            context = wrapper.getResponseData();
 
//            if(urlPath.equals("/panosys/") || urlPath.equals("/panosys")) {
//              isWriteToMemcache = false;
//            }
 
            //POST过滤,不在写入缓存中
            if(inRequest.getMethod().equalsIgnoreCase("POST")) {
                isWriteToMemcache = false;
            }
 
            //获取验证码请求不写入缓存中
            if(urlPath.indexOf("getCheckCode") >= 0) {
                isWriteToMemcache = false;
            }
 
            if(context == null || context.length <= 0) {
                context = getReadData(defaultTomcatPath, urlPath);
            }
        }
 
        //modify by shma1664 2014-05-05 16:48:38
        if(context == null || context.length <= 0) {
            String redirectUrl = "http://"+inRequest.getHeader("Host")+"/panosys/views/login.jsp";
            logger.info("页面回调内容为空!页面异常跳转,跳转到:" + redirectUrl);
            inResponse.sendRedirect(redirectUrl);
        }
 
        String key = urlPath;
 
        if(isWriteToMemcache) {
            if(context != null && context.length > 0) {
                memcacheManager.put(key, context);
            }
        }
 
        // 重置响应输出的内容长度
        response.setContentLength(-1);
 
        ServletOutputStream myServletOutputStream = null;
 
        try {
            myServletOutputStream = response.getOutputStream();
            myServletOutputStream.write(context);
            myServletOutputStream.flush();
        } finally {
            if(myServletOutputStream != null) {
                myServletOutputStream.close();
                myServletOutputStream = null;
            }
        }  
 
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
//      memcacheManager = MemcacheManager.getInstance();
        memcacheManager = MemcacheClientManagerFactory.getMemcacheClientManagerFactory();
//      memcacheManager = XMemcacheManager.getInstance();
 
        interFilterPath = memcacheManager.getInterFilterPath();
        defaultNginxPath = memcacheManager.getDefaultNginxPath();
        defaultTomcatPath = memcacheManager.getDefaultTomcatPath();
 
        memcacheManager.put("key", "123456");
        logger.info(memcacheManager.get("key"));
    }
 
    public static byte[] readInputStream(InputStream inStream) throws Exception {   
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();   
        byte[] buffer = new byte[2048 * 1024];   
        int len = 0;   
        while( (len=inStream.read(buffer)) != -1 ){   
            outStream.write(buffer, 0, len);   
        }   
        inStream.close();   
        return outStream.toByteArray(); 
    } 
 
    private byte[] getReadData(String urlPath, String key) throws IOException {
        byte[] context = null;
        InputStream inStream = null;
        try {  
            String imgPath = urlPath + key;
            logger.info(imgPath);
            File fileImage = new File(imgPath);
            if(fileImage.isFile()) {
                inStream = new FileInputStream(fileImage);
                context = readInputStream(inStream);         
            } else {
                logger.error(imgPath + " 不存在!");
            }
 
        } catch (Exception e) {   
            e.printStackTrace();   
        } finally {
            if(inStream != null) {
                inStream.close();
                inStream = null;
            }
        }
 
        return context;
    }
 
}

第三步:servlet配置在web.xml文件

<filter>
        <filter-name>memcached</filter-name>
        <filter-class>com.superscene.streetview.memcache.MemcachedManagerFilter</filter-class>
    </filter>
 
    <filter-mapping>
        <filter-name>memcached</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>