Java web开发——过滤器Filter的常见使用

一、基本介绍

1、概念

       Filter也称之为过滤器,通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。

2、原理图

注意:filter在web程序启动的时候被创建(和servlet相似)、init()方法也只在启动的时候调用一次。

二、技术详情

1、入门案例

1.编写Filter

public class FilterDemo1 implements Filter {
​
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        System.out.println("filterdemo1执行前!!!");//部分1

        chain.doFilter(request, response);  //让目标资源执行,放行  部分2

        System.out.println("filterdemo1执行后!!!");    //部分3
​
    }
​
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
​
    }
    public void destroy() {
        // TODO Auto-generated method stub
​
    }
​
}

注意:假如该过滤器拦截index.jsp,如果没有部分2,那么index.jsp是不会执行的

说明:在部分1中可以先对request、response进行加工,来对多个资源进行处理,如解决乱码问题(这样所以的servlet都解决了)

//对request和response进行一些预处理

request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");

在部分2中可以返回执行的结果,如果下一层(servlet、filter...)还没有执行完的话,2是不会执行的(参考下)

2.配置Filter

在web.xml文件中

  <filter>
    <filter-name>FilterDemo1</filter-name>
    <filter-class>com.shen.web.filter.FilterDemo1</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>FilterDemo1</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

注意:这里拦截所有的url(参考servlet),即所有的资源都要先通过FilterDemo1过滤器

2、多重Filter(Filter链)

     假如现在有两个filter

1.配置文件

  <filter>
    <filter-name>FilterDemo1</filter-name>
    <filter-class>com.shen.web.filter.FilterDemo1</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>FilterDemo1</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <filter>
    <filter-name>FilterDemo2</filter-name>
    <filter-class>com.shen.web.filter.FilterDemo2</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>FilterDemo2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

注意:谁个在前面谁个先执行(FilterDemo1先执行)

2.程序

FilterDemo1:

        System.out.println("filterdemo1执行前!!!");

        chain.doFilter(request, response);  //让目标资源执行,放行

        System.out.println("filterdemo1执行后!!!");

FilterDemo2:

        System.out.println("filterdemo2执行前~!!");
        chain.doFilter(request, response);
        System.out.println("filterdemo2执行后~!!");

ServletDemo1:

        System.out.println("servletdemo1");
        request.getRequestDispatcher("/index.jsp").forward(request, response);

3.结果

filterdemo1执行前!

filterdemo2执行前!

servletdemo1

filterdemo2执行后!

filterdemo1执行后!

3、初始化参数

1.配置

  <filter>
    <filter-name>FilterDemo3</filter-name>
    <filter-class>com.shen.web.filter.FilterDemo3</filter-class>
    <init-param>
        <param-name>xxx</param-name>
        <param-value>yyy</param-value>
    </init-param>

  </filter>

2.获取

public class FilterDemo3 implements Filter {
​
    private FilterConfig config = null;//应为初始化在init中

    public void init(FilterConfig filterConfig) throws ServletException {
        this.config = filterConfig;
​
    }

    public void destroy() {
    }
​
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        //获取配置的初始化参数
        System.out.println(this.config.getInitParameter("xxx"));
    }   
​
}

附:所有获取方式

  • String getFilterName():得到filter的名称。
  • String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
  • Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
  • public ServletContext getServletContext():返回Servlet上下文对象的引用。

4、配置拦截类型

  <filter>
    <filter-name>FilterDemo4</filter-name>
    <filter-class>com.shen.web.filter.FilterDemo4</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>FilterDemo4</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>ERROR</dispatcher><!--在这里指定拦截的方式-->
  </filter-mapping>

说明:获取页面(error.jsp),只有在以错误处理的方式获取时,才会拦截,如果直接以http://local.../error.jsp 方式来访问时,是不会被拦截的。

其他类型:

REQUEST 当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用
INCLUDE 如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用
FORWARD 如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用
ERROR 如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用

注意:默认是REQUEST

三、常见应用

1、禁止缓存所有动态页面

