要求:web工程下有一个admin的目录。这个admin目录下的所有资源必须要在用户登录之后才允许访问。
原理: Filter过滤器检查用户权限,有权限就放行,无权限挑战登录页面,不允许其访问。
实现javax.servlet.Filter接口过滤方法doFilter @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; HttpSession session = httpServletRequest.getSession(); Object user = session.getAttribute("user"); if (user==null){ servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse); }else { //让程序继续往下访问用户的目标资源 filterChain.doFilter(servletRequest,servletResponse); } } 配置web.xml <!-- 配置过滤器--> <filter> <filter-name>AdminFilter</filter-name> <filter-class>com.bookstore.filter.AdminFilter</filter-class> </filter> <filter-mapping> <filter-name>AdminFilter</filter-name> <!--配置拦截路径,/ 表示请求地址为:http://ip:port/工程路径/ 映射到IDEA的web目录 '/admin/*' 表示http://ip:port/工程路径/admin/*,--> <url-pattern>/admin/*</url-pattern> </filter-mapping>错误:不要/打头
<url-pattern>/admin/*.jsp</url-pattern>正确:
<url-pattern>*.jsp</url-pattern>只关心是否匹配,不关心资源是否存在。
注意,拦截页面和拦截servlet的地址不完全一致:
<!-- 拦截页面--> <url-pattern>/pages/manager/*</url-pattern> <!-- 拦截servlet--> <url-pattern>/manager/bookServlet</url-pattern>该类提供了线程局部(thread-local)变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过get/set方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal实例通常是类中的private static字段,它们希望将状态与某一个线程(例如,用户ID或事务ID)相关联。
解决同一个Connection对象:
用ThredLocal确保所有操作都使用同一个Connection对象。 前提:所有操作都是在同一线程中。回滚事务需要得知异常,也就是内部操作将异常的处理权 让渡 给数据库事务管理的代码。数据库事务(Jdbc实现):
@Test public void testCommit() throws SQLException { Connection connection = JdbcUtils.getConnection(); //conn.set(connection); try{ connection.setAutoCommit(false); //connection = conn.get(); //执行一系列的jdbc操作 connection.commit();//connection = conn.get(); } catch (SQLException e) { connection.rollback();//connection = conn.get(); }finally { JdbcUtils.close(connection);//connection = conn.get(); } //======================================== //改写后 try{ //执行一系列的jdbc操作 orderService.createOrder(cart,userId);底层调用了多步对数据库的操作 JdbcUtils.commitAndClose();//提交事务 } catch (SQLException e) { JdbcUtils.rollbackAndClose();//回滚事务 e.printStackTrace(); } }改写数据库connection的相关操作改写:
/* * 为了数据库事务 提交/回滚 改写的 */ private static ThreadLocal<Connection> conn = new ThreadLocal<>(); public static Connection getConnection(){ Connection connection = conn.get(); if (connection == null){ try { connection = dataSource.getConnection(); conn.set(connection); //保存到ThreadLocal对象中,供后面的jdbc使用 connection.setAutoCommit(false);//设置为手动管理 } catch (SQLException e) { e.printStackTrace(); } } return connection; } /* * 提交事务,并关闭释放连接 */ public static void commitAndClose(){ Connection connection = conn.get(); if (connection!=null){ try { connection.commit();//提交事务 } catch (SQLException e) { e.printStackTrace(); }finally { try { connection.close();//关闭连接 } catch (SQLException e) { e.printStackTrace(); } } } //一定要执行remove操作,否则会出错,因为tomcat'服务器使用了线程池技术 conn.remove(); } /* * 回滚事务,并关闭释放连接 */ public static void rollbackAndClose(){ Connection connection = conn.get(); if (connection!=null){ try { connection.rollback();//提交事务 } catch (SQLException e) { e.printStackTrace(); }finally { try { connection.close();//关闭连接 } catch (SQLException e) { e.printStackTrace(); } } } //一定要执行remove操作,否则会出错,因为tomcat'服务器使用了线程池技术 conn.remove(); } 最后,将数据库事务操作改写成了 try{ //执行一系列的jdbc操作 orderService.createOrder(cart,userId);底层调用了多步对数据库的操作 JdbcUtils.commitAndClose();//提交事务 } catch (SQLException e) { JdbcUtils.rollbackAndClose();//回滚事务 e.printStackTrace(); }上面是对项目其中一个操作的改写,但项目中往往有多个操作,也就是要改写多处代码。
可以用Filter,相当于给所有的service方法加上try-catch但若是过程中,依然有try-catch把异常内部消化了,那么TransactionFilter还是接收不到异常,影响对事务成功还是失败的判断。但是这样统一处理异常,缺乏错误页面的展示 <!-- 配置过滤器--> <filter> <filter-name>TransactionFilter</filter-name> <filter-class>com.bookstore.filter.TransactionFilter</filter-class> </filter> <filter-mapping> <filter-name>TransactionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> package com.bookstore.filter; import com.bookstore.utils.JdbcUtils; import javax.servlet.*; import java.io.IOException; public class TransactionFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { try { filterChain.doFilter(servletRequest,servletResponse); JdbcUtils.commitAndClose(); } catch (IOException e) { JdbcUtils.commitAndClose(); } catch (ServletException e) { e.printStackTrace(); e.printStackTrace(); } } }