JavaWeb06过滤器,事务管理,监听器

过滤器Filter:

啥是过滤器?

 在客户端发请求的时候,会先经过过滤器,过滤器会有放行语句,才会向后执行,执行完毕响应的时候还会输出一句话

代码实现:

没有过滤器的版本:

 此时输出demo01正常工作并且成功跳转

 有过滤器的版本:

创建过滤器:

因为我们要建立过滤器,所以要遵守过滤器规范,实现过滤器的接口,并且重写方法

 过滤器也有初始化,服务,销毁三个过程

我们主要的代码还是要写在服务里面的

 正常情况应该是被拦截——>输出helloA(servlet执行结束后返回响应)——>输出helloA2

用注解配置拦截:

还可以用配置文件拦截:

测试:

 

过滤器拦截所有请求:

可以使用通配符注解来完成

 

 

 访问01:

 

 访问02:

 

 

过滤器链(过滤器可以干什么?):

可以设置多层过滤器,让每层过滤器完成自己的功能,完成后再给servlet进行处理

 

 

 

 

 输出结果:

 

 注意:过滤器链的执行顺序是文件命名顺序从上到下

过滤器对于我们现在项目的实际应用:

之前我们设置编码是在核心控制器中完成的,因为请求最先被过滤器拦截,所以我们可以把设置编码这个工作交给第一层过滤器去完成

 而且我们还可以把utf-8设置为默认值,如果用户想改其他的编码方式,可以在初始化的时候获取再次设置编码

 所以现在的控制器的设置编码就可以去掉了

 测试正常:

 总结:

事务管理: 

我们现在的事务管理模式(我们没有写,但是老师现在的是)

所以我们需要对事务管理结构进行重新编写

 1.尝试在service层进行事务管理:

2.用过滤器进行事务管理:

为什么不在service进行管理呢?

因为我们的service可能会有很多个,如果这样子,service每个功能的代码都需要进行事务管理,会非常麻烦,最终决定在过滤器进行事务管理

如果使用过滤器会遇到什么问题呢?

因为我们事务管理需要进行connection.setAutoCommit,和 connection.commit操作,所以包保证三个DAO组件使用的都是一个connection

如何去解决?

比如,现在一个工厂里有三个员工(DAO123),但是老板只给发了一套工具(connection),那么这三个人如何去工作?

 可以设置一个纽带(ThreadLocal),员工1看看溴代上有没有工具,如果没有工具,就去拿一个工具并且使用,使用完毕后放回纽带上(ThreadLocal.set(connection)),第二个人如果想使用,先看看纽带上有没有工具,如果有就拿工具使用(ThreadLocal.get(connection)),这样子就可以解决只有一个connection的问题了

代码实现:

 我们需要在这边实现关闭自动提交,手动提交,是否回滚事务,所以我们可以自己写一个实现类用于存放操作的代码,而且我们还可以在这里放set.connection和get.connection

 设置一个ThreadLocal用于存放connection

public class TransactionManager {

    private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    //开启事务
    public void beginTrans() throws Exception {
        //先获取threadLocal里面有没有connection
        Connection connection = threadLocal.get();
        //如果获取的为空,说明当前还没有创建connection
        if (connection == null){
            //创建connection
            connection = JDBCutil.getConnection();
            //放到threadLocal里
            threadLocal.set(connection);
        }
        //如果connection不为空,此时关闭自动提交,就是开启事务
        connection.setAutoCommit(false);
    }
    //提交事务
    public void commit() throws Exception {
        //先获取threadLocal里面有没有connection
        Connection connection = threadLocal.get();
        //如果获取的为空,说明当前还没有创建connection
        if (connection == null){
            //创建connection
            connection = JDBCutil.getConnection();
            //放到threadLocal里
            threadLocal.set(connection);
        }
        //如果connection不为空,进行事务提交
        connection.commit();
    }
    //回滚数据
    public void rollback() throws Exception {
        //先获取threadLocal里面有没有connection
        Connection connection = threadLocal.get();
        //如果获取的为空,说明当前还没有创建connection
        if (connection == null){
            //创建connection
            connection = JDBCutil.getConnection();
            //放到threadLocal里
            threadLocal.set(connection);
        }
        //如果connection不为空,回滚数据
        connection.rollback();

    }
}

但是我们现在发现,里面有很多代码都是重复的,可不可以把重复的集成起来

可以集成到JDBCutil里面

现在的JDBCutil:

 我们可以把判断ThreadLocal里有没有connection放到这里

如果有,直接返回connection

如果没有就在这里面调用方法创造一个connection放到ThreadLocal里

1.改名字:

 

2.创建真正的获取连接方法

此时外层就需要更改:

帮助我们判断ThreadLocal里有没有connection已经在JDBCutil里做好了,此时只需要进行事务管理就可以了

public class TransactionManager {