配置:

  <filter>
    <filter-name>NoCacheFilter</filter-name>
    <filter-class>com.shen.web.filter.NoCacheFilter</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>NoCacheFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>

代码:

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        response.setDateHeader("Expires", -1);
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        chain.doFilter(request, response);
​
    }

2、缓存页面中的静态资源

配置:

  <filter-mapping>
    <filter-name>AutoLoginFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <filter>
    <filter-name>ExpiresFilter</filter-name>
    <filter-class>com.shen.web.filter.ExpiresFilter</filter-class>

    <init-param>
        <param-name>css</param-name>
        <param-value>4</param-value><!--缓存时间为4小时-->
    </init-param>

    <init-param>
        <param-name>jpg</param-name>
        <param-value>1</param-value>
    </init-param>

    <init-param>
        <param-name>js</param-name>
        <param-value>4</param-value>
    </init-param>

    <init-param>
        <param-name>bmp</param-name>
        <param-value>4</param-value>
    </init-param>

  </filter>
  
  <filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>*.jpg</url-pattern>
  </filter-mapping>
  
  <filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>*.css</url-pattern>
  </filter-mapping>
  
  <filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>*.js</url-pattern>
  </filter-mapping>

代码:

//控制缓存的filter
public class ExpiresFilter implements Filter {
​
    private FilterConfig filterConfig;
​
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        //1.获取用户想访问的资源
        String uri = request.getRequestURI(); 

        //2.得到用户想访问的资源的后缀名
        String ext = uri.substring(uri.lastIndexOf(".")+1);

        //得到资源需要缓存的时间
        String time = filterConfig.getInitParameter(ext);
        if(time!=null){
            long t = Long.parseLong(time)*3600*1000;
            response.setDateHeader("expires", System.currentTimeMillis() + t);
        }

        chain.doFilter(request, response);
​
    }

3、实现用户自动登陆

配置:

  <filter>
    <filter-name>AutoLoginFilter</filter-name>
    <filter-class>com.shen.web.filter.AutoLoginFilter</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>AutoLoginFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

页面:

登陆::

    <form action="${pageContext.request.contextPath }/servlet/LoginServlet"  method="post">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        有效期:
            <input type="radio" name="logintime" value="3600">1小时
            <input type="radio" name="logintime" value="${10*60 }">10分钟
            <input type="radio" name="logintime" value="${5*60 }">5分钟

            <br/>

        <input type="submit" value="登陆">

    </form>

显示::(message)

    ${message }

代码:

实体::(user)

public class User {
    private String username;
    private String password;
        //get和set和构造函数
}

数据库(模拟)::(MyDb)

public class MyDb {
​
    private static List list = new ArrayList();

    static{
        list.add(new User("aaa","123"));
        list.add(new User("bbb","123"));
        list.add(new User("ccc","123"));
    }

    public static List getAll(){
        return list;
    }

}

注意:密码在这里存的是明文

登陆::(LoginServlet)

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
​
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        UserDao dao = new UserDao();
        User user = dao.find(username, password);
        if(user==null){
            request.setAttribute("message", "用户名或密码不对!!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return;
        }

        request.getSession().setAttribute("user", user);
        request.setAttribute("message", "恭喜,登陆成功!!");

        //发送自动登陆cookie
        sendAutoLoginCookie(request,response,user);
        request.getRequestDispatcher("/message.jsp").forward(request, response);
    }
​
    private void sendAutoLoginCookie(HttpServletRequest request, HttpServletResponse response, User user) {

        int logintime = Integer.parseInt(request.getParameter("logintime"));
        Cookie cookie = new Cookie("autologin",user.getUsername() + "." + WebUtils.md5(user.getPassword()));//“.”为分割符【md5加密后不产生.】,autologin="username.password"
        cookie.setMaxAge(logintime);
        cookie.setPath("/day18");
        response.addCookie(cookie);
    }

注意:存给cookie的是md5加密后的

Md5加密:WebUtils

