zoukankan      html  css  js  c++  java
  • javaEE(15)_Servlet过滤器

    一、Filter简介

    1、Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能.例如实现网站定期自动登录、URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能.
    2、Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter.通过Filter技术,开发人员可以实现用户访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示:

    二、Filter开发入门

    1、Filter开发分为二个步骤:
    •编写java类实现Filter接口,并实现其doFilter方法.
    •在 web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源.
    2、Filter链
    •在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链.
    •web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法.在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源.

    三、Filter的生命周期

    1、init(FilterConfig filterConfig)throws ServletException:
    •和我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责(Servlet也是). web 应用程序启动时,web 服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(注:filter对象只会创建一次(所有请求共享),init方法也只会执行一次)
    •开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象.
    2、destroy():
    •在Web容器卸载 Filter 对象之前被调用.该方法在Filter的生命周期中仅执行一次.在这个方法中,可以释放过滤器使用的资源.
    *Filter生命周期和ServletContext类似.

    四、FilterConfig接口

    用户在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来.因此开发人员在编写filter时,通过filterConfig对象的方法,就可获得:
    •String getFilterName():得到filter的名称.
    •String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值.如果不存在返回null.
    •Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合.
    •public ServletContext getServletContext():返回Servlet上下文对象的引用.
    *FilterConfig和ServletConfig类似,但生命周期不同.

    五、Filter案例:

    1、解决全站乱码过滤器(含开发入门&Filter链&生命周期&FilterConfig)servlet3.0规范

    @WebFilter(
            urlPatterns = { "/ServletDemo1" }, 
            initParams = { 
               @WebInitParam(name = "charset", value = "UTF-8", description = "编码")
            })
    public class FilterDemo1 implements Filter {
        FilterConfig fConfig=null;
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
            System.out.println("FilterDemo1 doFilter 前!");
            String charset = fConfig.getInitParameter("charset");
            HttpServletRequest req = (HttpServletRequest)request;
            req.setCharacterEncoding(charset);
            
            //这两句用来设置当servlet打印页面时的编码设置,实际开发中都是转发给jsp,由jsp来通过指令和meta标签进行设置
            /*HttpServletResponse resp = (HttpServletResponse)response;
            resp.setCharacterEncoding(charset);
            resp.setContentType(charset);*/
            
            chain.doFilter(request, response);
            System.out.println("FilterDemo1 doFilter 后!");
        }
    
        public void init(FilterConfig fConfig) {
            System.out.println("FilterDemo1 init!");
            this.fConfig = fConfig;
        }
        
        public void destroy() {
            System.out.println("FilterDemo1 destroy!");
        }
    }
    @WebFilter("/ServletDemo1")
    public class FilterDemo2 implements Filter {
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
            System.out.println("FilterDemo2 doFilter 前!");
            chain.doFilter(request, response);
            System.out.println("FilterDemo2 doFilter 后!");
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
            System.out.println("FilterDemo2 init!");
        }
        
        public void destroy() {
            System.out.println("FilterDemo2 destroy!");
        }
    }
    @WebServlet("/ServletDemo1")
    public class ServletDemo1 extends HttpServlet {
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) {
            String name = request.getParameter("username");
            System.out.println("ServletDemo1 doget! name="+name);
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) {
            this.doGet(request, response);
        }
        
        public void init(ServletConfig config) throws ServletException {
            System.out.println("ServletDemo1 init!");
        }
    
        public void destroy() {
            System.out.println("ServletDemo1 destroy!");
        }
    }
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <form action="${pageContext.request.contextPath}/ServletDemo1 " method="post">
            <input name="username" />
            <input type="submit" value="提交"/>
        </form>
    </body>
    </html>

    运行结果:

    1、当服务器启动时:

    FilterDemo2 init!
    FilterDemo1 init!

    首先初始化FilterDemo2,与调用doFilter的顺序刚好相反(doFilter的调用顺序与类的名称相关).

    2、当在demo1.jsp中输入中文点击提交时:

    ServletDemo1 init!
    FilterDemo1 doFilter 前!
    FilterDemo2 doFilter 前!
    ServletDemo1 doget! name=王维
    FilterDemo2 doFilter 后!
    FilterDemo1 doFilter 后!

    3、当服务器关闭或者项目重新发布时:

    ServletDemo1 destroy!
    FilterDemo2 destroy!
    FilterDemo1 destroy!

    如上所示的servlet过滤器可以实现当访问说有的servlet时,在它之前进行编码设置.

    2、控制浏览器缓存页面中的静态资源,禁止浏览器缓存动态页面

    •场景:有些动态页面中引用了一些图片或css文件以修饰页面效果,这些图片和css文件经常是不变化的,所以为减轻服务器的压力,可以使用filter控制浏览器缓存这些文件,以提升服务器的性能.web站点优化,越在前端效果越好,比后端做缓存效果好.
    <!--测试jsp页面,此页面首次访问时共会向服务器发送3次请求  -->
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <link rel="stylesheet" type="text/css" href="/Filter/css/1.css">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>noCache</title>
    </head>
    <body>
        hello
        <img id="img1" alt="ss" src="/Filter/image/1.png">
    </body>
    </html>
    //控制jsp不缓存的Filter,我们的jsp都是由servlet forward来的
    @WebFilter(dispatcherTypes = {DispatcherType.FORWARD }, urlPatterns = { "*.jsp" })//ps备注
    public class NoCacheFilter implements Filter {
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
            HttpServletResponse resp = (HttpServletResponse)response;
            
            //注意一个是setDateHeader另两个是setHeader
            resp.setDateHeader("Expires",-1);
            resp.setHeader("Cache-Control","no-cache");
            resp.setHeader("Pragma","no-cache");
            
            chain.doFilter(request, response);
        }
    
        public void destroy() {
        }
        public void init(FilterConfig arg0) throws ServletException {
        }
    }
    //控制css文件和图片缓存的Filter
    @WebFilter(
            urlPatterns={"*.css","*.png"},//一个Filter可对应多个url映射,类似Servlet
            initParams = { 
                 @WebInitParam(name = "cssExpires", value = "6000", description = "css文件缓存时间"),
                 @WebInitParam(name = "imageExpires", value = "6000", description = "图片文件缓存时间")
            })
    public class CacheFilter implements Filter {
        FilterConfig fConfig=null;
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
            HttpServletResponse resp = (HttpServletResponse)response;
            HttpServletRequest req = (HttpServletRequest)request;
            
            String cssExpires = fConfig.getInitParameter("cssExpires");
            String imageExpires = fConfig.getInitParameter("imageExpires");
            
            String uri = req.getRequestURI();
            if(uri.endsWith("css")){
                //这里注意是setDateheader不是setHeader
                resp.setDateHeader("Expires",System.currentTimeMillis()+Long.parseLong(cssExpires));
            }else{
                resp.setDateHeader("Expires",System.currentTimeMillis()+Long.parseLong(imageExpires));
            }
            chain.doFilter(request, response);
        }
        
        public void init(FilterConfig fConfig) throws ServletException {
            this.fConfig=fConfig;
        }
        public void destroy() {
        }
    }

    ps:1、Ctrl+F5强制刷新的话,不管浏览器有没有缓存都会向服务器重新请求.

        2、<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST.用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截.

    <dispatcher> 子元素可以设置的值及其意义:
    REQUEST:当用户直接访问页面时,Web容器将会调用过滤器.如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用.
    INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用.除此之外,该过滤器不会被调用.
    FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用.
    ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用.除此之外,过滤器不会被调用.

    用法实例:

    <filter-mapping>
         <filter-name>testFilter</filter-name>
         <url-pattern>/test.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>testFilter</filter-name>
        <url-pattern>/index.jsp</url-pattern>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

    3、实现用户自动登陆的过滤器      *代码非常经典

    <!--登陆界面  -->
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>My JSP 'login.jsp' starting page</title>
      </head>
      
      <body>     
           <form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="post">
               用户名:<input type="text" name="username"><br/>
               密码:<input type="password" name="password"><br/>
               有效期:
               1分钟<input type="radio" name="time" value="${1*60 }">
               5分钟<input type="radio" name="time" value="${5*60 }">
               10分钟<input type="radio" name="time" value="${10*60 }">
               <br/>
               <input type="submit" value="登陆">
           </form>
      </body>
    </html>
    
    //登陆Servlet
    public class LoginServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response){
    
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    
            BusinessService service = new BusinessService();
            User user = service.login(username, password);
            if (user == null) {
                request.setAttribute("message", "用户名或密码错误!!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }
    
            request.getSession().setAttribute("user", user);
    
            // 给客户机发送自动登陆的 cookie
         //把username回写给cookie,Filter需要通过username拿到用户信息,校验cookie带的md5和服务器算出的MD5是否一致,判断cookie有没有被修改
            int expirestime = Integer.parseInt(request.getParameter("time"));
            // autologin=username:expirestime:md5(password:expirestime:username)
            Cookie cookie = makeCookie(user, expirestime);
            response.addCookie(cookie);
            response.sendRedirect("/day19/index.jsp");
        }
    
        public Cookie makeCookie(User user, int expirestime) {
            long currenttime = System.currentTimeMillis();
            String cookieValue = user.getUsername() + ":" + (currenttime + expirestime * 1000) + ":"
                    + md5(user.getUsername(), user.getPassword(), (currenttime + expirestime * 1000));
            Cookie cookie = new Cookie("autologin", cookieValue);
            cookie.setMaxAge(expirestime);
            cookie.setPath("/day19");
            return cookie;
        }
    
        private String md5(String username, String password, long expirestime) {
            try {
                String value = password + ":" + expirestime + ":" + username;
                MessageDigest md = MessageDigest.getInstance("md5");
                byte md5[] = md.digest(value.getBytes());
                BASE64Encoder encode = new BASE64Encoder();
                return encode.encode(md5);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception {
            doGet(request, response);
        }
    
    }
    
    //自动登录拦截器
    @WebFilter("*.*") // 访问所有资源都进行拦截
    public class AutoLoginFilter implements Filter {
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
                throws IOException, ServletException {
    
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
    
            // 1.先检查用户是否已登陆,没登陆才自动登陆
            User user = (User) request.getSession().getAttribute("user");
            if (user != null) {
                chain.doFilter(request, response);
                return;
            }
    
            // 2.没登陆,再执行自动登陆逻辑
    
            // 看用户有没有带自动登陆的cookie
            Cookie autoLoginCookie = null;
            Cookie cookies[] = request.getCookies();
            for (int i = 0; cookies != null && i < cookies.length; i++) {
                if (cookies[i].getName().equals("autologin")) {
                    autoLoginCookie = cookies[i];
                }
            }
            if (autoLoginCookie == null) {
                chain.doFilter(request, response);
                return;
            }
    
            // 用户带了自动登陆的cookie,则先检查cookie的有效期
            String values[] = autoLoginCookie.getValue().split("\:");
            if (values.length != 3) {
                chain.doFilter(request, response);
                return;
            }
            long expirestime = Long.parseLong(values[1]);
            if (System.currentTimeMillis() > expirestime) {
                chain.doFilter(request, response);
                return;
            }
    
            // 代表cookie时间有效,再检查cookie的有效性
            String username = values[0];
            String client_md5 = values[2];
    
            BusinessService service = new BusinessService();
            user = service.findUser(username);
            if (user == null) {
                chain.doFilter(request, response);
                return;
            }
            //// autologin=username:expirestime:md5(password:expirestime:username)
            String server_md5 = md5(user.getUsername(), user.getPassword(), expirestime);
            if (!server_md5.equals(client_md5)) {
                chain.doFilter(request, response);
                return;
            }
    
            // 执行登陆
            request.getSession().setAttribute("user", user);
            chain.doFilter(request, response);
        }
    
        private String md5(String username, String password, long expirestime) {
            try {
                String value = password + ":" + expirestime + ":" + username;
                MessageDigest md = MessageDigest.getInstance("md5");
                byte md5[] = md.digest(value.getBytes());
                BASE64Encoder encode = new BASE64Encoder();
                return encode.encode(md5);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        public void destroy() {
        }
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }

    六、Decorator设计模式

    •1.首先看需要被增强对象继承了什么接口或父类,编写一个类也去继承这些接口或父类.
    •2.在类中定义一个变量,变量类型即需增强对象的类型.
    •3.在类中定义一个构造函数,接收需增强的对象.
    •4.覆盖需增强的方法,编写增强的代码.

    由于开发人员在filter中可以得到代表用户请求和响应的request、response对象,因此在编程中可以使用Decorator(装饰器)模式对request、response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求.

    Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,(HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法)以避免用户在对request对象进行增强时需要实现request接口中的所有方法.
    request对象的增强案例如下:
    例1、真正解决全站乱码
    public class CharacterEncodingFilter2 implements Filter {
    
        public void doFilter(ServletRequest req, ServletResponse resp,
                FilterChain chain) throws IOException, ServletException {
            
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
            
            request.setCharacterEncoding("UTF-8");  //只能解决post乱码问题
            
            chain.doFilter(new MyRequest(request), response); 
        }
        
        class MyRequest extends HttpServletRequestWrapper{
    
            private HttpServletRequest request;
            public MyRequest(HttpServletRequest request) {
                super(request);
                this.request = request;
            }
            @Override
            public String getParameter(String name) {
                
                String value = this.request.getParameter(name);
                if(!request.getMethod().equalsIgnoreCase("get")){
                    return value;
                }
                if(value==null){
                    return null;
                }
                try {
                    return value = new String(value.getBytes("iso8859-1"),request.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        public void destroy() {
        }
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }

    例2、使用Decorator模式包装request对象,实现html标签转义功能(Tomcat服务器中提供了转义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;
            
            chain.doFilter(new MyRequest(request), response);  
        }
        
        class MyRequest extends HttpServletRequestWrapper{
            private HttpServletRequest request;
            public MyRequest(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());
            }
        }
        public void init(FilterConfig filterConfig) throws ServletException {
        }
        public void destroy() {
        }
    }

    例3、词汇过滤器

    其实和html标签转义功能完全类似,使用装饰器模式,拦截getParameter方法,当在servlet中调用getParameter方法时,实际调用的是我修改过的getParameter方法,该方法对词汇进行了过滤.

    response对象的增强最经典案例-压缩响应如下:

    1、Servlet  API 中提供了response对象的Decorator设计模式的默认实现类HttpServletResponseWrapper , (HttpServletResponseWrapper类实现了response接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 response对象的对应方法)以避免用户在对response对象进行增强时需要实现response接口中的所有方法.

    2、应用HttpServletResponseWrapper对象,压缩响应正文内容.思路:

    •通过filter向目标页面传递一个自定义的response对象.
    •在自定义的response对象中,重写getOutputStream方法和getWriter方法,使目标资源调用此方法输出页面内容时,获得的是我们自定义的ServletOutputStream对象.
    •在我们自定义的ServletOuputStream对象中,重写write方法,使写出的数据写出到一个buffer中.
    •当页面完成输出后,在filter中就可得到页面写出的数据,从而我们可以调用GzipOuputStream对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能.

    例1、没有实现全站式的压缩

    //压缩输出
    public class ServletDemo2 extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            String data = "aaaaaaaa";
            
            ByteArrayOutputStream bout = new ByteArrayOutputStream();//缓存字节流
            GZIPOutputStream gout = new GZIPOutputStream(bout);
            gout.write(data.getBytes());
            gout.close();//确保写入缓存流成功
            
            byte gzip[] = bout.toByteArray();
            response.setHeader("content-encoding", "gzip");
            response.setHeader("content-length", gzip.length + "");
            
            response.getOutputStream().write(gzip);
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    }

    例2、全站式压缩实现

    //giz压缩过滤器
    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;
            MyResponse myresponse = new MyResponse(response);
            
            //response.getwriter  response.getOutputStream 
            chain.doFilter(request, myresponse);   
            
            //取出缓冲的数据压缩后输出
            byte out[] = myresponse.getBuffer();  //得到目标资源的输出
            System.out.println("压之前:" + out.length);
            
            byte gzipout[] = gzip(out);
            System.out.println("压之后:" + gzipout.length);
            
            response.setHeader("content-encoding", "gzip");
            response.setHeader("content-length", gzipout.length + "");
            response.getOutputStream().write(gzipout);
        }
        
        public byte[] gzip(byte b[]) throws IOException{
            
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            GZIPOutputStream gout = new GZIPOutputStream(bout);
            gout.write(b);
            gout.close();
            return bout.toByteArray();
        }
        
        class MyResponse extends HttpServletResponseWrapper{
            private ByteArrayOutputStream bout = new ByteArrayOutputStream();
            private PrintWriter pw;
            
            private HttpServletResponse response;
            public MyResponse(HttpServletResponse response) {
                super(response);
                this.response = response;
            }
            @Override
            public ServletOutputStream getOutputStream() throws IOException {
                return new MyServletOutputStream(bout);    //myresponse.getOutputStream().write("hahah");
            }
            
            @Override
            public PrintWriter getWriter() throws IOException {
                pw = new PrintWriter(new OutputStreamWriter(bout,response.getCharacterEncoding()));
                return pw;  //MyResponse.getWriter().write("中国");
            }
            public byte[] getBuffer(){
                if(pw!=null){
                    pw.close();
                }
                return bout.toByteArray();
            }
        }
        
        class MyServletOutputStream extends ServletOutputStream{
    
            private ByteArrayOutputStream bout;
            public MyServletOutputStream(ByteArrayOutputStream bout){
                this.bout = bout;
            }
            @Override
            public void write(int b) throws IOException {
                bout.write(b);
            }
        }
        public void destroy() {
        }
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }
    public class GzipServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            String data = "中国";
            response.getOutputStream().write(data.getBytes("UTF-8"));
            request.getRequestDispatcher("/index.jsp").forward(request, response);
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    }

    web.xml配置

    <filter>
        <filter-name>GzipFilter</filter-name>
        <filter-class>cn.itcast.web.filter.example.GzipFilter</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.js</url-pattern>
    </filter-mapping>

    ps:gzip一般压缩文本类型的数据,对图片视频等压缩率较低.

    ***有一点要注意,当servlet中以forward方式转发给另一个servlet时,实际是通知tomcat去调用另一个servlet,这其中如果有拦截器的话会执行.

    七、实用案例-缓存数据到内存  

    对于页面中很少更新的数据,例如商品分类,为避免每次都要从数据库查询分类数据,因此可把分类数据缓存在内存或文件中,以此来减轻数据库压力,提高系统响应速度.
    //可以配置给几个指定的servlet
    public
    class WebCacheFilter implements Filter { private Map<String,byte[]> map = new HashMap(); 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.看map集合中是否保存了该资源的数据 byte b[] = map.get(uri); //3.如果保存了,则直接取数据打给浏览器 if(b!=null){ response.getOutputStream().write(b); return;//servlet就不执行了 } //4.如果没有保存数据,则放行让目标资源执行,这时还需写一个response的包装类,捕获目标资源的输出 MyResponse my = new MyResponse(response); chain.doFilter(request, my); byte data[] = my.getBuffer(); //5.以资源uri为关键字,打资源的数据保存map集合中,以备于下次访问 map.put(uri, data); //6.输出数据给浏览器 response.getOutputStream().write(data); } class MyResponse extends HttpServletResponseWrapper{ private ByteArrayOutputStream bout = new ByteArrayOutputStream(); private PrintWriter pw; private HttpServletResponse response; public MyResponse(HttpServletResponse response) { super(response); this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(bout); //myresponse.getOutputStream().write("hahah"); } @Override public PrintWriter getWriter() throws IOException { pw = new PrintWriter(new OutputStreamWriter(bout,response.getCharacterEncoding())); return pw; //MyResponse.getWriter().write("中国"); } public byte[] getBuffer(){ if(pw!=null){ pw.close(); } return bout.toByteArray(); } } class MyServletOutputStream extends ServletOutputStream{ private ByteArrayOutputStream bout; public MyServletOutputStream(ByteArrayOutputStream bout){ this.bout = bout; } @Override public void write(int b) throws IOException { bout.write(b); } } public void init(FilterConfig filterConfig) throws ServletException { } public void destroy() { } }

    ps:过滤器经典案例,权限系统,略。

  • 相关阅读:
    P2319 [HNOI2006]超级英雄
    P4302 [SCOI2003]字符串折叠
    P1122 最大子树和
    HDU——2089 不要62
    P4555 最长双回文串
    P1463 [HAOI2007]反素数
    P2412 查单词
    P2787 语文1(chin1)- 理理思维
    P3078 [USACO13MAR]扑克牌型Poker Hands
    ubuntu中desktop与alternate版本的区别(转载)
  • 原文地址:https://www.cnblogs.com/wangweiNB/p/4998650.html
Copyright © 2011-2022 走看看