Listener && Filter

来源:互联网 发布:修改默认ssh端口 编辑:程序博客网 时间:2024/06/06 00:07
一、Listener监听器
1、javaweb开发中的监听器,是用于监听web常见对象
2、HttpServletRequest HttpSession ServletContext
3、监听它们的创建与销毁,属性变化,session绑定javaBean
4、监听机制
     事件 就是一个事情
     事件源 产生这个事情的源头
     监听器 用于监听指定的事件的对象
     注册监听 要想让监听器可以监听到事件产生,必须对其进行注册
5、javaweb开发中常见监听器
  • 监听域对象的创建与销毁
    • 监听ServletContext创建与销毁 ServletContextListener
    • 监听HttpSession创建与销毁 HttpSessionListener
    • 监听HttpServletRequest创建与销毁 ServletRequestListener
  • 监听域对象的属性变化
    • 监听ServletContext属性变化 ServletContextAttributeListener
    • 监听HttpSession属性变化 HttpSessionAttributeListener
    • 监听HttpServletRequest属性变化 ServletRequestAttributeListener
  • 监听Session绑定javaBean
    • 它是用于监听javaBean对象是否绑定到了session域 HttpSessionBindingListener
    • 它是用于监听javaBean对象的活化与钝化 HttpSessionActivationListener (服务器停止后Session数据内否恢复)
6、监听器的快速入门
  • 关于创建一个监听器的步骤
    • 创建一个类,实现指定的监听器接口
    • 重写接口中的方法
    • 在web.xml文件中对监听器进行注册
7、关于域对象创建与销毁的演示
     1、ServletContext对象的创建与销毁
     这个对象是在服务器启动时创建的,在服务器关闭时销毁的
<listener>
            <listener-class>com.itheima.listener.MyServletContextListener</listener-class>
      </listener>
publicclassMyServletContextListenerimplementsServletContextListener{
      publicvoidcontextInitialized(ServletContextEventsce) {
            System.out.println("ServletContext对象创建了");
      }
      publicvoidcontextDestroyed(ServletContextEventsce) {
            System.out.println("ServletContext对象销毁了");
            
      }
}
     2、HttpSession对象的创建与销毁
     HttpSession session = request.getSession();
     Session 销毁:
          1、默认超时 30分钟
          2、关闭服务器
          3、invalidate()方法
          4、setMaxInactiveInterval(int interval) 可以设置超时时间
     问题:直接访问一个jsp页面时,是否会创建session?
     会创建,因为我们默认情况下时可以在jsp页面中直接使用session内置对象的
<listener>
            <listener-class>com.itheima.listener.MyHttpSessionListener</listener-class>
      </listener>
publicclassMyHttpSessionListenerimplementsHttpSessionListener {
      publicvoidsessionCreated(HttpSessionEventse) {
            System.out.println("HttpSession对象创建了");
      }
      publicvoidsessionDestroyed(HttpSessionEventse) {
            System.out.println("HttpSession对象销毁了");
      }
}
     3、HttpServletRequest创建与销毁
     Request对象是发送请求服务器就会创建它,当响应产生时,request对象就会销毁
<listener>
            <listener-class>com.itheima.listener.MyServletRequestListener</listener-class>
      </listener>
publicclassMyServletRequestListenerimplementsServletRequestListener {
      publicvoidrequestDestroyed(ServletRequestEventsre) {
            System.out.println("ServletRequest销毁了");
      }
      publicvoidrequestInitialized(ServletRequestEventsre) {
            System.out.println("ServletRequest创建 了");
      }
}
8、演示Request域对象中属性变化
     在java的监听机制中,它的监听器中的方法都是有参数的,参数就是事件对象,而我们可以通过事件对象直接获取事件源。
publicclassMyServletRequestListenerimplements
            ServletRequestAttributeListener {
      publicvoidattributeAdded(ServletRequestAttributeEventsrae) {
            System.out.println("ServletRequest添加属性了");
      }
      publicvoidattributeRemoved(ServletRequestAttributeEventsrae) {
            System.out.println("ServletRequest移除属性了");
      }
      publicvoidattributeReplaced(ServletRequestAttributeEventsrae) {//参数代表事件源对象
            System.out.println("ServletRequest替换属性了");
           System.out.println(srae.getName()+"\t"+srae.getValue());
            
      }
}
9、演示session绑定javaBean
     1、javaBean对象自动感知被绑定到session中
     HttpSessionBindingListener 这个接口是由javaBean实现的,并且不需要在web.xml文件中注册