public class WebUtils {
    public static String md5(String message) {
​
        try {
            MessageDigest md = MessageDigest.getInstance("md5");
            byte result[] = md.digest(message.getBytes());
​
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(result);
​
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
​
    }
}

过滤器::(AutoLoginFilter)

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        if(request.getSession().getAttribute("user")!=null){//如果用户已经登陆,直接放行
            chain.doFilter(request, response);
            return;
        }


        //1.得到用户带过来的authlogin的cookie,
        String value = null;
        Cookie cookies[] = request.getCookies();
        for(int i=0;cookies!=null && i<cookies.length;i++){
            if(cookies[i].getName().equals("autologin")){
                value = cookies[i].getValue();
            }
        }

        //2.得到 cookie中的用户名和密码 
        if(value!=null){
            String username = value.split("\\.")[0];
            String password = value.split("\\.")[1];

            //3.调用dao获取用户对应的密码
            UserDao dao = new UserDao();
            User user = dao.find(username);
            String dbpassword = user.getPassword();

            //4.检查用户带过来的md5的密码和数据库中的密码是否匹配,如匹配则自动登陆
            if(password.equals(WebUtils.md5(dbpassword))){
                request.getSession().setAttribute("user", user);
            }
        }

        chain.doFilter(request, response);
​
    }

4、解决全站乱码问题

配置:

   <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>com.shen.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>charset</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

代码:

//解决全站乱码问题
public class CharacterEncodingFilter implements Filter {
​
    private FilterConfig filterConfig = null;
    private String defaultCharset = "UTF-8";//设置一个默认值
​
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        String charset = filterConfig.getInitParameter("charset");
        if(charset==null){
            charset = defaultCharset;
        }

        request.setCharacterEncoding(charset);  //其实只能解决post方式
        response.setCharacterEncoding(charset);
        response.setContentType("text/html;charset=" + charset);


        chain.doFilter(request, response);

    }
​
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
​
    }

    public void destroy() {
        // TODO Auto-generated method stub
​
    }
​
}

注意:以上代码实际上只能解决post方式的请求,而不能解决get方式。

5、对request进行增强

1.解决全站乱码

1.包装设计

如果想要解决get方式请求,需要采用包装类的设计思想(将request进行增强):

  • 实现与被增强对象相同的接口 
  • 定义一个变量记住被增强对象
  • 定义一个构造器,接收被增强对象
  • 覆盖需要增强的方法
  • 对于不想增强的方法,直接调用被增强对象(目标对象)的方法
//为解决全站乱码
public class CharacterEncodingFilter implements Filter {
​
    public void destroy() {
        // TODO Auto-generated method stub
​
    }
​
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        request.setCharacterEncoding("gb2312");
        response.setCharacterEncoding("gb2312");
        response.setContentType("text/html;charset=gb2312");


        MyCharacterEncodingRequest requestWrapper = new MyCharacterEncodingRequest(request);
        chain.doFilter(requestWrapper, response);

​
    }
​
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
​
    }
}
​
​

class MyCharacterEncodingRequest extends HttpServletRequestWrapper{

    private HttpServletRequest request;
    public MyCharacterEncodingRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }
    @Override
    public String getParameter(String name) {

        try{
            String value= this.request.getParameter(name);
            if(value==null){
                return null;
            }

            if(!this.request.getMethod().equalsIgnoreCase("get")) {
                return value;
            }

            value = new String(value.getBytes("ISO8859-1"),this.request.getCharacterEncoding());
            return value;

        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

2.动态代理

public class CharacterEncodingFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;


        request.setCharacterEncoding("UTF-8");  //post
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");


        //request.getParamter()  requestProxy.getParameter()
        chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(),request.getClass().getInterfaces(), new InvocationHandler(){
​
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {

                if(!method.getName().equals("getParameter")){
                    return method.invoke(request, args);
                }

                if(!request.getMethod().equalsIgnoreCase("get")){
                    return method.invoke(request, args);
                }

                //getParameter get
                String value = (String) method.invoke(request, args);
                if(value==null){
                    return null;
                }

                return new String(value.getBytes("iso8859-1"),"UTF-8");
            }

        }), response);  

