• java web 之 listen 与 filter


    一、Listener监听器

    Javaweb开发中的监听器,是用于监听web常见对象 HttpServletRequest HttpSession ServletContext

    监听它们的创建与销毁属性变化 以及session绑定javaBean

    1监听机制

    • 事件  就是一个事情
    • 事件源  产生这个事情的源头
    • 监听器  用于监听指定的事件的对象
    • 注册监听 要想让监听器可以监听到事件产生,必须对其进行注册。

    2Javaweb开发中常见监听器

    2.1监听域对象的创建与销毁

    • 监听ServletContext创建与销毁  ServletContextListener
    • 监听HttpSession创建与销毁  HttpSessionListener
    • 监听HttpServletRequest创建与销毁  ServletRequestListener

    2.2监听域对象的属性变化

    • 监听ServletContext属性变化  ServletContextAttributeListener
    • 监听HttpSession属性变化  HttpSessionAttributeListener
    • 监听HttpServletRequest属性变化  ServletRequestAttributeListener

    2.3监听session绑定javaBean

    它是用于监听javaBean对象是否绑定到了session域   HttpSessionBindingListener

    它是用于监听javaBean对象的活化与钝化  HttpSessionActivationListener

    3监听器的快速入门

    关于创建一个监听器的步骤

    1. 创建一个类,实现指定的监听器接口
    2. 重写接口中的方法
    3. web.xml文件中对监听器进行注册。
    4. ServletContext对象的创建与销毁

    3.1关于域对象创建与销毁的演示

    这个对象是在服务器启动时创建的,在服务器关闭时销毁的。

    HttpSession对象的创建与销毁

    HttpSession session=request.getSession();

    Session销毁 的方法

    1. 默认超时  30分钟
    2. 关闭服务器
    3. invalidate()方法
    4. setMaxInactiveInterval(int interval) 可以设置超时时间

    问题:直接访问一个jsp页面时,是否会创建session?

    会创建,因为我们默认情况下是可以在jsp页面中直接使用session内置对象的。

    HttpServletRequest创建与销毁

    Request对象是发送请求服务器就会创建它,当响应产生时,request对象就会销毁。

    3.2演示了Request域对象中属性变化

    java的监听机制中,它的监听器中的方法都是有参数的,参数就是事件对象,而我们可以通过事件对象直接获取事件源。

    3.3演示session绑定javaBean

    1、javaBean对象自动感知被绑定到session.

    HttpSessionBindingListener 这个接口是由javaBean实现的,并且不需要在web.xml文件中注册.

    2、javabean对象可以活化或钝化到session中。

    HttpSessionActivationListener如果javaBean实现了这个接口,那么当我们正常关闭服务器时,session中的javaBean对象就会被钝化到我们指定的文件中。

    当下一次在启动服务器,因为我们已经将对象写入到文件中,这时就会自动将javaBean对象活化到session中。

    我们还需要个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>
    

    案例-定时销毁session

    1、怎样可以将每一个创建的session全都保存起来?

    我们可以做一个HttpSessionListener,当session对象创建时,就将这个session对象装入到一个集合中.

    将集合List<HttpSession>保存到ServletContext域中。

    2、怎样可以判断session过期了?

    HttpSession中有一个方法public long getLastAccessedTime()

    它可以得到session对象最后使用的时间,可以使用invalidate方法销毁。

    ps(我们上面的操作需要使用任务调度功能.)java中有一个Timer定时器类

    package com.timer;
    
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TestTimer {
        public static void main(String[] args) {
            Timer t = new Timer();
            
            t.schedule(new TimerTask() {
                
                @Override
                public void run() {
                    System.out.println(new Date().toLocaleString());
                }
            }, 2000, 1000);
        }
    }

    关于三个域对象获取

    如果在Servlet中要获取request在方法上就有,request.getSession()  getServletContext();

    如果我们有request对象了,  request.getSession()    request.getSession().getServletCotnext();

    public class MySessionListener implements HttpSessionListener {
    
        public void sessionCreated(HttpSessionEvent arg0) {
            HttpSession session = arg0.getSession();
            //得到application中的list集合
            ServletContext application = session.getServletContext();
            //得到session对象,并放入list集合
            List<HttpSession> list =(List<HttpSession>) application.getAttribute("sessions");
            list.add(session);
            System.out.println("添加了"+session.getId());
        }
        public void sessionDestroyed(HttpSessionEvent arg0) {
            // TODO Auto-generated method stub
        }
    
    }

    程序在使用时,需要考虑并发问题,因为我们在web中,它一定是一个多线程的,那么我们的程序对集合进行了添加,还有移除操作。具体在MyServletContextListener的方法中如下

    public class MyServletContextListener implements ServletContextListener {
        public void contextDestroyed(ServletContextEvent arg0) {   
        }
        public void contextInitialized(ServletContextEvent arg0) {
            //通過事件原對象得到事件源
                ServletContext application = arg0.getServletContext();
                //创建一个集合 存储所有session对象
                final List<HttpSession> list = Collections.synchronizedList(new ArrayList<HttpSession>());
                application.setAttribute("sessions", list);
                //创建一个计时器对象
                Timer t = new Timer();
                t.schedule(new TimerTask() {
                    
                    @Override
                    public void run() {
                        System.out.println("开始扫描");
                        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
                            HttpSession session = (HttpSession) iterator.next();
                            long l = System.currentTimeMillis() - session.getLastAccessedTime();
                            if(l > 5000){
                                System.out.println("session移除了"+session.getId());
                                session.invalidate();
                                iterator.remove();
                            }
                        }
                    }
                }, 2000, 5000);    
        }
    }

    二、Filter

    二、Filter过滤器(重要)

    Javaweb中的过滤器可以拦截所有访问web资源的请求或响应操作。

    1.1、步骤:

    1. 创建一个类实现Filter接口
    2. 重写接口中方法  doFilter方法是真正过滤的。
    3. 在web.xml文件中配置

    注意:在Filter的doFilter方法内如果没有执行chain.doFilter(request,response),那么资源是不会被访问到的。

    1.2、FilterChain

    FilterChain 是 servlet 容器为开发人员提供的对象,它提供了对某一资源的已过滤请求调用链的视图。过滤器使用 FilterChain 调用链中的下一个过滤器,如果调用的过滤器是链中的最后一个过滤器,则调用链末尾的资源。

    问题:怎样可以形成一个Filter链?

      只要多个Filter对同一个资源进行拦截就可以形成Filter链

    问题:怎样确定Filter的执行顺序?

      由<filter-mapping>来确定

    1.3、Filter生命周期

    Servlet生命周期:

    实例化 --》 初始化 --》 服务 --》 销毁

    • 1 当服务器启动,会创建Filter对象,并调用init方法,只调用一次.
    • 2 当访问资源时,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,这个方法是真正拦截操作的方法.
    • 3 当服务器关闭时,会调用Filter的destroy方法来进行销毁操作.

    1.4、FilterConfig

    在Filter的init方法上有一个参数,类型就是FilterConfig.

    FilterConfig它是Filter的配置对象,它可以完成下列功能

    1. 获取Filtr名称
    2. 获取Filter初始化参数
    3. 获取ServletContext对象。

    问题:怎样在Filter中获取一个FIlterConfig对象?

     1 package com.itheima.filter;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.Filter;
     6 import javax.servlet.FilterChain;
     7 import javax.servlet.FilterConfig;
     8 import javax.servlet.ServletException;
     9 import javax.servlet.ServletRequest;
    10 import javax.servlet.ServletResponse;
    11 
    12 public class MyFilterConfigTest implements Filter{
    13 
    14     private FilterConfig filterConfig;
    15 
    16     public void init(FilterConfig filterConfig) throws ServletException {
    17         this.filterConfig = filterConfig;
    18     }
    19 
    20     public void doFilter(ServletRequest request, ServletResponse response,
    21             FilterChain chain) throws IOException, ServletException {
    22         //通过FilterConfig对象获取到配置文件中的初始化信息
    23         String encoding = filterConfig.getInitParameter("encoding");
    24         System.out.println(encoding);
    25         request.setCharacterEncoding(encoding);
    26         //放行
    27         chain.doFilter(request, response);
    28     }
    29 
    30     public void destroy() {
    31         // TODO Auto-generated method stub
    32     }
    33 }

    如下 web.xml配置
    <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>

    1.5、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()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用

     三、自动登录  (PS bean的属性名和数据库里的字段名千万要一样哦 不然会emmm 很惨)

    1. 当用户登陆成功后,判断是否勾选了自动登陆,如果勾选了,就将用户名与密码持久化存储到cookie
    2. 做一个Filter,对需要自动登陆的资源进行拦截

    首写要在登录Servlet中登录成功时把登录的信息保存在cookie里,并设置存活时间

    if(null != user){
                String autologin = request.getParameter("autologin");
                
                Cookie cookie = new Cookie("user", user.getUsername()+"&"+user.getPassword());
                cookie.setPath("/");
                if(autologin != null){// on / null
                    cookie.setMaxAge(60*60*24*7);
                }else{
                    cookie.setMaxAge(0);
                }
                response.addCookie(cookie);
                request.getSession().setAttribute("user", user);
                request.getRequestDispatcher("/home.jsp").forward(request, response);
            }

     然后设置好filter类 记住要在web.xml里面配置  如下 为 doFilter代码

    public void doFilter(ServletRequest arg0, ServletResponse arg1,
                FilterChain arg2) throws IOException, ServletException {
            //1、转换对象
            HttpServletRequest req = (HttpServletRequest) arg0;
            String uri = req.getRequestURI();
            String path = req.getContextPath();
            path = uri.substring(path.length());
            
            if(!("/login.jsp".equals(path)||"/servlet/loginServlet".equals(path))){
                
                User user = (User) req.getSession().getAttribute("user");
                if(user == null){
                    //2、处理业务
                    Cookie[] cookies = req.getCookies();
                    String username = "";
                    String password = "";
                    for (int i = 0;cookies!=null && i < cookies.length; i++) {
                        if("user".equals(cookies[i].getName())){
                            String value = cookies[i].getValue();
                            String[] values = value.split("&");
                            username = values[0];
                            password = values[1];
                        }
                    }
                    UserService us = new UserService();
                    User u = us.findUser(username, password);
                    if(u != null){
                        req.getSession().setAttribute("user", u);
                    }
                }
            }
            //3、放行
            arg2.doFilter(arg0, arg1);
        }

    ps 当访问别的页面时通过判断session时减少访问数据库的操作

    四、MD5加密

    mysql中可以对数据进行md5加密   Md5(字段)

    UPDATE USER SET PASSWORD=MD5(PASSWORD);

    需要一个MD5Utils工具类

    package com.util;
    
    import java.math.BigInteger;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    public class MD5Utils {
        /**
         * 使用md5的算法进行加密
         */
        public static String md5(String plainText) {
            byte[] secretBytes = null;
            try {
                secretBytes = MessageDigest.getInstance("md5").digest(
                        plainText.getBytes());
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException("没有md5这个算法!");
            }
            String md5code = new BigInteger(1, secretBytes).toString(16);
            for (int i = 0; i < 32 - md5code.length(); i++) {
                md5code = "0" + md5code;
            }
            return md5code;
        }
    }

     
    这样在loginservlet调用一下方法转化一下就ok了。

    五、全局的编码过滤器

    之前做的操作,只能对post请求是ok

     

    怎样可以做成一个通用的,可以处理post,get所有的请求的?

    在java中怎样可以对一个方法进行功能增强?

    1. 继承
    2. 装饰设
      1. 创建一个类让它与被装饰类实现同一个接口或继承同一个父类
      2. 在装饰类中持有一个被装饰类的引用
      3. 重写要增强的方法

    我们可以用getparameterMap这个方法来实现getparameter和getparametervalues两个方法 即MyFilter 最终版本

    package com.filter;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    
    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.HttpServletRequestWrapper;
    
    public class MyFilter implements Filter{
    
        public void destroy() {
            // TODO Auto-generated method stub
            
        }
    
        public void doFilter(ServletRequest arg0, ServletResponse arg1,
                FilterChain arg2) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) arg0;
            req = new MyRequest(req);
            arg2.doFilter(req, arg1);
            
        }
    
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
            
        }
    
    }
    class MyRequest extends HttpServletRequestWrapper{
    
        private HttpServletRequest request;
    
        public MyRequest(HttpServletRequest request) {
            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
        public String getParameter(String name) {
            Map<String, String[]> map = getParameterMap();
            return map.get(name)[0];
        }
        @Override
        public String[] getParameterValues(String name) {
            Map<String, String[]> map = getParameterMap();
            return map.get(name);
        }
        private boolean flag = true; //防止重复
        public Map<String, String[]> getParameterMap() {
            Map<String, String[]> map = request.getParameterMap();
            if(flag){
                for (Map.Entry<String, String[]> m : map.entrySet()) {
                    String[] values = m.getValue();
                    for (int i = 0; i < values.length; i++) {
                        try {
                            values[i] = new String(values[i].getBytes("iso-8859-1"),"UTF-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }
                }
                flag =false;
            }
            return map;
        }
    }
  • 相关阅读:
    html5 to jsp
    java通过springMail发送邮件
    solr配置-Solrconfig.xml
    solr配置-Schema.xml
    solr连接数据库导入数据
    log4j 1.2 配置总结
    1-12 ARP协议
    1-11 ICMP协议
    1-10 网际层
    1-9 TCP/IP参考模型
  • 原文地址:https://www.cnblogs.com/lzhh/p/javaweb_0.html
Copyright © 2020-2023  润新知