栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

22-05-31 西安 javaweb(12) 监听器listener和过滤器filter、编码过滤器、登录过滤器、事务过滤器

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

22-05-31 西安 javaweb(12) 监听器listener和过滤器filter、编码过滤器、登录过滤器、事务过滤器

服务器三大组件:

  1. servlet,处理请求和响应
  2. filter,过滤请求和响应
  3. listener,监听服务器中某个对象的状态

监听器listener
        监听器用于监听服务器的状态或者服务器中某个对象的状态

监听器有3种:

1、ServletContextListener,监听ServletContext的状态

ServletContextEvent对象代表从ServletContext对象身上捕获到的事件,通过这个事件对象我们可以获取到ServletContext对象。

1、ServletContextListener,监听ServletContext的状态
public void contextInitialized(ServletContextEvent sce) {
    //监听ServletContext初始化
    //因为ServletContext对象是在服务器启动的时候创建、 在服务器关闭的时候销毁 
    //所以ServletContextListener也可以监听服务器的启动和关闭
}

public void contextDestroyed(ServletContextEvent sce) {
    //监听ServletContext销毁
}

2、HttpSessionListener,监听HttpSession的状态

HttpSessionEvent对象代表从HttpSession对象身上捕获到的事件,通过这个事件对象我们可以获取到触发事件的HttpSession对象。

2、HttpSessionListener,监听HttpSession的状态
public void sessionCreated(HttpSessionEvent se) {
    //监听HttpSession的创建
}

public void sessionDestroyed(HttpSessionEvent se) {
    //监听HttpSession的销毁
}

3、HttpSessionAttributeListener,监听HttpSession中共享数据的变化情况

3、HttpSessionAttributeListener,监听HttpSession中共享数据的变化情况
public void attributeAdded(HttpSessionBindingEvent sbe) {
    //监听HttpSession中添加共享的数据
}

public void attributeRemoved(HttpSessionBindingEvent sbe) {
    //监听HttpSession中删除共享的数据
}

public void attributeReplaced(HttpSessionBindingEvent sbe) {
    //监听HttpSession中替换共享的数据
}

过滤器Filter:

过滤器本质是一个Filter接口。广义上来说:所有实现了Filter接口的类都是过滤器

filter:作用于浏览器和目标资源之间。什么叫资源?服务器中一切皆资源!
过滤器结果要么拦截要么放行。

过滤器的使用步骤:

  1. 创建一个类,实现Filter接口,并重写方法
  2. 在web.xml中进行注册
  3. 使用过滤器中的doFilter()过滤请求和响应