​
    }

​
    public void destroy() {}
    public void init(FilterConfig filterConfig) throws ServletException {}
​
}

2.对脏话进行处理

//脏话过滤器
public class DirtyFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
​

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        DirtyRequest dirtyrequest = new DirtyRequest(request);

        chain.doFilter(dirtyrequest, response);
    }
​
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void destroy() {
    }
}
​
class DirtyRequest extends HttpServletRequestWrapper{
​
    private List<String> dirtyWords = Arrays.asList("傻B","操蛋","畜生");
    private HttpServletRequest request;
    public DirtyRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }
    @Override
    public String getParameter(String name) {

        String value = this.request.getParameter(name);
        if(value==null){
            return null;
        }

        for(String dirtyWord : dirtyWords){
            if(value.contains(dirtyWord)){
                value = value.replace(dirtyWord, "****");
            }
        }
        return value;
    }
}

3.对HTML元素进行处理

//html转义过滤器
public class HtmlFilter implements Filter {
​
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
​
        MyHtmlRequest myrequest = new MyHtmlRequest(request);
        chain.doFilter(myrequest, response);

    }
    public void destroy() {
        // TODO Auto-generated method stub
​
    }
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
​
    }
}
​
class MyHtmlRequest extends HttpServletRequestWrapper{
​
    private HttpServletRequest request;

    public MyHtmlRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }
    @Override
    public String getParameter(String name) {

        String value = this.request.getParameter(name);
        if(value==null){
            return null;
        }
        return filter(value);
    }

     public String filter(String message) {
​
            if (message == null)
                return (null);
​
            char content[] = new char[message.length()];
            message.getChars(0, message.length(), content, 0);
            StringBuffer result = new StringBuffer(content.length + 50);
            for (int i = 0; i < content.length; i++) {
                switch (content[i]) {
                case '<':
                    result.append("&lt;");
                    break;
                case '>':
                    result.append("&gt;");
                    break;
                case '&':
                    result.append("&amp;");
                    break;
                case '"':
                    result.append("&quot;");
                    break;
                default:
                    result.append(content[i]);
                }
            }
            return (result.toString());
​
        }   
}

6、对response进行增强

1.全站压缩

1.包装设计模式

//解决全站压缩
public class GzipFilter implements Filter {
​
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        BufferResponse myresponse = new BufferResponse(response);

        chain.doFilter(request, myresponse);


        //拿出缓存中的数据,压缩后再打给浏览器
        byte out[] = myresponse.getBuffer();
        System.out.println("原始大小:" + out.length);

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        GZIPOutputStream gout = new GZIPOutputStream(bout);
        gout.write(out);
        gout.close();


        byte gzip[] = bout.toByteArray();
        System.out.println("压缩后的大小:" + gzip.length);


        response.setHeader("content-encoding", "gzip");
        response.setContentLength(gzip.length);
        response.getOutputStream().write(gzip);
    }

    public void destroy() {
    }
​
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}
​
class BufferResponse extends HttpServletResponseWrapper{
​
    private ByteArrayOutputStream bout = new ByteArrayOutputStream();