    //开启事务
    public static void beginTrans() throws Exception {
        //如果connection不为空,此时关闭自动提交,就是开启事务
        JDBCutil.getConnection().setAutoCommit(false);
    }
    //提交事务
    public static void commit() throws Exception {
        //如果connection不为空,进行事务提交
        JDBCutil.getConnection().commit();
    }
    //回滚数据
    public static void rollback() throws Exception {
        //如果connection不为空,回滚数据
        JDBCutil.getConnection().rollback();

    }
}

此时我们的过滤器就可以起作用了

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try{
            //开启事务
            TransactionManager.beginTrans();
            //放行
            filterChain.doFilter(servletRequest,servletResponse);
            //提交数据
            TransactionManager.commit();
        }catch (Exception e){
            e.printStackTrace();
            try {
                //如果有异常,需要回滚
                TransactionManager.rollback();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

但是现在还有问题,我们ThreadLocal的connection还没有关闭

应该是先开启事务

放行进行执行代码

如果没有异常,就提交并且关闭事务

如果有异常,就回滚并且关闭事务

我们也可以在JDBCutil里集成

注意:这里关闭的connection只限于关闭ThreadLocal里的connection,其他的关闭result或者preparementStatement..........会用之前的方法在BaseDAO里进行关闭

JDBCutil:

 TranscationManager(commit和rollback需要修改):

 我们现在的流程是

过滤器捕获

事务开始(此时已经有connection在thredlocal里)

过滤器放行

进入FruitController执行index方法

之前我们需要在这边获取connection并且传给下一层,现在已经在过滤器被创建好了,所以不需要了,关闭也不需要了

进入FruitService传参去掉

 进入FruitDAO传参去掉

 进入baseDAO

此时需要使用JDBCutil里的getConnection方法,如果里面有,就正常进行使用,如果没有就会去创建并且使用

 

 此时执行程序

 可以执行,那我们对于所有的方法都进行修改尝试以下

这里修正一下之前的bug

测试的时候,del方法总是执行不出来,method.invoke的时候返回空,原因是之前写的index.html点击删除链接之后跳转的是del.do,但是现在已经没有del.do了,应该跳转fruit.do

修改后目前测试功能正常 

看看这个时候访问index页面对数据库的两个操作是否是同一个connection

 是同一个

现在的问题:

现在的功能都正常,获取的数据库连接也都是对的

但是,如果我们程序真的出错了,我们可以进行事务回滚吗?

不能,因为现在我们的BaseDAO里有trycatch,有问题的话在DAO层就被拦截下来了,过滤器肯定检测不到

那我们如何做?——自己定义一个异常,并且向外抛出,一直抛到过滤器层就可以了

对BaseDAO的修改:

 新建一个异常类,如果BaseDAO出了问题,就抛这个异常

 给BaseDAO里每个方法都加这个异常向外抛的语句

 

 

 现在我们BaseDAO的异常都向上抛给service,service没有处理异常的语句向上抛给controller,controller现在也没有处理异常的语句,向上跑给控制器,控制器里有异常处理语句

对DispacterServlet的修改:

新建一个DispacterServlet异常类

 

 现在DispacterServlet继续向上抛异常,会被过滤器捕捉到,进行回滚处理

测试:

 现在我们进行添加的时候强行改变id为6的价格,故意写错updatesql语句,看看会不会回滚事务

 结果:

成功进行了回滚,没有成功添加

 

问题:之前改basedao代码把抛出异常写在finally里面了,应该在catch里面

修改后程序正常运行

ThreadLocal到底是个啥?

 

监听器是干什么的?

 用代码进行测试:

 配置文件:

 因为监听器是被动监听的,所以不用像之前一样配置的十分麻烦

此时在tomcat启动好之前就监听了

 tomcat关闭时也在监听

 监听器对于我们现在的项目有什么优化呢?

我们现在的DispatcherServlet里是中央控制器初始化的时候才会加载BeanFactory,这样子是非常不好的,作为控制注入描述类与类关系的bean工厂我们希望越早进行实现🈷好,那我们的监听器在tomcat还没有启动好的时候就会执行里面的代码,我们可以把创建bean容器的代码放在监听器中,需要的时候直接获取就好

创建监听器:

 

 我们是在中央控制器初始化时要使用IOC容器

此时运行程序正常

注意:中央控制器应该是MVC的内容,而创建IOC容器是整个应用程序应该做的,所以把他们分开写比较好

关于配置文件写法的改动:

之前我们的配置文件名称是写在ClassPathXmlApplicationContext里的,是固定写死的,这样子比较不好,可以设置为从web.xml里进行设置

ClassPathXmlApplicationContext的修改:

如何获取参数——在监听器内获取:

在web.xml写出配置文件的名称(路径):

 这样子获取配置文件路径是动态的,更好一点

测试:功能正常

JavaWeb知识点部分到这里就结束啦!!!!!

好耶!!!!!!!!!

现在程序的架构流程:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值