JavaWeb书城项目(四)

JavaWeb书城项目(四),第1张

JavaWeb书城项目(四)

JavaWeb书城项目(四)
  • 9、使用 Filter 过滤器
    • 9.1、使用 Filter 过滤器拦截/pages/manager/所有内容,实现权限检查
    • 9.2、使用 ThreadLocal 来确保所有 dao *** 作都在同一个 Connection 连接对象中完成
    • 9.3、使用 Filter 过滤器对上面进行优化
    • 9.4、将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息页面

9、使用 Filter 过滤器 9.1、使用 Filter 过滤器拦截/pages/manager/所有内容,实现权限检查 9.2、使用 ThreadLocal 来确保所有 dao *** 作都在同一个 Connection 连接对象中完成

以下仅对 生成订单 的部分进行演示

原理分析图:

在 orderServiceImpl.createOrder() 方法里面,调用到了 orderDAOImpl.saveOrder()、orderItemDAOImpl.saveOrderItem()、bookServiceImpl.updateBook() 三个方法

如果在生成订单之后,生成订单详情和销量库存变更的 for 循环之前出现了异常,就会导致数据库里面只有订单,但是没有订单商品内容
【如图】

数据库里面有订单

但是没有订单商品内容

所以要保证 createOrder() 方法在一个事务中,要么都执行,要么都不执行

回忆 JDBC 里的事务部分,代码如下:
【代码如下】

建立连接——开启事务——一系列 *** 作——如没有异常就提交事务——如有异常就回滚事务——最后关闭连接

那么在 OrderServlet.createOrder() 方法里面,首先要保证该方法里面所有调用到的 *** 作都是一个连接里面,就使用 ThreadLocal 来存放连接,那么对 JdbcUtils 工具类进行修改,代码如下:
【代码如下】

存放连接的同时可以开启事务,这样非首次获取连接的时候,就已经开启了事务

最后关闭连接之后还需要释放连接,因为 Tomcat 底层也是使用数据库连接池,如果不及时释放,那么到一定数量时,就再也拿不到连接了

public class JdbcUtils {
	private static ThreadLocal conns = 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

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5695118.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存