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:过滤器经典案例,权限系统,略。

  • 相关阅读:
    Anagram
    HDU 1205 吃糖果(鸽巢原理)
    Codeforces 1243D 0-1 MST(补图的连通图数量)
    Codeforces 1243C Tile Painting(素数)
    Codeforces 1243B2 Character Swap (Hard Version)
    Codeforces 1243B1 Character Swap (Easy Version)
    Codeforces 1243A Maximum Square
    Codeforces 1272E Nearest Opposite Parity(BFS)
    Codeforces 1272D Remove One Element
    Codeforces 1272C Yet Another Broken Keyboard
  • 原文地址:https://www.cnblogs.com/wangweiNB/p/4998650.html
Copyright © 2011-2022 走看看