zoukankan      html  css  js  c++  java
  • Listener&Filter

    Listener&Filter

    1.Listener

    监听器,用于监听某一个事件的发生。

    监听器的内部机制:接口回调。

    1.1接口回调

    需求:

    A类执行循环,当循环次数为5时,通知B。

    • 传统做法

      传递B的实例给A。

    public class A {
        public static void loop(){
            for(int i=0;i<10;i++){
                if(i==5){
                    B b=new B();
                    b.print();
                }
            }
        }
    }
    
    public class B {
        public void print(){
            System.out.println("A循环了5次,通知到B");
        }
    }
    
    public class Test1 {
        public static void main(String[] args) {
            A a=new A();
            a.loop();
        }
    }
    
    • 接口回调做法

      传递一个接口PrintListener给A,B实现了该接口,因为A可能在B之前就写好了,此时A并不知道有B的存在,也就更无法直接接收B的实例了,所以可以利用接口回调解决。

    public class A {
        public static void loop(PrintListener printListener){
            for(int i=0;i<10;i++){
                if(i==5){
                    printListener.print();
                }
            }
        }
    }
    
    public class B implements PrintListener{
        public void print(){
            System.out.println("A循环了5次,通知到B");
        }
    }
    
    public interface PrintListener {
        public void print();
    }
    
    public class Test1 {
        public static void main(String[] args) {
            A a=new A();
            a.loop(new B());//A中的loop方法接收的是PrintListener,而这里可以传递PrintListener的实现类的实例对象,这是多态的体现。
        }
    }
    

    1.2Web监听器

    总共有8个,分为三种类型。

    使用步骤都一致:

    1. 定义一个类,实现监听器接口
    2. 注册/配置监听器

    1.2.1监听作用域的创建和销毁

    作用域共有4个:page,request,session,application,监听作用域的创建和销毁是监听request,session,application三个作用域的创建和销毁。

    • ServletRequestListener

    监听request作用域对象的创建和销毁。

    request对应类型为HttpServletRequest。

    reqeust创建:访问服务器上的任意资源时,如html,jsp,servlet;

    request销毁:服务器已经对这次请求做出了响应后。

    @WebListener//注册监听器,相当于在web.xml中配置的那一段
    public class MyServletRequestListener implements ServletRequestListener {
    
        @Override
        public void requestDestroyed(ServletRequestEvent sre) {
            System.out.println("request销毁了");
        }
    
        @Override
        public void requestInitialized(ServletRequestEvent sre) {
            System.out.println("request初始化了");
        }
    }
    

    在web.xml中注册监听器:

    <listener>
            <listener-class>com.itheima.listener.MyServletRequestListener</listener-class>
    </listener>
    
    • ServletContextListener

    监听application作用域对象的创建和销毁。

    application对应类型为ServletContext。

    ServletContext创建:服务器启动时;

    ServletContext销毁:正常关闭服务器。

    作用:完成初始化工作,执行自定义任务调度。

    @WebListener
    public class MyServletContextListener implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            System.out.println("servletContext初始化了");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("servletContext销毁了");
        }
    
    • HttpSessionListener

    监听session作用域对象的创建和销毁。

    session对应类型为HttpSession。

    session创建:调用request.getSession(),jsp中默认创建了session;

    session销毁:关闭服务器(包括正常和非正常);Session会话时间过期,默认是30分钟。

    作用:可以统计在线人数。

    @WebListener
    public class MyHttpSessionListener implements HttpSessionListener {
        @Override
        public void sessionCreated(HttpSessionEvent se) {
            System.out.println("session创建了");
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            System.out.println("session销毁了");
        }
    }
    

    1.2.2监听作用域属性状态变更

    监听在servletContext,request,session作用域中属性的添加,替换,移除动作。

    • ServletContextAttributeListener

    @WebListener
    public class MyServletContextAttributeListener implements ServletContextAttributeListener {
        @Override
        public void attributeAdded(ServletContextAttributeEvent scae) {
            System.out.println("servletContext属性添加了");
        }
    
        @Override
        public void attributeRemoved(ServletContextAttributeEvent scae) {
            System.out.println("servletContext属性移除了");
        }
    
        @Override
        public void attributeReplaced(ServletContextAttributeEvent scae) {
            System.out.println("servletContext属性替换了");
        }
    }
    
    <body>
        <%
            //添加name属性
            application.setAttribute("name","zhangsan");
            //替换name属性
            application.setAttribute("name","wanger");
            //移除name属性
            application.removeAttribute("name");
        %>
    </body>
    
    • ServletRequestAttributeListener

    • HttpSessionAttributeListener

    1.2.3监听HttpSession里存值的状态的变更

    此类监听器无须注册。

    • HttpSessionBindingListener

    监听对象与session绑定和解除绑定的动作,此对象要实现HttpSessionBindingListener。

    public class Student implements HttpSessionBindingListener {
        private int id;
        private String name;
        @Override
        public void valueBound(HttpSessionBindingEvent event) {
            System.out.println("Student对象被绑定到session了");
        }
    
        @Override
        public void valueUnbound(HttpSessionBindingEvent event) {
            System.out.println("Student对象从session中解除绑定了");
        }
    	...
    }
    
    <%
            session.setAttribute("obj1",new Student(1,"小王"));
            session.removeAttribute("obj1");
    %>
    
    • HttpSessionActivationListener

    用于监听现在session的值是钝化(序列化)还是活化(反序列化)的动作。

    钝化:把内存中的数据存储到硬盘上;

    活化:把硬盘中的数据读取到内存中。

    钝化活化作用:session中的值可能会很多,并且可能很长一段时间不使用这个内存中的值,那么可以考虑把session的值可以存储到硬盘上【钝化】,等下一次使用时,再从硬盘上提取出来【活化】。

    1. Student2.java
    public class Student2 implements HttpSessionActivationListener, Serializable {
        private int id;
        private String name;
    
        @Override
        public void sessionWillPassivate(HttpSessionEvent se) {
            System.out.println("session被钝化了");
        }
    
        @Override
        public void sessionDidActivate(HttpSessionEvent se) {
            System.out.println("session被活化了");
        }
       ...
    }
    
    1. index2.jsp

      index2.jsp将Student2存入到session,然后正常关闭服务器,session 将被钝化。

    <%
        //存入到session
        session.setAttribute("obj2",new Student2(1,"coco"));
    %>
    
    1. index3.jsp

      重启服务器后,session将被活化,此时访问index3.jsp可以取到值。

    <%--取值--%>
    ${obj2.name}
    
    • 配置钝化活化

    配置让session在一定时间内钝化。

    三种方式:

    1. 在tomcat的conf/context.xml里面配置;

    对所有的运行在这个服务器的项目生效。

    1. 在conf/Catalina/localhost/context.xml配置;

    对localhost生效。 localhost:8080

    1. 在自己的web工程项目中的 META-INF/context.xml配置;

    只对当前的工程生效。

    maxIdleSwap:1分钟不用就钝化
    directory:钝化后的那个文件存放的目录位置。

    D: omcatapache-tomcat-7.0.52workCatalinalocalhostListenerDemoitheima

    ​ //itheima为相对路径,存放到了D: omcatapache-tomcat-7.0.52workCatalinalocalhostListenerDemoitheima


    2.Filter

    过滤器,其实就是对客户端发出来的请求进行过滤,起到拦截作用。

    作用:过滤敏感词汇;统一设置编码;自动登录等。

    2.1如何使用Filter

    1. 定义一个类,实现Filter(注意是javax.servlet.Filter)
    @WebFilter(filterName = "FilterDemo1",urlPatterns = "/*")//可简写成下面这行
    //@WebFilter("/*")
    public class FilterDemo1 implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("过滤器1初始化了");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("来到了过滤器1");
            //放行,请求会到达下一个目标
      		filterChain.doFilter(servletRequest,servletResponse);
        }
    
        @Override
        public void destroy() {
            System.out.println("过滤器1被销毁了");
        }
    }
    
    1. 注册过滤器

    两种注册方式:在web.xml中注册,或在类上用注解注册,见上。

    <filter>
        <filter-name>FilterDemo1</filter-name>
        <filter-class>com.itheima.Filter.FilterDemo1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterDemo1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    2.2Filter的生命周期

    • 创建

    在服务器启动时就创建。

    • 销毁

    在服务器关闭时就销毁。

    2.3Filter的执行顺序

    1. 客户端发出请求,先经过过滤器,如果过滤器放行,那么才能到servlet;
    2. 如果有多个过滤器,请求过来时,会按照在web.xml中注册的映射顺序()依次通过,只要其中任意一个不放行,那么后面的过滤器及servlet都不会收到请求,服务器响应回去时也会依次倒着经过过滤器。

    2.4Filter细节

    1. init方法中的FilterConfig参数可以用于获取Filter注册的名字及初始化参数,与ServletConfig类似;

    2. Filter的拦截路径,写法与servlet的一样:

      • 全路径匹配,以/开始

        如/LoginServlet

      • 目录匹配,以/开始,以*结束

        /demo01/*

      • 后缀名匹配,以*开始,以后缀名结束

        .jsp,.html,*.do等

    3. 拦截规则也可针对dispatcher设置

      filter-mapping>
          <filter-name>FilterDemo1</filter-name>
          <dispatcher>REQUEST</dispatcher>
      	<!--只要是请求过来都拦截,默认就是REQUEST-->
          <dispatcher>FORWARD</dispatcher>
      	<!--只要是转发都拦截-->
          <dispatcher>ERROR</dispatcher>
      	<!--只要是页面出错跳转时就拦截-->
          <dispatcher>INCLUDE</dispatcher>
      	<!--包含页面时就拦截-->
      </filter-mapping>
      

    2.5自动登录案例

    访问login.jsp页面不拦截,访问index2.jsp拦截,依次判断session和cookie,实现自动登录。

    • login.jsp
    <form action="LoginServlet" method="post" >
            账号:<input type="text" name="username"><br/>
            密码:<input type="text" name="password"><br/>
            <input type="checkbox" name="autoLogin">自动登录<br/>
            <input type="submit" value="登录">
    </form>
    
    • LoginServlet
    @WebServlet("/LoginServlet")
    public class LoginServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            UserDao userDao=new UserDaoImpl();
            User user = userDao.loginCheck(username, password);
            if(user!=null){
                //判断是否勾选了自动登录
                String autoLogin = request.getParameter("autoLogin");
                if("on".equals(autoLogin)){
                    //勾选了自动登录
                    Cookie cookie=new Cookie("info",username+"#"+password);
                    cookie.setMaxAge(60*60*24*7);
                    //cookie.setPath("/StuSysMvc");
                    cookie.setPath(request.getContextPath());//当前应用名
                    //发送cookie到客户端
                    response.addCookie(cookie);
                }
                //将用户信息存储到session
                request.getSession().setAttribute("user",user);
                response.sendRedirect("index2.jsp");
            }else{
                response.sendRedirect("login.jsp");
            }
        }
    }
    
    • index2.jsp
    <body>
        <c:if test="${not empty sessionScope.user}">
            欢迎来自${sessionScope.user.address}的${sessionScope.user.username}!!!
        </c:if>
        <c:if test="${empty sessionScope.user}">
            您好,请<a href="login.jsp">登录</a>!
        </c:if>
    </body>
    
    • AutoLoginFilter
    @WebFilter("/index2.jsp")
    public class AutoLoginFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            //1.先判断session是否失效,如果失效再判断cookie
            User sessionUser = (User) request.getSession().getAttribute("user");
            if (sessionUser == null) {
                //2.如果session失效,判断cookie
                Cookie[] cookies = request.getCookies();
                Cookie autoLoginCookie = CookieUtils.findCookie(cookies, "info");
                if (autoLoginCookie != null) {
                    //session失效了,但cookie不为空,所以要重新登录
                    String value = autoLoginCookie.getValue();
                    String[] split = value.split("#");
                    UserDao userDao = new UserDaoImpl();
                    User user = userDao.loginCheck(split[0], split[1]);
                    //重新登录成功后,再把session放回request
                    request.getSession().setAttribute("user", user);
                }
            }
            //放行到index2.jsp,在index2.jsp判断是否登录
            filterChain.doFilter(request, servletResponse);
        }
    
        @Override
        public void destroy() {
        }
    }
    

    2.6BeanUtils

    依赖jar包:

    对于这种情况,提交上来的参数很多,而这些参数又恰好能封装成一个JavaBean,可以使用BeanUtils简化代码。

    • 传统做法:
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            request.setCharacterEncoding("utf-8");//只针对post请求有效
            String username = request.getParameter("username");
            String password=request.getParameter("password");
            String address=request.getParameter("addresss");
            String phone=request.getParameter("phone");
            String birthday=request.getParameter("birthday");
            String email=request.getParameter("email");
    		User user=new User();
            
            user.setUsername(username);
            user.setPassword(password);
            user.setAddress(address);
            user.setPhone(phone);
            user.setEmail(email);
            try {
                user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse(birthday));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    
    • BeanUtils做法
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            request.setCharacterEncoding("utf-8");
    
            //注册自己的日期转换器,将String类型的birthday转换为Date类型
            ConvertUtils.register(new MyDateConverter(),Date.class);
    
            User user=new User();
            Map<String, String[]> parameterMap = request.getParameterMap();
            try {
                BeanUtils.populate(user,parameterMap);
            } catch (Exception e)  {
                e.printStackTrace();
            }
        }
    

    自定义时间转换器MyDateConverter:

    public class MyDateConverter implements Converter {
    	@Override
    	// 将value 转换 c 对应类型
    	// 存在Class参数目的编写通用转换器,如果转换目标类型是确定的,可以不使用c 参数
    	public Object convert(Class c, Object value) {
    		String strVal = (String) value;
    		// 将String转换为Date --- 需要使用日期格式化
    		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    		try {
    			Date date = dateFormat.parse(strVal);
    			return date;
    		} catch (ParseException e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    }
    
  • 相关阅读:
    Java服务,内存OOM了,如何快速定位?
    Java内存分析工具MAT(Memory Analyzer Tool)安装使用实例
    jmap使用方法及原理
    可能发生Full gc 的情况
    java--jvm GC-常用参数配置
    JVM. GC 性能调优方法与思路
    《嫌疑人X的献身》——两个天才之间的思想火花
    爱的纯粹与代价
    18年下半年计划表
    阿里校招准备-总纲
  • 原文地址:https://www.cnblogs.com/ALiWang/p/13875411.html
Copyright © 2011-2022 走看看