JavaWEB过滤器和监听器技术

Posted A小小高

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWEB过滤器和监听器技术相关的知识,希望对你有一定的参考价值。

 

  1. 过滤器介绍

 

    1. 什么是过滤器

生活中的例子:

 

滤水器,口罩,杯子上滤网,渔网

 

生活中的过滤器:留下我们想要的,排除,我们不想要的。

 

高考: 只有分数够高的同学才能进入理想的大学。有一部分同学被拦截在大学之外。(起到拦截的作用)

 

传智播客: 一开始大家都是小白,进入传智播客学习,经历了4个月的学习,毕业之后,具有了一定(月薪10000左右)的编码能力。

(对每一个经过的学员,都增强了学员的编码能力,起到了增强的作用)

 

JavaWeb中的过滤器的概念: 对请求和响应进行拦截或者增强的对象,就是过滤器。

 

JavaWeb中的过滤器是什么呢?

 

Filter接口:功能——对请求和响应进行增强,或者进行拦截。

 

 

  1. JavaWEB中的过滤器运行图解

 

 

 

  1. Filter的快速入门(重点:必须掌握)

 

    1. Filter定义以及创建步骤介绍

package cn.itcast.filter;

 

import java.io.IOException;

 

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

 

/**

* @author wjn

* 总结:过滤器书写步骤

* 第一:创建类实现接口——DemoFilter implements Filter

* 第二:过滤任务写在doFilter方法中

* 第三:web.xml中配置

*/

public class  

    @Override

    //销毁的方法

    public void destroy() {

    }

 

    @Override

    //执行过滤的方法

    public void doFilter(ServletRequest arg0, ServletResponse arg1,

            FilterChain arg2) throws IOException, ServletException {

        System.out.println("DemoFilter.....doFilter....");

        

    }

 

    @Override

    //初始化的方法

    public void init(FilterConfig arg0) throws ServletException {

    }

 

} 