publicclassUserimplementsSerializable, HttpSessionBindingListener{
      privateStringname;
      privateintage;
publicvoidvalueBound(HttpSessionBindingEventevent) {
            System.out.println("user对象被绑定了");
      }
      publicvoidvalueUnbound(HttpSessionBindingEventevent) {
            System.out.println("user对象解除被绑定了");
      }
      
      
}
     2、javabean对象可以活化或钝化到session中
     HttpSessionActivationListener 如果javaBean实现了这个接口,那么当我们正常关闭服务器时,session中javaBean对象就回被钝化到我们指定的文件中。当下一次再启动服务器,因为我们已经将对象写入到文件中,这是就会自动将javaBean对象活化到session中
 <%
      //session.invalidate();//使session销毁
      /*request.setAttribute("name", "tom");
      request.setAttribute("name", "jerry");
      request.removeAttribute("name"); */
      
      session.setAttribute("u",newUser());
      session.removeAttribute("u");
 %>

     我们还需要个context.xml文件来配置钝化时存储的文件
     在meta-inf目录下创建一个context.xml文件
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="it315"/>
                                   </Manager>
</Context>
10、定时销毁session
     1、怎样可以将每一个创建的session全都保存起来?
     我们可以做一个HttpSessionListener,当session对象创建时,就将这个session对象装入到一个集合中
     将集合List<HttpSession>保存到ServletContext域中
     2、怎么样可以判断session过期了?
     在HttpSession中有一个方法public long getLastAccessedTime()
     它可以得到session对象最后使用的时间
     可以使用invalidate方法销毁
     我们上面的操作需要使用任务调度功能
     在java中有一个Timer定时器类
publicclassTestTimer {
      publicstaticvoidmain(String[]args) {
            //创建一个计时器对象
            Timert= new Timer();
            
            //调度任务
            t.schedule(newTimerTask() {//要执行的任务
                  
                  @Override
                  publicvoidrun() {
                              System.out.println(newDate().toLocaleString());
                  }
            }, 2000, 1000); //2000 执行任务前的延迟时间  1000 执行各后续任务之间的时间间隔
            
      }
}
    程序在使用时,需要考虑并发问题,因为我们在web中,它一定是一个多线程的,那么我们的程序对集合进行了添加,还有移除操作。
publicclassMyServletContextListenerimplementsServletContextListener {
      publicvoidcontextInitialized(ServletContextEventsce) {
            //通过事件源对象得到事件源(ServletContext)
            ServletContextapplication= sce.getServletContext();
            //创建一个集合用于存储所有session对象
            finalList<HttpSession>list= Collections.synchronizedList(newArrayList<HttpSession>());
            
            //把集合放到application域中
            application.setAttribute("sessions",list);
            
            //创建一个计时器对象
            Timert= new Timer();
            
            t.schedule(newTimerTask() {
                  
                  @Override
                  publicvoidrun() {
                        System.out.println("开始扫描了。。。");
                        for(Iteratoriterator= list.iterator();iterator.hasNext();) {
                              HttpSessionsession= (HttpSession)iterator.next();
                              longl= System.currentTimeMillis()-session.getLastAccessedTime();
                              if(l>5000){//如果时间大于5秒,把session销毁
                                    System.out.println("session移除了"+session.getId());
                                    session.invalidate();//把session销毁
                                    //list.remove(session);//从集合中移除
                                    iterator.remove();
                              }
                              
                        }
                        /*for (HttpSession session : list) {
                              long l = System.currentTimeMillis()-session.getLastAccessedTime();
                              if(l>5000){//如果时间大于5秒,把session销毁
                                    session.invalidate();//把session销毁
                                    list.remove(session);//从集合中移除
                              }
                        }*/
                  }
            }, 2000, 5000);//延迟2秒后执行,每间隔5秒执行一次
      }
      publicvoidcontextDestroyed(ServletContextEventsce) {
      }
}
publicclassMySessionListenerimplementsHttpSessionListener {
      publicvoidsessionCreated(HttpSessionEventse) {
            HttpSessionsession= se.getSession();
            //得到application对象中的list集合
            ServletContextapplication= session.getServletContext();
            //得到session对象,并放入到list集合中
            List<HttpSession>list= (List<HttpSession>) application.getAttribute("sessions");
            
            list.add(session);
            System.out.println("添加了"+session.getId());
      }
      publicvoidsessionDestroyed(HttpSessionEventse) {
            //TODOAuto-generated method stub
      }
}
二、Filter过滤器(重要)
1、javaweb中的过滤器可以拦截所有访问web资源的请求或响应操作
2、Filter快速入门
  • 步骤
    • 创建一个类实现Filter接口
    • 重写接口中方法,doFilter方法是真正过滤的
    • 在web.xml文件中配置
    • 注意:在Filter的doFilter方法内如果没有执行chain.doFilter(request,response)那么资源是不会被访问到的
