- 9、使用 Filter 过滤器
- 9.1、使用 Filter 过滤器拦截/pages/manager/所有内容,实现权限检查
- 9.2、使用 ThreadLocal 来确保所有 dao *** 作都在同一个 Connection 连接对象中完成
- 9.3、使用 Filter 过滤器对上面进行优化
- 9.4、将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息页面
以下仅对 生成订单 的部分进行演示
原理分析图:
在 orderServiceImpl.createOrder() 方法里面,调用到了 orderDAOImpl.saveOrder()、orderItemDAOImpl.saveOrderItem()、bookServiceImpl.updateBook() 三个方法
如果在生成订单之后,生成订单详情和销量库存变更的 for 循环之前出现了异常,就会导致数据库里面只有订单,但是没有订单商品内容
【如图】
数据库里面有订单
但是没有订单商品内容
所以要保证 createOrder() 方法在一个事务中,要么都执行,要么都不执行
回忆 JDBC 里的事务部分,代码如下:
【代码如下】
建立连接——开启事务——一系列 *** 作——如没有异常就提交事务——如有异常就回滚事务——最后关闭连接
那么在 OrderServlet.createOrder() 方法里面,首先要保证该方法里面所有调用到的 *** 作都是一个连接里面,就使用 ThreadLocal 来存放连接,那么对 JdbcUtils 工具类进行修改,代码如下:
【代码如下】
存放连接的同时可以开启事务,这样非首次获取连接的时候,就已经开启了事务
最后关闭连接之后还需要释放连接,因为 Tomcat 底层也是使用数据库连接池,如果不及时释放,那么到一定数量时,就再也拿不到连接了
public class JdbcUtils { private static ThreadLocalconns = new ThreadLocal (); public static Connection getConnection(){ Connection conn = conns.get(); if (conn == null) { try { conn = dataSource.getConnection();//从数据库连接池中获取连接 conns.set(conn); // 保存到 ThreadLocal 对象中,供后面的 jdbc *** 作使用 conn.setAutoCommit(false); // 设置为手动管理事务 } catch (SQLException e) { e.printStackTrace(); } } return conn; } public static void commitAndClose(){ Connection connection = conns.get(); if (connection != null) { // 如果不等于 null,说明 之前使用过连接, *** 作过数据库 try { connection.commit(); // 提交 事务 } catch (SQLException e) { e.printStackTrace(); } finally { try { connection.close(); // 关闭连接,资源资源 } catch (SQLException e) { e.printStackTrace(); } } } // 一定要执行 remove *** 作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术) conns.remove(); } public static void rollbackAndClose(){ Connection connection = conns.get(); if (connection != null) { // 如果不等于 null,说明 之前使用过连接, *** 作过数据库 try { connection.rollback();//回滚事务 } catch (SQLException e) { e.printStackTrace(); } finally { try { connection.close(); // 关闭连接,资源资源 } catch (SQLException e) { e.printStackTrace(); } } } // 一定要执行 remove *** 作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术) conns.remove(); } }
在 orderServiceImpl.createOrder() 方法里面,调用到了 orderDAOImpl.saveOrder()、orderItemDAOImpl.saveOrderItem()、bookServiceImpl.updateBook() 三个方法
那么这些方法传入的连接就都使用 ThreadLocal 里面存放的那个连接,并且不可以有关闭 *** 作,也不可以捕获异常,必须抛出异常,否则回滚事务的地方就无法捕获异常,代码如下:
【代码如下】
修改 baseDao
编写代码的时候都对异常进行捕获了,这里就需要抛出异常,可以将 try-catch 改为 throws ,这里为了方便,直接加一句 throw new RuntimeException(e);
因为抛出了异常,最下面的 return -1; 就没作用了
修改 baseServlet
不可以捕获异常
修改 OrderItemDAOImpl
不可以有关闭 *** 作
修改 OrderDAOImpl
不可以有关闭 *** 作
修改 OrderServiceImpl
修改 OrderServlet
如此在 Servlet 程序里面,对业务语句进行 try-catch *** 作,即可实现生成订单、生产订单详情位于同一个事务中
做到发生异常的时候实现回滚
9.3、使用 Filter 过滤器对上面进行优化其实就是使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch,来进行实现的管理
原理分析图:
上面说到要对业务 Servlet 程序进行 try-catch *** 作,由于业务较多,会比较麻烦
不妨将所有 Servlet 程序放入 Filter 过滤器中
因为在 Filter 过滤器中,执行到 filterChain.doFilter()的时候才会执行所有 Servlet 程序
所以对 filterChain.doFilter()方法进行 try-catch *** 作,就相当于对所有 Servlet 程序进行 try-catch *** 作
Filter 类代码:
在 web.xml 中的配置:
TransactionFilter com.atguigu.filter.TransactionFilter TransactionFilter /*
一定要记得把 把 baseServlet 中的异常往外抛给 Filter 过滤器
public abstract class baseServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { doPost(req, resp); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { // 解决 post 请求中文乱码问题 // 一定要在获取请求参数之前调用才有效 req.setCharacterEncoding("UTF-8"); String action = req.getParameter("action"); try { // 获取 action 业务鉴别字符串,获取相应的业务 方法反射对象 Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class,HttpServletResponse.class); // System.out.println(method); // 调用目标业务 方法 method.invoke(this, req, resp); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e);// 把异常抛给 Filter 过滤器 } } }9.4、将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息页面
因为对于用户的角度,只知道点击后显示空白页面,不知道出了什么问题
在 web.xml 中我们可以通过错误页面配置来进行管理
将要显示的页面信息地址放在里面
500 /pages/error/error500.jsp 404 /pages/error/error404.jsp
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)