Filter 是在 Web 应用程序的部署描述符中配置的——过滤器创建好之后,需要在web.xml中做配置

    1. 在web.xml文件中配置过滤器

       

       <filter>
      
          <filter-name>DemoFilter</filter-name>
      
          <filter-class>cn.itcast.filter.DemoFilter</filter-class>
      
      </filter>
      
       
      
      <filter-mapping>
      
          <filter-name>DemoFilter</filter-name>
      
          <url-pattern>/1.txt</url-pattern>
      
      </filter-mapping> 

       

      1. Filter拦截操作效果

       

      1. 过滤器放行的对象:FilterChain功能介绍

       

      FilterChain的doFilter方法

       

       

       

      代码实现

       

      过滤器放行执行过程:

       

       

       

      1. Filter生命周期

      为什么要学习生命周期?

      (servlet,只有知道servlet是在什么时候创建和什么时候销毁,才能知道,我在什么时候可以使用servlet)

      我需要知道servlet存活的时间,才能正确的使用servlet对象。

       

      对于过滤器,我们同样要知道,过滤器什么时候被创建,什么时候被销毁,我们才能正确的使用过滤器。

       

      1. Filter生命周期

      回顾servlet的生命周期:

      创建: 第一次被访问的时候

      销毁: 服务器关闭的时候,或者当前项目从服务器中移除

       

      回顾session的生命周期:

      创建: 第一次调用getsession方法

      销毁: 服务器非正常关闭,超过生存时间,调用销毁(自杀)的方法

      Filter:

      创建:在服务器启动的时候

       

      服务器启动截图:

       

      销毁: 在服务器关闭的时候,过滤器销毁。

       

      服务器关闭截图:

      1. FilterConfig介绍


      servletConfig对象:获取servlet相关的配置信息。

       

      FilterConfig定义:获取filter相关的配置信息。

       

      API介绍:

       

       

      API代码演示:

       

      1)设置过滤器初始化参数

      2)通过filterconfig对象来获取参数

      参数配置:

       

      效果演示:

       

       

       

      同学提问:filter是不是单例的?

       

      1. 类比servlet,我们通过什么来测试,servlet是单例的?

       

      测试单例的思路:

      1. 设置一个成员变量在过滤器中
      2. 发送两次请求,都去操作成员变量
      3. 如果前一次请求操作的结果,影响后一次请求获取到的成员变量,那么filter就是单例的,反之,不是单例。

       

       

      1. Filter配置详解(web.xml中的配置)

        1. 关于url-pattern配置

      过滤器如何匹配请求的路径?

       

      回顾servlet的url-pattern:

      全路径匹配——

          地址栏:localhost:8080/项目根路径/资源路径 localhost:8080/itcast-filter2/1.txt

      通配符的匹配——

          地址栏:localhost:8080/项目根路径/abc/*

       

      以上两种匹配方式,配置路径的时候必须以"/"开头

       

       

      后缀名匹配——/路径/*.do: *.do *.txt *.action

          地址栏:localhost:8080/项目根路径/*.txt

      后缀名匹配方式,配置路径的时候不能以"/"开头

       

      Filter的url-pattern配置与servlet一致。

       

       

      过滤器的执行顺序?

       

      测试方式:

       

      1. 两个过滤器,拦截同一个请求
      2. 调整两个过滤器的配置,再来看执行的顺序

       

      总结:

      过滤器执行的顺序是按照,web.xml中filter-mapping标签的书写顺序执行(从上往下执行)

       

      1. 关于servlet-name配置

      什么是servlet-name配置?

       

      定义:针对指定的servlet进行拦截或者增强操作的配置

       

      Servlet:

       

      package cn.itcast.web;
      
       
      
      import java.io.IOException;
      
       
      
      import javax.servlet.ServletException;
      
      import javax.servlet.http.HttpServlet;
      
      import javax.servlet.http.HttpServletRequest;
      
      import javax.servlet.http.HttpServletResponse;
      
       
      
      public class DemoServlet extends HttpServlet {
      
       
      
          public void doGet(HttpServletRequest request, HttpServletResponse response)
      
                  throws ServletException, IOException {
      
              System.out.println("DemoServlet.....执行.......");
      
          }
      
       
      
          public void doPost(HttpServletRequest request, HttpServletResponse             throws ServletException, IOException {
      
              doGet(request, response);
      
          }
      
       
      
      } 

       

      Filter:

       

      package cn.itcast.filter;
      
       
      
      import java.io.IOException;
      
      import java.util.Enumeration;
      
       
      
      import javax.servlet.Filter;
      
      import javax.servlet.FilterChain;
      
      import javax.servlet.FilterConfig;
      
      import javax.servlet.ServletException;
      
      import javax.servlet.ServletRequest;
      
      import javax.servlet.ServletResponse;
      
       
      
      /**
      
      * @author wjn
      
      * 1:定义一个类,实现javax.servlet.Filter;
      
      * 2:要进行拦截或者增强的代码,要写在doFilter方法中
      
      * 3:在web.xml中做配置
      
      */
      
      public class  
      
          @Override//初始化的方法
      
          public void init(FilterConfig config) throws ServletException {
      
              System.out.println("MyFilter....init....");
      
              //获取过滤器名称
      
              //选中要输出的内容,按住alt,点击两次右斜线
      
              System.out.println("FilterName:"+config.getFilterName());
      
              //获取指定的初始化参数
      
              String plane = config.getInitParameter("plane");
      
              System.out.println("plane:"+plane);
      
              
      
              String train = config.getInitParameter("train");
      
              System.out.println("train:"+train);
      
              
      
              //获取所有初始化参数的名称
      
              Enumeration<String> enumeration = config.getInitParameterNames();
      
              while(enumeration.hasMoreElements()){
      
                  System.out.println(enumeration.nextElement());
      
              }
      
              
      
          }
      
       
      
          @Override//执行过滤任务的方法
      
          public void doFilter(ServletRequest request, ServletResponse response,
      
                  FilterChain chain) throws IOException, ServletException {
      
              System.out.println("MyFilter.....doFilter.....");
      
              //chain:是放行请求和响应的对象
      
              chain.doFilter(request, response);
      
          }
      
       
      
          @Override//销毁的方法
      
          public void destroy() {
      
              System.out.println("MyFilter....destroy....");
      
          }
      
       
      
      } 

       

      Web.xml配置:

       

       

      怎么想公司里的老司机请教:

      1. 我现在在做一个什么功能。
      2. 现在出现了什么状况(报错,页面显示,什么都没有发生)
      3. 我预期的效果是什么(我的思路是什么)

       

       

      1. Filter案例--自动登录(重点:必须掌握)

       

      1. 分析

      自动登陆的功能需求?

       

      用户懒,不想输入用户名和密码,希望,访问网站,直接自动登陆

       

      用户的使用场景:

       

      用户点击网站,访问项目根路径的时候,启动自动登陆

       

      实现思路:

       

      1. 用户在第一次登陆网站,保存用户名和密码(使用Cookie技术)
      2. 第二次访问网站,先访问根路径,启动自动登陆的功能(使用过滤器技术,在请求到达项目根路径之前完成自动登陆)

       

       

      画图分析:

       

       

       

       

      工作的时候,自动登陆功能,设置一定要慎重。

      人人网,微博,论坛,贴吧,可以设置自动登录

       

      银行,企业内网,支付系统,安全系统(国家网络应用,交通信号灯等),慎重选择制作自动登陆

       

       

      自动登陆功能,本身就是不安全。

      数据保存在cookie中,都是保存在用户的个人电脑中。

       

       

       

       

      提供一个用户选择自动登录的选项,修改页面

       

       

       

      1. LoginServlet实现

       

      package cn.itcast.web;
      
       
      
      import java.io.IOException;
      
      import java.net.URLEncoder;
      
       
      
      import javax.servlet.ServletException;
      
      import javax.servlet.http.Cookie;
      
      import javax.servlet.http.HttpServlet;
      
      import javax.servlet.http.HttpServletRequest;
      
      import javax.servlet.http.HttpServletResponse;
      
       
      
      import cn.itcast.domain.User;
      
      import cn.itcast.service.UserService;
      
      import cn.itcast.service.impl.UserServiceImpl;
      
       
      
      public class LoginServlet extends HttpServlet {
      
       
      
          public void doGet(HttpServletRequest request, HttpServletResponse response)
      
                  throws ServletException, IOException {
      
              request.setCharacterEncoding("utf-8");
      
              //第一步:接受参数
      
              String username = request.getParameter("username");
      
              String pwd = request.getParameter("pwd");
      
              
      
              //第二步:调用service方法登录用户
      
              UserService userService = new UserServiceImpl();
      
              User loginUser = userService.login(username ,pwd);
      
              
      
              //第三步:接收返回值,根据不同返回值不同处理(User == null != null)
      
              if(loginUser == null){
      
                  request.setAttribute("msg", "用户名或者密码错误");
      
                  request.getRequestDispatcher("/login.jsp").forward(request, response);
      
                  return;
      
              }
      
              //登录成功
      
              
      
              //需求:在登录页面显示用户名
      
              /*
      
               * 第一步:登录成功之后,先记住用户名,通过cookie技术,通过response对象将cookie发送给浏览器
      
               *
      
               * 第二步:在登录页面解析cookie,使用EL表达式的内置对象(cookie),再使用javascript进行解码
      
               * */
      
              //=================================自动登录修改=========================
      
              String remember = request.getParameter("remember");
      
              if("on".equals(remember)){
      
                  //表示用户需要记住用户名和密码自动登录
      
                  Cookie c = new Cookie("username", URLEncoder.encode(loginUser.getName(), "utf-8"));
      
                  c.setMaxAge(60*60*24*7);
      
                  c.setPath("/");
      
                  response.addCookie(c);
      
                  
      
                  Cookie c2 = new Cookie("password",pwd );
      
                  c2.setMaxAge(60*60*24*7);
      
                  c2.setPath("/");
      
                  response.addCookie(c2);
      
              }else{
      
                  //用户不需要自动登录
      
                  Cookie c = new Cookie("username","");
      
                  c.setMaxAge(0);
      
                  c.setPath("/");
      
                  response.addCookie(c);
      
                  
      
                  Cookie c2 = new Cookie("password","" );
      
                  c2.setMaxAge(0);
      
                  c2.setPath("/");
      
                  response.addCookie(c2);
      
              }
      
              //=================================自动登录修改=========================
      
              
      
              request.getSession().setAttribute("loginUser", loginUser);
      
              //response.sendRedirect(request.getContextPath()+"/findAllContact");
      
              //response.sendRedirect(request.getContextPath()+"/queryPage?pageNum=1");
      
              response.sendRedirect(request.getContextPath()+"/queryPage2?pageNum=1");
      
          }
      
       
      
          public void doPost(HttpServletRequest request, HttpServletResponse response)
      
                  throws ServletException, IOException {
      
              doGet(request, response);
      
          }
      
       
      
      }
      
       

       

      1. 过滤器实现

        
      
      package cn.itcast.filter;
      
       
      
      import java.io.IOException;
      
      import java.net.URLDecoder;
      
       
      
      import javax.servlet.Filter;
      
      import javax.servlet.FilterChain;
      
      import javax.servlet.FilterConfig;
      
      import javax.servlet.ServletException;
      
      import javax.servlet.ServletRequest;
      
      import javax.servlet.ServletResponse;
      
      import javax.servlet.http.Cookie;
      
      import javax.servlet.http.HttpServletRequest;
      
      import javax.servlet.http.HttpServletResponse;
      
       
      
      import cn.itcast.domain.User;
      
      import cn.itcast.service.UserService;
      
      import cn.itcast.service.impl.UserServiceImpl;
      
       
      
      publicclass AutologinFilter implements Filter{
      
       
      
          @Override
      
          publicvoid destroy() {
      
          }
      
       
      
          @Override
      
          publicvoid doFilter(ServletRequest request, ServletResponse response,
      
                  FilterChain chain) throws IOException, ServletException {
      
              //第一步: 获取数据 (cookie username password)
      
              //HttpServletRequest?
      
              HttpServletRequest req = (HttpServletRequest)request;
      
              HttpServletResponse res = (HttpServletResponse)response;
      
              
      
              Cookie[] cookies = req.getCookies();
      
              if(cookies == null){
      
                  res.sendRedirect(req.getContextPath()+"/login.jsp");
      
                  return;
      
              }else{
      
                  //将cookie中的username和password
      
                  String username = "";
      
                  String password = "";
      
                  for (Cookie cookie : cookies) {
      
                      if("username".equals(cookie.getName())){
      
                          username = URLDecoder.decode(cookie.getValue(), "utf-8") ;
      
                      }
      
                      if("password".equals(cookie.getName())){
      
                          password = cookie.getValue();
      
                      }
      
                  }
      
                  if(username.equals("") || password.equals("")){
      
                      res.sendRedirect(req.getContextPath()+"/login.jsp");
      
                      return;
      
                  }else{
      
                      //第二步:调用方法(UserService.login())
      
                      UserService userService = new UserServiceImpl();
      
                      User loginUser = userService.login(username, password);
      
                      //第三步:根局不同返回值,不同处理
      
                      if(loginUser == null){
      
                          res.sendRedirect(req.getContextPath()+"/login.jsp");
      
                          return;
      
                      }else{
      
                          req.getSession().setAttribute("loginUser", loginUser);
      
                          res.sendRedirect(req.getContextPath()+"/queryPage2?pageNum=1");
      
                          return;
      
                      }
      
                  }
      
              }
      
          }
      
       
      
          @Override
      
          publicvoid init(FilterConfig arg0) throws ServletException {
      
          }
      
       
      
      } 

       


       

       

      web.xml配置:

       

      <!-- =======================过滤器配置=============================== -->
      
      <filter>
      
          <filter-name>AutologinFilter</filter-name>
      
          <filter-class>cn.itcast.filter.AutologinFilter</filter-class>
      
      </filter>
      
       
      
      <filter-mapping>
      
          <filter-name>AutologinFilter</filter-name>
      
          <!-- 因配置文件中默认的主页index.jsp,所访问根路径的时候,默认会跳转到主页上,所以,我们配置 url-pattern使用index.jsp -->
      
          <url-pattern>/index.jsp</url-pattern>
      
      </filter-mapping>
      
      <!-- =======================过滤器配置=============================== --> 
      1. 案例--解决day14_Contact项目中乱码

      需求:请求参数在每一个servlet中单独中文乱码处理,代码重复

       

       

      优化的思路,使用一个过滤器,在请求到达servlet之前,先对象request对象进行设置编码

       

      要对所有的请求都要进行设置编码,都要拦截,进行增强,url-pattern:/*

       

       

      过滤器代码:

       

      package cn.itcast.filter;
      
       
      
      import java.io.IOException;
      
       
      
      import javax.servlet.Filter;
      
      import javax.servlet.FilterChain;
      
      import javax.servlet.FilterConfig;
      
      import javax.servlet.ServletException;
      
      import javax.servlet.ServletRequest;
      
      import javax.servlet.ServletResponse;
      
      import javax.servlet.http.HttpServletRequest;
      
      import javax.servlet.http.HttpServletResponse;
      
       
      
      public class EncodingFilter implements Filter{
      
       
      
          @Override
      
          public void init(FilterConfig filterConfig) throws ServletException {
      
          }
      
       
      
          @Override
      
          public void doFilter(ServletRequest request, ServletResponse response,
      
                  FilterChain chain) throws IOException, ServletException {
      
              // 强制转换request response
      
              HttpServletRequest req = (HttpServletRequest)request;
      
              HttpServletResponse res = (HttpServletResponse)response;
      
              
      
              //处理响应乱码
      
              res.setContentType("text/html;charset=utf-8");
      
              //处理POST请求乱码
      
              req.setCharacterEncoding("utf-8");
      
              chain.doFilter(req, res);
      
              
      
          }
      
       
      
          @Override
      
          public void destroy() {
      
          }
      
       
      
      }

       

      Web.xml配置:

       

       

      补充(装饰(包装)设计模式口诀):

      1. 定义一个类,实现被装饰对象的接口
      2. 定义一个成员变量,记住被装饰对象的引用
      3. 定义构造方法,传入被装饰对象的实例
      4. 改写要修改的方法
      5. 不需要改写的方法,调用被装饰对象的原来的方法

       

      补充:什么时候使用装饰设计模式

       

      当我们需要对一个类进行增强的时候,增强后的类不再当前类的范畴(animal类型 cat dog都属于动物类型中可以使用继承,电子狗,不属于动物范围,所以选择使用包装设计模式 )中

       

      复杂过滤器实现:

       

      package cn.itcast.filter;
      
       
      
      import java.io.IOException;
      
       
      
      import javax.servlet.Filter;
      
      import javax.servlet.FilterChain;
      
      import javax.servlet.FilterConfig;
      
      import javax.servlet.ServletException;
      
      import javax.servlet.ServletRequest;
      
      import javax.servlet.ServletResponse;
      
      import javax.servlet.http.HttpServletRequest;
      
      import javax.servlet.http.HttpServletResponse;
      
       
      
      import cn.itcast.domain.MyRequest;
      
       
      
      public class EncodingFilter implements Filter{
      
       
      
          @Override
      
          public void init(FilterConfig filterConfig) throws ServletException {
      
          }
      
       
      
          @Override
      
          public void doFilter(ServletRequest request, ServletResponse response,
      
                  FilterChain chain) throws IOException, ServletException {
      
              // 强制转换request response
      
              HttpServletRequest req = (HttpServletRequest)request;
      
              HttpServletResponse res = (HttpServletResponse)response;
      
              
      
              //处理响应乱码
      
              res.setContentType("text/html;charset=utf-8");
      
              //自定义一个request对象:MyRequest,对服务器原来的request进行增强,使用装饰设计模式
      
              //要增强原来的request对象,必须先获取到原来的request对象
      
              MyRequest myrequest = new MyRequest(req);
      
              //注意:放行的时候应该,传入增强后的request对象
      
              chain.doFilter(myrequest, res);
      
              
      
          }
      
       
      
          @Override
      
          public void destroy() {
      
          }
      
       
      
      } 

       

      自定义增强类:

       

      package cn.itcast.domain;
      
       
      
      import java.io.UnsupportedEncodingException;
      
      import java.util.Map;
      
       
      
      import javax.servlet.http.HttpServletRequest;
      
      import javax.servlet.http.HttpServletRequestWrapper;
      
      //第一问题:HttpServletRequestWrapper他是什么?
      
      //HttpServletRequestWrapper:它实现了HttpServletRequest接口,继承当前对象之后,也是HttpServletRequest接口的实现类
      
      //第一问题:增强request,可以直接实现接口,为什么要继承HttpServletRequestWrapper?
      
      //因为HttpServletRequestWrapper,已经实现了接口的方法,我们只需继承就可以使用,
      
      //如果需要对某些方法增强,只需要修改部分方法即可,其他,调用父类的方法就完成了
      
       
      
      /**
      
      * 补充(装饰(包装)设计模式心法):
      
      1)    定义一个类,实现被装饰对象的接口
      
      2)    定义一个成员变量,记住被装饰对象的引用
      
      3)    定义构造方法,传入被装饰对象的实例
      
      4)    改写要修改的方法
      
      5)    不需要改写的方法,调用被装饰对象的原来的方法
      
       
      
      * */
      
      //1)    定义一个类,实现被装饰对象的接口
      
      public class MyRequest extends HttpServletRequestWrapper{
      
          //2)    定义一个成员变量,记住被装饰对象的引用
      
          private HttpServletRequest request = null;
      
          //3)    定义构造方法,传入被装饰对象的实例
      
          
      
          //设置一个标记,用来防止,编码多次运行,要保证get方式编码,只运行一次
      
          private boolean flag = false;
      
          public MyRequest(HttpServletRequest request) {
      
              super(request);
      
              this.request = request;
      
          }
      
       
      
          //4)    改写要修改的方法
      
          //所有获取参数的方法,都需要改写
      
          
      
          @Override
      
          public Map<String, String[]> getParameterMap() {
      
              //先判断请求的方式——每一次请求,只会有一种请求方式post get
      
              
      
              String method = this.request.getMethod();
      
              if("post".equalsIgnoreCase(method)){
      
                  //post请求方式
      
                  try {
      
                      this.request.setCharacterEncoding("utf-8");
      
                      return this.request.getParameterMap();
      
                  } catch (UnsupportedEncodingException e) {
      
                      e.printStackTrace();
      
                      return super.getParameterMap();
      
                  }
      
              }else if("get".equalsIgnoreCase(method)){
      
                  //先获取所有的数
      
                  Map<String, String[]> map = this.request.getParameterMap();
      
                  if(map == null){
      
                      return super.getParameterMap();
      
                  }
      
                  //如果flag是false,说明没有执行过,执行中文乱码处理
      
                  //如果flag是true,说明执行过乱码处理,不再重复
      
                  if(flag){
      
                      return map;
      
                  }
      
                  //遍历循环map集合,将每一个数据进行中文乱码处理
      
                  //循环map集合的时候,先获取所有key的Set集合,然后,根据key,获取value值
      
                  //当前循环结束,map集合中所有数据处理完成
      
                  for (String key : map.keySet()) {
      
                      //获取的数据是String数组
      
                      String[] value = map.get(key);
      
                      //当前for循环结束之后,value中的数据全部处理完成
      
                      for(int i = 0 ;i< value.length ;i++){
      
                          try {
      
                              String temp = new String(value[i].getBytes("iso-8859-1"),"utf-8");
      
                              //再存入原来的位置
      
                              value[i] = temp;
      
                          } catch (UnsupportedEncodingException e) {
      
                              e.printStackTrace();
      
                              //这里还在继续循环,所以不能return结束
      
                          }
      
                      }
      
                  }
      
                  //循环结束,标记设置为true
      
                  flag = true;
      
                  return map;
      
                  
      
              }else{
      
                  return super.getParameterMap();
      
              }
      
          }
      
          
      
          @Override
      
          public String[] getParameterValues(String name) {
      
              //先获取所有的数据,map
      
              Map<String, String[]> map = this.getParameterMap();
      
              if(map == null){
      
                  return super.getParameterValues(name);
      
              }
      
              //获取map集合中指定数据,根据name指定,相当于key
      
              String[] values = map.get(name);
      
              
      
              return values;
      
          }
      
          
      
          @Override
      
          public String getParameter(String name) {
      
              //获取指定请求参数的数组
      
              String[] values = this.getParameterValues(name);
      
              if(values == null){
      
                  return super.getParameter(name);
      
              }
      
              JavaWeb核心之Servlet

      javaWeb核心之servlet

      05-JavaWeb的三大组件:小程序Servlet+过滤器Filter+监听器Listener

      Java学习之Javaweb核心servlet

      JavaEE之JavaWeb核心之Servlet

      JavaWeb监听器和过滤器