publicclassMyFilterimplementsFilter{
      publicMyFilter(){
            System.out.println("MyFilter实例化了");
      }
      publicvoidinit(FilterConfigfilterConfig)throwsServletException {
            System.out.println("MyFilter初始化了");
            
      }
      publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,
                  FilterChainchain)throwsIOException, ServletException {
            System.out.println("MyFilter1拦截开始了");
            
            //放行
            chain.doFilter(request,response);
            
           System.out.println("拦截结束了");
      }
      publicvoiddestroy() {
            System.out.println("MyFilter销毁了");
      }
}
<filter>
      <filter-name>MyFilter</filter-name>
      <filter-class>com.itheima.filter.MyFilter</filter-class>
<filter>
<filter-mapping>
      <filter-name>MyFilter</filter-name>
      <url-pattern>/*</url-pattern>
</filter-mapping>
  • FilterChain
    • FilterChain是servlet容器为开发人员提供的对象,它提供了对某一资源的已过滤请求调用链的视图。过滤器使用FilterChain调用链中的下一个过滤器,如果调用的过滤器是链中的最后一个过滤器,则调用链末尾的资源。
    • 问题:怎么样可以形成一个Filter链?只要多个Filter对同一资源进行拦截就可以形成Filter链
    • 问题:怎样确定Filter的执行顺序?由<filter-mapping>来确定
  • Filter生命周期
    • Servlet生命周期:实例化、初始化、服务、销毁
    • Filter生命周期:
      • 当服务器启动,会创建Filter对象,并调用init方法,只调用一次
      • 当访问资源时,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,这个方法是真正拦截操作的方法
      • 当服务器关闭时,会调用Filter的destroy方法来进行销毁操作
  • FilterConfig
    • 在Filter的init方法上有一个参数,类型就是FilterConfig
    • FilterConfig它是Filter的配置对象,它可以完成下列功能
      • 获取Filter名称
      • 获取Filter初始化参数
      • 获取ServletContext对象
      • String getFilterName()
      • String getInitParameter(String name)
      • Enumeration getInitParameterNames()
      • ServletContext getServletContext()
    • 怎样在Filter中获取一个FilterConfig对象
    • publicclassMyFilterConfigTestimplementsFilter{
            privateFilterConfigfilterConfig;
            publicvoidinit(FilterConfigfilterConfig)throwsServletException {
                  this.filterConfig= filterConfig;
            }
            publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,
                        FilterChainchain)throwsIOException, ServletException {
                  //通过FilterConfig对象获取到配置文件中的初始化信息
                  Stringencoding= filterConfig.getInitParameter("encoding");
                  System.out.println(encoding);
                  request.setCharacterEncoding(encoding);
                  //放行
                  chain.doFilter(request,response);
            }
            publicvoiddestroy() {
                  //TODOAuto-generated method stub
                  
            }
      }
    • <filter>
            <filter-name>MyFilterConfigTest</filter-name>
            <filter-class>com.itheima.filter.MyFilterConfigTest</filter-class>
            <init-param>
                  <param-name>encoding</param-name>
                  <param-value>UTF-8</param-value>
            </init-param>
            
      </filter>
      <filter-mapping>
            <filter-name>MyFilterConfigTest</filter-name>
            <servlet-name>ServletDemo2</servlet-name>
      </filter-mapping>
  • Filter配置
    • 基本配置
    • <filter>
            <filter-name>filter名称</filter-name>
            <filter-class>Filter类的包名.类名</filter-class>
      </filter> 
    • <filter-mapping>
            <filter-name>filter名称</filter-name>
            <url-pattern>路径</url-pattern>
      </filter-mapping>
    • 其他配置
          1、<url-pattern>
               完全匹配 以"/demo1"开始,不包含通配符*
               目录匹配 以"/"开始 以*结束
               扩展名匹配 *.xxx 不能写成/*.xxx
          2、<servlet-name>
               它是对指定的servlet名称的servlet进行拦截的
          3、<dispatcher>
               可以取的值有 REQUEST FORWARD ERROR INCLUDE
               它的作用是:当以什么方式去访问web资源时,进行拦截操作
               1、REQUEST 当是从浏览器直接访问资源,或是重定向到某个资源时进行拦截方式配置的,它也是默认值
               2、FORWARD 它描述的是请求转发的拦截方式配置
               3、ERROR 如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用,除此以外,过滤器不会被调用
               4、INCLUDE 如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用,除此以外,过滤器不会被调用
三、自动登录
1、创建库与表
     create database day17
     use day17
     create table user{
          id int primary key auto_increment
          username varchar(100)
          password varchar(100)
     }
     insert into user values(null,"tom","123");
2、自动登录功能实现
     1、当用户登录成功后,判断是否勾选了自动登录,如果勾选了,就将用户名与密码持久化存储到cookie中
     2、做一个Filter,对需要自动登录的资源进行拦截
3、问题
     1、如果用户想要登录操作,还需要自动登录吗?
     2、如果用户已经登陆了,还需要自动登录吗?
4、AutoFilter.java
publicclassAutoLoginFilterimplementsFilter {
      publicvoidinit(FilterConfigfilterConfig)throwsServletException {
            //TODOAuto-generated method stub
      }
      publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,
                  FilterChainchain)throwsIOException, ServletException {
            // 1、转换两个对象HttpServletRequest,HttpServletResponse
            HttpServletRequestreq= (HttpServletRequest)request;
            HttpServletResponseresp= (HttpServletResponse)response;
            Stringuri= req.getRequestURI();// /day17_02_autologin/login.jsp
            Stringpath= req.getContextPath();// /day17_02_autologin
            path= uri.substring(path.length());// /login.jsp
            //如果请求的资源不是login.jsp,也不是/servlet/loginServlet,才往下执行
            if(!("/login.jsp".equals(path) || "/servlet/loginServlet".equals(path))) {
                  Useruser= (User)req.getSession().getAttribute("user");
                  //如果session得到了user对象,说明已经登录过或自动登录过。
                  //那么请求下一个资源时就不用执行自动登录了。
                  //用户没有登录过,我们才执行自动登录
                  if(user== null) {
                        System.out.println("aaaaaaaaaaaaaaa");
                        // 2、处理业务
                        // 得到cookies数组
                        Cookie[]cookies= req.getCookies();
                        Stringusername= "";
                        Stringpassword= "";
                        // 从数组中找到想要的user对象的信息
                        for(inti= 0;cookies!= null && i <cookies.length;i++) {
                              if("user".equals(cookies[i].getName())) {
                                    Stringvalue= cookies[i].getValue();// tom&123
                                    String[]values= value.split("&");
                                    username= values[0];
                                    password= values[1];
                              }
                        }
                        // 登录操作
                        UserServiceus= new UserService();
                        Useru= us.findUser(username,password);
                        // 如果登录成功,把用户信息存到session中
                        if(u!= null) {
                              req.getSession().setAttribute("user",u);
                        }
                  }
            }
            // 3、放行
            chain.doFilter(request,response);
      }
      publicvoiddestroy() {
            //TODOAuto-generated method stub
      }
}
5、AutoLoginServlet.java
publicclassLoginServletextendsHttpServlet {
      publicvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse)
                  throwsServletException, IOException {
            
            Stringusername= request.getParameter("username");
            Stringpassword= request.getParameter("password");
            //MD5加密
            password= MD5Utils.md5(password);
            UserServiceus= new UserService();
            Useruser= us.findUser(username,password);
            
            if(user!=null){
                  Stringautologin= request.getParameter("autologin");
                  Cookiecookie= new Cookie("user",user.getUsername()+"&"+user.getPassword());
                  cookie.setPath("/");
                  if(autologin!=null){//要把用户信息保存到cookie中
                        cookie.setMaxAge(60*60*24*7);
                  }else{//要清除cookie对象的数据
                        cookie.setMaxAge(0);
                  }
                  response.addCookie(cookie);//把cookie对象保存到客户端
                  
                  request.getSession().setAttribute("user",user);
                  request.getRequestDispatcher("/home.jsp").forward(request,response);
            }else{
                  request.setAttribute("msg","用户名或密码错误,请重新登录!");
                  request.getRequestDispatcher("/login.jsp").forward(request,response);
            }
            
      }
      publicvoiddoPost(HttpServletRequestrequest, HttpServletResponseresponse)
                  throwsServletException, IOException {
            doGet(request,response);
      }
}
四、MD5加密
1、在mysql中可以对数据进行md5加密
   md5(字段)
   update user set password = md5(password);
2、在java中也提供了md5加密
     
publicclassMD5Utils {
      /**
       * 使用md5的算法进行加密
       */
      publicstaticString md5(StringplainText) {
            byte[]secretBytes= null;
            try{
                  secretBytes= MessageDigest.getInstance("md5").digest(
                              plainText.getBytes());
            }catch(NoSuchAlgorithmExceptione) {
                  thrownewRuntimeException("没有md5这个算法!");
            }
            Stringmd5code= new BigInteger(1, secretBytes).toString(16);
            for(inti= 0;i< 32 -md5code.length();i++) {
                  md5code= "0" + md5code;
            }
            returnmd5code;
      }
}
五、全局的编码过滤器
1、分析:我们之前做的操作,只能对post请求是满足的
    req.setCharacterEncoding("utf-8");//只对post方式满足