3大组件使用都要在web.xml中注册,filter注册的时候和servlet的注册是一模一样的,就是把单词换了一下


    FirstFilter
    com.atguigu.filter.FirstFilter


    FirstFilter
    /*

filter过滤路径的写法

精确匹配   /index.html 只过滤某一个资源

模糊匹配
/* 所有请求
/pages/* 只对pages下的资源有效果

后缀匹配
*.html 只对html资源有效果

  1.  可以写多个
  2.  *要么出现在最前面,要么最后面
  3.  这三种语法必须单独使用,不能混合使用

servlet匹配

OrderServlet 对某个servlet(如整合后的servlet)的所有请求和响应过滤


filter的生命周期

初始化:过滤器在服务器启动时执行init()初始化。在整个服务器工作的整个过程中,只执行一次。

执行过滤:只有访问符合过滤路径的资源才会执行doFilter(),执行多次。

销毁:在服务器关闭时销毁,destroy()。在整个服务器工作的整个过程中,只执行一次。

servletContext监听器先被加载,第二个是过滤器,第三个是servlet


过滤器链

过滤器不是只有一个,会把所有过滤器放在一起称为过滤器链(FilterChain对象)。如下是我们的编码过滤器。

多个过滤器同时过滤同一个资源,谁先过过滤,谁后过滤(doFilter)。只跟在web.xml 中 的注册顺序有关

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)  {
   req.setCharacterEncoding("UTF-8");
   resp.setCharacterEncoding("UTF-8");
   //处理完编码直接放行
   chain.doFilter(req, resp);
}

doFilter调用过滤器链下一个过滤器的DoFilter方法,没有下一个过滤器则直接放行。

在doFilter方法中(其实就是方法栈)
放行前的代码会按照在web.xml 中 的顺序执行
放行后的内容会按照在web.xml 中 的反序执行


登录过滤器 LoginFilter

值得注意的是,filter过滤路径这里用的是servlet匹配.表示在访问订单相关功能的时,都要先判断用户是否处于登录状态。

    
        LoginFilter
        com.atguigu.filter.LoginFilter
    
    
        LoginFilter
        OrderClientServlet
    
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpSession session = request.getSession();
        Object user = session.getAttribute("user");
        if (user == null) {
            //未登录,转发到登录页面,并给出提示
            request.setAttribute("errorMsg", "订单功能请先登录");
//            processTemplate("user/login", request, response);
            request.getRequestDispatcher("/UserServlet?method=toLogin").forward(request,response);
        } else {
            //已登录,放行
            chain.doFilter(req, resp);
        }
    }

未登录的情况下,去访问订单功能(结账),会跳转到登录页面,并且提示也变为“订单功能清先登录”,比较友好


事务过滤器 TransactionFilter 

一般情况下,业务逻辑层作为事务处理层,但是每一个功能都需要处理事务,每一个service的方法都需要添加事务的代码。


过滤器作用于浏览器和目标资源之间,放行chain.doFilter()表示servlet的执行,即当前功能的执行因此只需要在过滤器中,对放行chain.doFilter()添加事务的代码,即对所有的功能添加了事务的代码

当然,这个代码改动起来还是比较麻烦的,

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        Connection connection = null;
        try {
            connection = JDBCUtil.getConnection();
            //开启事务
            connection.setAutoCommit(false);
            chain.doFilter(req, resp);
            //没有发生异常,对事务提交
            connection.commit();
            System.out.println("TransactionFilter-->提交事务");
        } catch (Exception e) {
            //执行功能过程中发生了异常,对事务进行回滚
            try {
                connection.rollback();
                System.out.println("TransactionFilter-->回滚事务");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
            //重定向到错误页面
            response.sendRedirect(request.getContextPath() + "/ErrorServlet");
        } finally {
            //把连接放回到连接池
            JDBCUtil.closeConnection(connection);
        }
    }

去保证出现异常的时候,之后的代码不再执行,之前的代码回滚。

1、用到的技巧有:在catch子句中手动抛出运行时异常!
     在catch里手动抛出异常。throw new RuntimeException(e),加了参数e就会把真实的异常打印出来。

try {
   connection = JDBCUtil.getConnection();
   o = queryRunner.query(connection, sql, new ScalarHandler(), params);
} catch (SQLException e) {
   throw new RuntimeException(e);
}

2、 ThreadLocal  使得事务过滤器中操作的连接对象和BaseDao中操作的连接对象是同一个

在从Filter、Servlet、Service一直到Dao运行的过程中,我们始终都没有做类似new Thread().start()这样开启新线程的操作,所以整个过程在同一个线程中。

ThreadLocal的本质是一个map集合,以当前线程对象为键,以数据为值,可以将连接对象和当前线程进行绑定,这样在当前线程中,获取的连接对象都是同一个。

  1. void set(Object object):存储数据
  2. Object get():获取存储的数据
  3. void remove():删除存储的数据
    private static ThreadLocal threadLocal = new ThreadLocal<>();    
    public static Connection getConnection(){
        Connection connection = null;
        try {
         // 一个ThreadLocal对象,在一个线程中只能存储一个数据,
         //在该线程的任何地方调用get()方法获取到的都是同一个数据
         connection = threadLocal.get();
            if(connection==null){
                connection = dataSource.getConnection();
               //跟当前线程绑定,往当前线程共享了这个数据
                threadLocal.set(connection);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

当然,这部分只是展示了核心代码。实际上还有好几步要改。

比如释放连接的时候,要删除存储在ThreadLocal的数据,不然下一次用的时候有connection ,但是这个connection已经放回连接池中了,不能再使用了。

connection.close();
threadLocal.remove();

 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/944084.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号