    private PrintWriter pw;
    private HttpServletResponse response;
    public BufferResponse(HttpServletResponse response) {
        super(response);
        this.response = response;
    }
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new MyServletOutputStream(bout);
    }
    @Override
    public PrintWriter getWriter() throws IOException {
        pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding()));  //PrintWriter.write(中国) <br>,要指定码表,不然可能乱码!!!!!!!!!!!!
        return pw;
    }

    public byte[] getBuffer(){
        try{
            if(pw!=null){
                pw.close();
            }
            if(bout!=null){
                bout.flush();
                return bout.toByteArray();
            }


            return null;
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
​
class MyServletOutputStream extends ServletOutputStream{
​
    private ByteArrayOutputStream bout;
    public MyServletOutputStream(ByteArrayOutputStream bout){
        this.bout = bout;
    }

    @Override
    public void write(int b) throws IOException {
        this.bout.write(b);
    }
}

2.动态代理技术

public class GzipFilter implements Filter {
​
    public void destroy() {
        // TODO Auto-generated method stub
​
    }
​
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
​

        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) resp;

        final ByteArrayOutputStream bout = new ByteArrayOutputStream();
        final PrintWriter pw = new PrintWriter(new OutputStreamWriter(bout,"UTF-8"));

        //response.getWriter().write("aaa");  responseProxy
        chain.doFilter(request, (ServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(), response.getClass().getInterfaces(), new InvocationHandler(){
​
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                if(method.getName().equals("getWriter")){
                    return pw; 
                }else if(method.getName().equals("getOutputStream")){  //servletOutputStream
                    return new MyServletOutputStream(bout);
                }else{
                    return method.invoke(response, args);
                }
            }
        }));


        pw.close();
        byte result[] = bout.toByteArray();  //拿到目标资源的输出
        System.out.println("原始大小:" + result.length);

        ByteArrayOutputStream bout2 = new ByteArrayOutputStream();
        GZIPOutputStream gout = new GZIPOutputStream(bout2);
        gout.write(result);
        gout.close();

        byte gzip[] = bout2.toByteArray();  //拿到目标资源输出的压缩数据
        System.out.println("压缩大小:" + gzip.length);

        response.setHeader("content-encoding", "gzip");
        response.setContentLength(gzip.length);
        response.getOutputStream().write(gzip);


    }
​
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
​
    }
}
​
class MyServletOutputStream extends ServletOutputStream{
​

    private ByteArrayOutputStream  bout = null;
    public MyServletOutputStream(ByteArrayOutputStream  bout){
        this.bout = bout;
    }
    @Override
    public void write(int b) throws IOException {
        bout.write(b);
    }

}

2.缓存数据到内存

     对于页面中很少更新的数据,例如商品分类,为避免每次都要从数据库查询分类数据,因此可把分类数据缓存在内存或文件中,以此来减轻数据库压力,提高系统响应速度。

//缓存数据到内存
public class CachedFilter implements Filter {
​
    private Map<String,byte[]> map = new HashMap<String,byte[]>();
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //1.得到用户请求的uri
        String uri = request.getRequestURI();
        //2.看缓存中有没有uri对应的数据
        byte b[] = map.get(uri);
        //3.如果缓存中有,直接拿缓存的数据打给浏览器,程序返回
        if(b!=null){
            response.getOutputStream().write(b);
            return;
        }
        //4.如果缓存没有,让目标资源执行,并捕获目标资源的输出
        BufferResponse1 myresponse = new BufferResponse1(response);
        chain.doFilter(request, myresponse);
        byte out[] = myresponse.getBuffer();
        //5.把资源的数据以用户请求的uri为关键字保存到缓存中
        map.put(uri, out);
        //6.把数据打给浏览器
        response.getOutputStream().write(out);
    }
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    public void destroy() {
    }
}

class BufferResponse1 extends HttpServletResponseWrapper{​
    private ByteArrayOutputStream bout = new ByteArrayOutputStream();  //捕获输出的缓存
    private PrintWriter pw;
    private HttpServletResponse response;
    public BufferResponse1(HttpServletResponse response) {
        super(response);
        this.response = response;
    }
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new MyServletOutputStream1(bout);
    }
    @Override
    public PrintWriter getWriter() throws IOException {
        pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding()));
        return pw;
    }
    public byte[] getBuffer(){
        try{
            if(pw!=null){
                pw.close();
            }
            return bout.toByteArray();
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
class MyServletOutputStream1 extends ServletOutputStream{
    private ByteArrayOutputStream bout;
    public MyServletOutputStream1(ByteArrayOutputStream bout){  //接收数据写到哪里
        this.bout = bout;
    }
    @Override
    public void write(int b) throws IOException {
        bout.write(b);
    }
}
 

猜你喜欢

转载自blog.csdn.net/qq_22172133/article/details/81367028