欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

javaEE(Listener监听器和Filter过滤器)

程序员文章站 2022-06-23 18:37:01
...

Listener监听器

javaweb监听器介绍

       1.监听web对象创建与销毁的监听器

                            ServletContextListener

                            HttpSessionListener

                            ServletRequestListener 

2.监听web对象属性变化

                            ServletContextAttributeListener

                            HttpSessionAttributeListener

                            ServletRequestAttributeListener  

3.监听session绑定javaBean

                            HttpSessionBindingListener

                            HttpSessionActivationListener

1.    javaweb监听器创建步骤

Ø  创建一个类,实现指定的监听器接口     

Ø  重写接口中的方法.

Ø  在web.xml文件中配置监听


监听对象创建销毁

ServletContextListener在系统启动时,调用contextInitialized()方法

HttpSessionListener在访问jsp页面或者servlet创建session时候,调用sessionCreated()

session时间到了,或者invalidate()时候,调用sessionDestroyed()

ServletRequestListener在访问页面的时候,调用requestInitialized();

监听对象属性变化

ServletRequestAttributeListener在添加属性的时候调用(注意第一次添加后会调用替换方法,因为request自动加了一些属性)

监听session绑定和活化.钝化

HttpSessionBindingListener绑定在javaBean上,如果此对象绑定了HttpSessions就会调用绑定方法(不需要xml配置,因为他不虚启动)

案列:定时销毁Session(可以直接设置session存留时间,这个案例是定时调度Timer的教程)

1.创建HttpSessionListener,当session对象创建时,就将这个session对象装入一个集合中

2.将List<HttpSession>保存到ServletContext域中。

3.HttpSession中有一个方法getLastAccessedTime();他可以获得session对象最后使用的时间。

4.使用invalidate方法销毁

创建实现ServletContextListener接口

public class MyServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext对象创建了");
        ServletContext context = servletContextEvent.getServletContext();
        //创建一个集合用于存储所有的session对象 注意:需要加锁,并发的创建session添加时候,会有问题
        List<HttpSession> sessions = Collections.synchronizedList(new ArrayList<HttpSession>());
        //把集合放到application域中
        context.setAttribute("sessions",sessions);
        //服务器启动就执行此方法,所以在这里加上计时器对象
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                //Iterator和listIterator都可以删除,区别在于listIterator可以倒序遍历,可以添加元素,而Iterator不能
                ListIterator<HttpSession> iterator = sessions.listIterator();
                while (iterator.hasNext()){
                    HttpSession next = iterator.next();
                    long l = next.getLastAccessedTime();
                    if(System.currentTimeMillis()-l>5000){//如果时间大于5秒,把session销毁
                        next.invalidate();//使之无效
                        iterator.remove();
                    }
                }
            }
        },5000,5000);//延迟2秒后执行,每间隔5秒执行一次
    }
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext对象删除了");
    }
}
创建实现HttpSessionListener接口

public class ServletSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        //得到当前创建的session
        HttpSession session = httpSessionEvent.getSession();
        //得到application对象中的list集合,session中有getServletContext()方法
        ServletContext application = session.getServletContext();
        List<HttpSession> sessions = (List<HttpSession>) application.getAttribute("sessions");
        //把当前创建的session对象添加到集合中
        boolean add = sessions.add(session);
        System.out.println(session.getId()+"  :   "+(add==true?"添加成功":"添加失败"));
    }
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("session销毁了");
    }
}
并且在xml配置信息

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
<listener>
    <listener-class>com.mck.entity.MyServletContextListener</listener-class>
</listener>
<listener>
    <listener-class>com.mck.entity.ServletSessionListener</listener-class>
</listener>
</web-app>



Filter过滤器(重要)

很多地方使用,比如验证是否登录,统一的编码设置,加密设置等。
快速入门:
1.创建一个类实现Filter接口
2.重写接口中的方法,doFiter方法是否真正过滤的
3.在web.xml文件中配置
注意:1.在Fiter的doFilter方法内如果没有执行chain.doFiter(request.response)那么资源是不会被访问到的。(需要放行)
2.在chain.doFiter()方法后,可以定义后面的操作(放行后又回到filter执行chain.dofilter后面的方法)
3.FilterChain过滤器链

如果有相同的过滤器拦截了某一个请求,则FilterChain会调用下一个过滤器

调用循序是xml的<filter-mapping>摆放的上下顺序!!(方法回执,先里面后外面)

Filter生命周期

Servlet生命周期:

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

当服务器启动,会创建filter对象,并调用init方法,只调用一次

当访问资源时,路径与filter的拦截路径匹配时,会执行filter中的doFilter,这个方法是真正拦截操作的方法

当服务器关闭时,会调用filter的destroy方法来进行销毁


FilterConfig类

用于获取filter初试化的参数


Filter实战(通过拦截器解决doGet提交和doPost提交乱码问题)

dopost方式通过拦截器

设置req.setContextType("text/html;charset=utf-8")

chain放行后,所有被拦截的servletl类都被设置了

doget方式通过包装设计模式(包装设计模式可以理解方法套一层皮,核心是改不了的,但是可以加额外的功能,如设置编码)

先了解两种模式

包装设计模式:1.实现被包装类相同的接口,2.被包装类作为参数传递包装类中(通过构造器),3.对需要重写的方法改动,不需要重写的,原样调用即可

适配器设计模式:适配器实现原理同上,区别在于,适配器实现接口所有的方法,需要重写方法直接调用即可。

思路:

1.通过拦截器得到HttpServletRequest

2.创建一个Myrequest类继承HttpServletRequestWrapper类(按照包装设计模式来说,应该实现HttpServletRequest接口,确实是,但是实现接口后发现,你只需要改动一个方法,但是却需要实现100多个其它方法,很麻烦,所以继承HttpServletRequestWrapper,这个类帮你实现了HttpServletRequest接口,并且没有改动方法,你只需要把需要改动的方法重写即可,这就是适配器模式(适配这个字就很方便,哈哈))

3.代码贴上来(包装类MyRequest)

public class MyRequest extends HttpServletRequestWrapper {
    HttpServletRequest request;
    public MyRequest(HttpServletRequest request){
        //HttpServletRequestWrapper适配器模式需要一个对象,原理和包装类一样
        //区别在于适配器模式把传递的对象接口的方法全部给实现了,不需要重新实现接口中方法,并且,需要那个方法,就单独调用重写那个方法
        super(request);
        this.request=request;
    }
    //重写方法
    public String getParameter(String name) {
        Map<String, String[]> map = getParameterMap();
        return map.get(name)[0];
    }
    //重写方法
    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();//调用传递过来的request参数的getParameterMap()方法
        if(flag) {//防止多次执行乱码,多次调用getParameter或者别的方法,就会坏变好变坏
            for (Map.Entry<String, String[]> e : map.entrySet()) {
                String[] value = e.getValue();//注意这里是引用类型 value指向实际堆内存地址改动可变
                for (int i = 0; i < value.length; i++) {
                    try {
                        value[i] = new String(value[i].getBytes("iso-8859-1"), "UTF-8");//转码
                    } catch (UnsupportedEncodingException e1) {
                        e1.printStackTrace();
                    }
                }
            }
            flag=false;
        }
        return map;
    }
}
4.再Filter中把request传递到MyRequest中,传递给其他页面,这时候其他页面就用的是包装类型,而不是原有的request


好了就这么多,跟黑马老师课程来的,觉得好就记录在网上供大家分享