说明:
本篇文章主要记录的是filter(过滤器)、事务管理、监听器Listener的介绍和使用。
JavaWeb中篇总结目录
1. 过滤器Filter的介绍和使用
1.1 过滤器Filter概述
文字描述
Filter也属于Servlet规范,中文名称就是过滤器,通俗的说它的作用就是在项目启动的时候,首先会进行拦截,将需要执行的内容先执行完毕之后,放行(可以继续访问服务),在经过一系列的执行之后又会返回回来,执行过滤器中放行后设置的程序
图片描述
说明:
①Filter开发步骤新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
②配置Filter,可以用注解@WebFilter,也可以使用xml文件 <filter> <filter-mapping>
③Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter(“*.do”)表示拦截所有以.do结尾的请求
④过滤器链【上图所示】
1)执行的顺序依次是: A B C demo03 C2 B2 A2
2)如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
3)如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
1.2 过滤器使用实例
首现创建三个过滤器
Filter01
@WebFilter("*.do")
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("A");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("A2");
}
@Override
public void destroy() {
}
}
Filter02
@WebFilter("*.do")
public class Filter02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("B");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("B2");
}
@Override
public void destroy() {
}
}
Filter03
@WebFilter("*.do")
public class Filter03 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("C");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("C2");
}
@Override
public void destroy() {
}
}
三个Filter形成一个过滤器链
执行的结果图(在默认的情况下按照名称进行过滤,但是在配置文件XML设置时按照配置的先后顺序进行过滤)
2. 事务管理
2.1 事务概述
事务,这个名词不是新鲜的知识点了,在学习数据库的时候就学习过事务,事务的含义是在执行的一件事的完整过程。例如:最经典的案例就是:转账,一个发钱,一个收钱。不可能是一个发钱没人收钱,不符合要求,另一种一个收钱,没人发钱也不行。所有两个过程只要有一个不能执行成功,就算事情没有成功,需要进行回滚操作【也就是恢复到刚开始的状态】
通过上图可以了解到:事务管理不能以DAO层的单精度方法为单位,而应该以业务层的方法为单位。
在实际的实现中我们可以在访问Servlet前,建立一个Filtter,建立过滤器之后,就可以实现建立一个连接开启事务,然后放行,在执行完毕所有的事务之后,就可以提交事务,只要在执行的过程中出现错误就会被catch捕捉到,然后执行事务的回滚。
实际开发中进行事务管理的方法
2.2 事务管理的实现
实现所需的项目仍然以说过后台存储管理系统为例:
实现过程简述:首先设置拦截器,来到事务管理,之后掉用新建链接的方法(通过ThreadLocal实现),修改BaseDAO中的内容
实现步骤:
①建立拦截器(建立一个类实现Filter接口),执行doFilter方法
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
//开启事务
TransactionManager.beginTrans();
System.out.println("开启事务...");
//放行
filterChain.doFilter(servletRequest,servletResponse);
//执行回来之后进行提交
TransactionManager.commit();
System.out.println("提交事务...");
}catch (Exception e){
e.printStackTrace();
try {
TransactionManager.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
②建立事务管理类,在这里实现三个方法:开启事务,提交事务,和回滚事务
//开启事务
public static void beginTrans() throws SQLException {
//如果获取到连接,直接设置取消自动提交
ConnUtil.getConn().setAutoCommit(false);
}
//提交事务
public static void commit() throws SQLException {
Connection conn = ConnUtil.getConn();
conn.commit();
ConnUtil.closeConn();
}
//回滚事务
public static void rollback() throws SQLException {
Connection conn = ConnUtil.getConn();
conn.rollback();
ConnUtil.closeConn();
}
③建立一个连接工具类,保证每一次事务的完整实现都是处在一个Connection中,在这里需要注意使用建立连接的属性是ThreadLocal(本地线程),建立连接工具类可以让其他需要用到的直接调用方法即可,不用新建连接,保障了使用的是同一个连接
//通过ThreadLocal的方法获取连接
static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
//从BaseDAO中过来的
public static Connection createConn(){
try {
//1.加载驱动
Class.forName(DRIVER);
//2.通过驱动管理器获取连接对象
return DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return null ;
}
public static Connection getConn(){
Connection conn = threadLocal.get();
if (conn==null){
//没有获取到连接的情况下,就调用创建连接的方法
conn = createConn();
threadLocal.set(conn);
}
//如果为空的话再获取一此连接
return threadLocal.get();
}
public static void closeConn() throws SQLException {
Connection conn = threadLocal.get();
if (conn==null){
//没有获取到连接的情况下,直接return
return;
}
if (!conn.isClosed()){
conn.close();
threadLocal.set(null);
}
}
BaseDAO中也不再需要建立连接,做出以下修改:
2.3 ThreadLocal介绍
了解内容【只需要知道set和get方法,使用泛型来确定类型即可】
ThreadLocal称之为本地线程 。 我们可以通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据,内部可以使用泛型,来实现同一个线程上都是用一个Connection。一共有两个方法:set()和get()方法即为:一个设置一个获取
ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
set方法源码分析:
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前的线程
ThreadLocalMap map = getMap(t); //每一个线程都维护各自的一个容器(ThreadLocalMap)
if (map != null)
map.set(this, value); //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection)
else
createMap(t, value); //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化
}
get方法源码分析:
public T get() {
Thread t = Thread.currentThread(); //获取当前的线程
ThreadLocalMap map = getMap(t); //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合)
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value; //entry.value就可以获取到工具箱了
return result;
}
}
return setInitialValue();
}
3. 监听器
3.1 监听器的分类
名称 | 说明 |
---|---|
ServletContextListener | 监听ServletContext对象的创建和销毁的过程 |
HttpSessionListener | 监听HttpSession对象的创建和销毁的过程 |
ServletRequestListener | 监听ServletRequest对象的创建和销毁的过程 |
ServletContextAttributeListener | 监听ServletContext的保存作用域的改动(add,remove,replace) |
HttpSessionAttributeListener | 监听HttpSession的保存作用域的改动(add,remove,replace) |
ServletRequestAttributeListener | 监听ServletRequest的保存作用域的改动(add,remove,replace) |
HttpSessionBindingListener | 监听某个对象在Session域中的创建与移除 |
HttpSessionActivationListener | 监听某个对象在Session域中的序列化和反序列化 |
3.2 监听器的简单使用
使用到的是:ServletContextAttributeListener,用于实现在项目启动的时候就创建beanFactory(实现中央处理器中冗余和控制反转)
监听器:
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext();
ServletContext application = servletContextEvent.getServletContext();
application.setAttribute("beanFactory",beanFactory);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
中央处理器做出的改变如下:
public void init() throws ServletException {
super.init();
// beanFactory = new ClassPathXmlApplicationContext();
//使用之后会在Tomcat启动的时候就实现IOC(控制反转)和依赖注入
ServletContext application = getServletContext();
Object beanFactoryObj = application.getAttribute("beanFactory");
if (beanFactoryObj!=null){
beanFactory = (BeanFactory) beanFactoryObj;
}else {
throw new RuntimeException("IOC容器创建失败");
}
}
简单总结就是:一个进行设置,一个进行获取(Set和Get)太晚了,就做这点说明吧…