• 第16 天 JavaWEB过滤器和监听器技术


    Day16 JavaWEB过滤器和监听器技术

    复习:

    1、大结果集分页mysql的实现,是使用那个关键字,从user表中取第一页的数据,长度为10,sql语句怎么写?

    2、分页查询的起始位置(startIndex)如何计算?

    3、分页数据中的尾页如何计算?

    4、分页Service的业务处理有那几个步骤?

    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 DemoFilter implements Filter{

     

        @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 response)

                  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 MyFilter implements Filter{

       

          @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);

              }

              //如果有数据,返回,数组中的第一个数据

              return values[0];

          }

            

          

      }

       

       

      注意:最后还有去掉原来设置编码的代码。

       

       

       

      1. 监听器介绍

    2. 什么是监听器

      生活中的例子:

       

      银行的自动门,班导

       

      监听器:监听事件源,根据事件源上发生事件,做出相应的处理。

       

       

       

    3. 监听机制相关概念

       

      事件源:发生事件的源头,监听器需要监听的对象。

      事件:事件源上发生的动作,监听器监听的内容。

      监听器:负责监听事件源的对象。

       

       

       

       

    4. web监听器介绍

    5. javaweb监听器介绍

      JavaWEB中的监听器主要监听JavaWEB中的request、session、ServletContext对象的各种变化。

      主要监听的任务:

      1. 监听request、ServletContext 、session对象的创建和销毁 (练习)
        1. ServletRequestListener、ServletContextListener、HttpSessionListener
      2. 监听request、session、ServletContext 对象存放的数据变化情况(练习)
        1. ServletContextAttributeListener 、HttpSessionAttributeListener 、ServletRequestAttributeListener
      3. 监听session中保存的JavaBean的状态
        1. HttpSessionBindingListener

       

       

    6. javaweb监听器创建步骤(示例:ServletRequestListener)

    7. 需要定义一个类实现对应的监听器接口

       

      ServletRequestListener定义(API截图):

       

       

      代码演示:

       

      package cn.itcast.listener;

       

      import javax.servlet.ServletRequestEvent;

      import javax.servlet.ServletRequestListener;

       

      public class MyServletRequestListener implements ServletRequestListener{

       

          @Override

          //监听request对象销毁的方法

          public void requestDestroyed(ServletRequestEvent sre) {

              System.out.println("MyServletRequestListener.....requestDestroyed....");

              

          }

       

          @Override

          //监听request对象初始化的方法

          public void requestInitialized(ServletRequestEvent sre) {

              System.out.println("MyServletRequestListener.....requestInitialized....");

          }

       

      }

       

       

       

    8. 配置监听器对象

       

       

       

       

      注意:当服务器加载项目的时候,会读取web.xml文件中listener标签,那么服务器会自动创建监听器对象,并且自动调用其方法

       

       

      监听器的小结:

      1. 创建一个类,实现监听器接口
      2. 在监听器对象的方法中,书写相关的代码
      3. 在web.xml中配置当前监听器。

       

    9. ServletContext创建销毁监听(ServletContextListener)

       

      ServletContextListener定义(API截图):

       

       

       

      代码演示:

      package cn.itcast.listener;

       

      import javax.servlet.ServletContextEvent;

      import javax.servlet.ServletContextListener;

       

      public class MyServletContextListener implements ServletContextListener{

       

          @Override

          public void contextInitialized(ServletContextEvent sce) {

              System.out.println("MyServletContextListener.....contextInitialized....");

              

          }

       

          @Override

          public void contextDestroyed(ServletContextEvent sce) {

              System.out.println("MyServletContextListener.....contextDestroyed....");

          }

       

      }

       

       

      监听器配置:

       

      <listener>

          <listener-class>cn.itcast.listener.MyServletContextListener</listener-class>

      </listener>

       

      监听servletcontext对象初始化截图:

       

       

      监听servletcontext对象销毁截图:

       

    10. 案例:定时任务演示

      需求:项目启动时,获取服务器时间(new Date()),每一秒钟更新一次,打印在控制台

       

      思路:

      1)监控项目的启动(使用ServletContextListener来监听ServletContext对象的初始化)

      1. 获取服务器时间:new Date();
      2. 每一秒更新一次:定时器Timer

      4)给定时器设置定时任务

       

      Timer:定时器

       

       

      timeTask:定时器的任务(类)

      firstTime:从什么时候开始执行,立即执行设置为:0

      period :间隔多少时间重复执行,毫秒值,1秒=1000毫秒

       

      TimerTask:定时器的任务(类)

       

      Run方法中应该写我们的定时任务:每一秒钟更新一次时间,打印在控制台上

       

       

       

      代码实现:

       

      package cn.itcast.listener;

       

      import java.util.Date;

      import java.util.Timer;

      import java.util.TimerTask;

       

      import javax.servlet.ServletContextEvent;

      import javax.servlet.ServletContextListener;

       

      /**

      * @author wjn

      * 1)    创建一个类,实现监听器接口

          2)    在监听器对象的方法中,书写相关的代码

          3)    在web.xml中配置当前监听器。

      */

      public class MyServletContextListener implements ServletContextListener{

       

          @Override

          public void contextInitialized(ServletContextEvent sce) {

              System.out.println("MyServletContextListener....contextInitialized...");

              //监控项目的启动(使用ServletContextListener来监听ServletContext对象的初始化)

              //2)    获取服务器时间:new Date();

              //3)    每一秒更新一次:定时器Timer

              //4) 给定时器设置定时任务

              

              //获取定时器

              Timer timer = new Timer();

              //调用定时器的设置定时任务的方法

              //firstTime 0:立即执行

              //period:间隔多长时间执行一次,1000

              timer.schedule(new TimerTask() {

                  

                  @Override

                  public void run() {

                      //在run方法中,书写,要执行的任务

                      //过时的方法一般不推荐使用,但是,过时的方法,jdk不会删除它的效果。

                      //当前显示时间,可以使用服务器中的时间——java代码,new Date();

                      //当前显示时间——javascript代码,new Date();

                      //javascript代码,是在浏览器运行,客户端的时间,一般是不使用客户端的时间

                      //业务:整点秒杀

                      //获取的是服务器时间,用户,是没有办法控制

                      //获取客户端时间,时间有客户控制,时间是不对的

                      //一般尊循的原则,只要可以控制在服务器的,绝对不给客户端

                      System.out.println(new Date().toLocaleString());

                  }

              }, 0, 1000);

              

          }

       

          @Override

          public void contextDestroyed(ServletContextEvent sce) {

              System.out.println("MyServletContextListener....contextDestroyed...");

          }

       

      }

       

      效果:

       

      1. HttpSessionListener对象监听session的创建与销毁监听

       

      HttpSessionListener定义(API截图):

       

       

      代码演示:

       

      package cn.itcast.listener;

       

      import javax.servlet.http.HttpSessionEvent;

      import javax.servlet.http.HttpSessionListener;

       

      public class MyHttpSessionListener implements HttpSessionListener{

       

          @Override

          public void sessionCreated(HttpSessionEvent se) {

              System.out.println("MyHttpSessionListener....sessionCreated....");

              

          }

       

          @Override

          public void sessionDestroyed(HttpSessionEvent se) {

              System.out.println("MyHttpSessionListener....sessionDestroyed....");

              

          }

       

      }

       

       

       

      配置文件:

       

      <listener>

              <listener-class>cn.itcast.listener.MyHttpSessionListener</listener-class>

          </listener>

       

      Invalidate.jsp页面代码:

       

      效果截图:

       

       

          

    11. 统计在线人数

       

      用户积累:优惠,折扣,广告,扫码关注,想所有QQ用推送一条消息,给所有支付宝用户发送消息。

       

      第三方登录,QQ账号,微博账号,微信账号,优酷账号,支付宝账号,银行账户,百度账号

       

      1. 用户体验非常好
      2. 创业公司,除了积累用户以外,还获取了用户的QQ或者支付宝,或者微信,可以使用现成推广渠道,再次推广自己应用

       

       

       

      需求:统计当前访问网站的人数有多少人?

       

       

      什么时候我们可以知道用户访问了网站?

      只要用户访问了我们的网站,session一定会创建。只要用户离开,点退出,session就销毁。

       

       

      思路:

      只要判断session创建,在线人数就加一

      只要判断session销毁,在线人数就减一

       

      在线人数的数据,要存在哪里?

       

      ServletContext对象中,所有应用程序范围都可以获取,所有访问当前网站的用户,都应该可以看到在线人数

       

      总思路:

      1)先在servletContext中初始化在线人数参数;当前项目初始化的时候,将在线人数初始化:0人。

      2)在监听器中只要判断session创建,在线人数就加一

      3)在监听器中只要判断session销毁,在线人数就减一

       

       

       

       

      代码实现:

      监听器代码:

       

      package cn.itcast.listener;

       

      import javax.servlet.ServletContext;

      import javax.servlet.http.HttpSessionEvent;

      import javax.servlet.http.HttpSessionListener;

       

      public class MyHttpSessionListener implements HttpSessionListener {

       

          @Override

          public void sessionCreated(HttpSessionEvent se) {

              System.out.println("MyHttpSessionListener....sessionCreated....");

              // 在监听器中只要判断session创建,在线人数就加一

       

              ServletContext context = se.getSession().getServletContext();

              // 获取里面的在线人数

              Integer onlineNum = (Integer) context.getAttribute("onlineNum");

              onlineNum = onlineNum + 1;

              context.setAttribute("onlineNum", onlineNum);

          }

       

          @Override

          public void sessionDestroyed(HttpSessionEvent se) {

              System.out.println("MyHttpSessionListener....sessionDestroyed....");

              // 在监听器中只要判断session销毁,在线人数就减去一

       

              ServletContext context = se.getSession().getServletContext();

              // 获取里面的在线人数

              Integer onlineNum = (Integer) context.getAttribute("onlineNum");

              onlineNum = onlineNum - 1;

              context.setAttribute("onlineNum", onlineNum);

       

          }

       

      }

       

       

       

       

       

       

      index.jsp显示在线人数,显示退出链接:

       

       

      <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

       

       

      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

      <html>

      <head>

       

      <title>My JSP 'index.jsp' starting page</title>

          <meta http-equiv="pragma" content="no-cache">

          <meta http-equiv="cache-control" content="no-cache">

          <meta http-equiv="expires" content="0">

          <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

          <meta http-equiv="description" content="This is my page">

          <!--

          <link rel="stylesheet" type="text/css" href="styles.css">

          -->

      </head>

       

      <body>

      itcast-filter2项目主页<br>

      当前在线人数:${onlineNum }

      <a href="${pageContext.request.contextPath }/validate.jsp">退出</a>

      </body>

      </html>

       

       

       

      页面效果:

       

       

    12. 属性变化的监听

    13. 属性监听器介绍

      主要是监听使用setAttribute、removeAttribute方法。

       

      ServletContextAttributeListener 专门用于监听ServletContext对象中的属性的变化情况

      HttpSessionAttributeListener 专门用于监听session对象中的属性的变化情况

      ServletRequestAttributeListener 专门用于监听request对象中的属性的变化情况

      它们中的的监听 添加 、删除 、 修改的方法名称全部一致:

       

       

       

      代码演示:

       

       

      Jsp:

      <%

              //添加数据

              session.setAttribute("addr", 111);

              //替换数据

              session.setAttribute("addr", 222);

              //删除数据

              session.removeAttribute("addr");

      %>

      监听器:

      package cn.itcast.listener;

       

      import javax.servlet.http.HttpSessionAttributeListener;

      import javax.servlet.http.HttpSessionBindingEvent;

       

      public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {

       

          @Override

          public void attributeAdded(HttpSessionBindingEvent se) {

              System.out.println("MyHttpSessionAttributeListener....attributeAdded...");

          }

       

          @Override

          public void attributeRemoved(HttpSessionBindingEvent se) {

              System.out.println("MyHttpSessionAttributeListener....attributeRemoved...");

          }

       

          @Override

          public void attributeReplaced(HttpSessionBindingEvent se) {

              System.out.println("MyHttpSessionAttributeListener....attributeReplaced...");

          }

       

      }

       

       

      配置文件:

       

      <listener>

              <listener-class>cn.itcast.listener.MyHttpSessionAttributeListener</listener-class>

          </listener>

    14. Bean监听演示

      1. Session中的bean监听

      当我们给Session中保存一个Java对象的时候,或者把Java对象从Session中移除的时候会触发专门用来监听Session中对象变化的监听器中的方法。拥有这个方法的对象——HttpSessionBindingListener接口

       

       

      属性监听和bean监听的区别:

       

      属性监听:是对三个容器中的任何属性(包括对象和不是对象的数据,基本类型数据)的变化,进行监听

      Bean监听:它只监听javabean对象往session中保存和session中移出的过程。

       

       

       

       

      由于HttpSessionBindingListener是用来监听某个JavaBean对象的绑定和解绑的,所以这个监听器的实现类必须是被操作的JavaBean(HttpSessionBindingListener不需要再web.xml中配置)

       

      javaBean:

       

       

       

      package cn.itcast.domain;

       

      import javax.servlet.http.HttpSessionBindingEvent;

      import javax.servlet.http.HttpSessionBindingListener;

       

      public class User implements HttpSessionBindingListener{

       

          private int age;

          private String name;

          public int getAge() {

              return age;

          }

          public void setAge(int age) {

              this.age = age;

          }

          public String getName() {

              return name;

          }

          public void setName(String name) {

              this.name = name;

          }

          @Override

          public String toString() {

              return "User [age=" + age + ", name=" + name + "]";

          }

          @Override

          public void valueBound(HttpSessionBindingEvent event) {

              System.out.println("User....valueBound...");

              

          }

          @Override

          public void valueUnbound(HttpSessionBindingEvent event) {

              System.out.println("User....valueUnbound...");

              

          }

          

      }

       

       

       

       

      JSP:

       

      <%

               session.setAttribute("user", new User());

            

           session.removeAttribute("user");

      %>

       

      效果:

       

      Bean监听需求:

       

      在线人数,根据session创建和销毁,来做人数的增减。

      在线会员统计:

      1. User类实现bean监听接口
      2. 每次监听到loginUser对象被绑定到session中的时候,会员人数加一
      3. 每次监听到loginUser对象被解绑的时候,会员人数减一

         

       

       

       

      1. 作业:

      1. 自动登录过滤器(40点积分)
      2. 定时任务(20点积分)
      3. 统计在线任务(进度20点积分)
      4. 全站乱码过滤器简单版(20点积分)
      5. 全站乱码过滤器复杂版(50点积分)

         

  • 相关阅读:
    Tomcat
    二叉树
    CDOJ 1962 天才钱vs学霸周2【最大流】
    次小生成树(POJ1679/CDOJ1959)
    CDOJ1927 爱吃瓜的伊卡洛斯(2) 【并查集】启发式合并+set
    HDU 1074 Doing Homework(DP状态压缩)
    uva 11367 (Dijkstra+DP)
    线段树模板
    openpose pytorch代码分析
    opencv图片坐标和数组下标
  • 原文地址:https://www.cnblogs.com/beyondcj/p/6270900.html
Copyright © 2020-2023  润新知