2、怎么可以做成一个通用的,可以处理post,get所有的请求的?
   在java中怎样可以对一个方法进行功能增强?
     1、继承
     2、装饰设计模式
          1、创建一个类让它与被装饰类实现同一个接口或继承同一个父类
          2、在装饰类中持有一个被装饰类的引用
          3、重写要增强的方法
     问题:我们获取请求参数有以下方法:
          1、getParameter
          2、getParameterValues
          3、getParameterMap
     这三个方法都可以获取请求参数
     分析后,我们知道getParameter与getParameterValue方法可以依赖于getParamterMap方法来实现
3、
// 实现与被包装对象相同的接口
// 定义一个与被包装类相对象的引用
// 定义一个构造方法,把被包装对象传过来
// 对于不需要改写方法,直接调用
// 对于无需要改写方法,写自己的方法体
classMyRequestextendsHttpServletRequestWrapper {
      HttpServletRequestrequest;
      publicMyRequest(HttpServletRequestrequest) {
            super(request);
            this.request= request;
      }
      /*
       * @Override public String getParameter(String name) { name =
       * request.getParameter(name);//乱码 try { return new
       * String(name.getBytes("iso-8859-1"),"UTF-8"); } catch
       * (UnsupportedEncodingException e) { e.printStackTrace(); } return null; }
       */
      @Override
      publicString getParameter(Stringname) {
            Map<String, String[]>map= getParameterMap();
            returnmap.get(name)[0];
      }
      @Override
      publicString[] getParameterValues(Stringname) {
            Map<String, String[]>map= getParameterMap();
            returnmap.get(name);
      }
      privatebooleanflag= true;
      @Override
      publicMap<String, String[]> getParameterMap() {
            Map<String, String[]>map= request.getParameterMap();// 乱码
            if(flag) {
                  for(Map.Entry<String, String[]>m: map.entrySet()) {
                        String[]values= m.getValue();
                        for(inti= 0;i< values.length;i++) {
                              try{
                                    values[i] = newString(
                                                values[i].getBytes("iso-8859-1"),"UTF-8");
                              }catch(UnsupportedEncodingExceptione) {
                                    e.printStackTrace();
                              }
                        }
                  }
                  flag= false;
            }
            returnmap;
      }
}
4、过滤器
publicclassMyFilterimplementsFilter {
      publicvoidinit(FilterConfigfilterConfig)throwsServletException {
      }
      publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,
                  FilterChainchain)throwsIOException, ServletException {
            HttpServletRequestreq= (HttpServletRequest)request;
            // 解决post方式
            // req.setCharacterEncoding("UTF-8");
            req= new MyRequest(req);
            chain.doFilter(req,response);
      }
      publicvoiddestroy() {
      }
}
0 0