JavaWeb学习笔记9:Listener&Filter

1-Listener介绍与接口调用原理

Listener-监听器:利用接口调用,监听某一个事件的发生,状态的改变
监听器总共有8个,分成三种类型↓
一类:监听作用域的创建和销毁
二类:监听作用域中属性的创建销毁和替换
三类:Session值的钝化和活化(Activation)
接口调用:假设A类方法中的参数为一个接口,而你在Test类中要调用A的方法,那么只能通过编写接口和实例化来调用A的方法
接口调用原理

2-Listener监听三个作用域创建和销毁

监听器的新建要在web.xml中先配置
先回忆一下有哪几个作用域以及作用域的对象是什么:
1、pageContext - PageContext
2、request - HttpServletRequest
3、session - HttpSession
4、application - ServletContext
我们主要对下面2、3、4三个作用域进行监听,每个作用域的监听器对象其实就是在作用域对象名后+Listener

  • ServletContextListener
    servletcontext创建:
    启动服务器的时候
    servletContext销毁:
    关闭服务器、从服务器移除项目

  • ServletRequestListener(比较少用)
    request创建:
    访问服务器上的任意资源都会有请求出现。 访问 html、访问 jsp、访问 servlet
    request销毁:
    服务器已经对这次请求作出了响应之后

    public class MyRequestListener implements ServletRequestListener {
    	@Override
    	public void requestDestroyed(ServletRequestEvent sre) {
    		System.out.println("servletrequest 销毁了");
    	}
    	@Override
    	public void requestInitialized(ServletRequestEvent sre) {
    		System.out.println("servletrequest 初始化了");
    	}
    }
    
  • HttpSessionListener
    session的创建
    只要有调用getSession就创建。 html:(没有Session的调用) jsp:(默认调用getSession) servlet:(默认调用getSession)
    session的销毁
    1、超时,30分钟 2、非正常关闭,销毁 3、正常关闭服务器(序列化)

    public class MySessionListener implements HttpSessionListener {
    	@Override
    	public void sessionCreated(HttpSessionEvent se) {
    		System.out.println("创建session了");
    	}
    	@Override
    	public void sessionDestroyed(HttpSessionEvent se) {
    		System.out.println("销毁session了");
    	}
    }
    

    监听器作用:
    利用它来,在作用域对象创建的时候
    1. 完成自己想要的初始化工作
    2. 执行自定义任务调度 执行某一个任务 Timer(定时器)

3-Listener监听三个作用域属性状态变更

使用AttributeListener重写并查看状态变更
其中有属性:添加(set)、替换(set:key一样)、移出(remove)三种状态

  • servletContext — ServletContextAttributeListene
    servletContext
  • request — ServletRequestAttributeListener
    request
  • session — HttpSessionAttributeListener
    session

HttpSessionBindingListener(比较少用,作用类似,就是看是否添加或移出属性)
> 监听对象与session绑定和解除绑定的动作

@Override
public void valueBound(HttpSessionBindingEvent event) {
	System.out.println("对象被绑定进来了");
}

@Override
public void valueUnbound(HttpSessionBindingEvent event) {
	System.out.println("对象被解除绑定");
}

这里有必要解释一下HttpSessionBindingListener与HttpSessionAttributeListener的区别。
首先,两者的作用类似,都是监听对象的添加与解除,最大的区别就是,BindingListener要一个待监听对象去实现这个接口,然后在Session中添加该对象的时候才会触发监听器,但是如果你添加了其他对象,这个监听器是不会被触发的。
相反,AttributeListener也是要一个类去实现,在web.xml中配置要监听的Session对象,注意是Session对象,也就是说,只要Session中无论添加了什么对象,都会触发这个监听器,可以理解为这是一个安检门。

4-Listener监听HttpSession钝化活化

上面所说的两种监听器都必须在xml文件中进行注册,而最后一种监听器不需要注册,只需要实现接口

HttpSessionActivationListener
用于监听现在session的值是钝化(序列化)还是活化(反序列化)的动作
1、钝化 (序列化)
把内存中的数据 存储到硬盘上
2、活化 (反序列化)
一定要实现Serializable接口 若已经钝化,则重启服务器就自动活化了 即把硬盘中的数据读取到内存中

为什么要有钝化活化?
Session中存放过多的值会增加内存负担,所以我们可以把暂时不用的东西先钝化,要用的时候活化
自动执行钝化的事件默认是30分钟,我们可以手动配置事件和路径

如何配置Session自动钝化?
 1、在tomcat/conf/context.xml 里面配置
对所有的运行在这个服务器的项目生效
 2、在conf/Catalina/localhost/context.xml 配置
对 localhost生效 localhost:8080
 3、在web工程项目中的META-INF/context.xml配置
只对当前的工程生效

	#maxIdleSwap : 1分钟不用就钝化
	#directory :  钝化后的那个文件存放的目录位置。
	#D:\tomcat\apache-tomcat-7.0.52\work\Catalina\localhost\ListenerDemo\helloworld
<Context>
	<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
		<Store className="org.apache.catalina.session.FileStore" directory="helloworld"/>
	</Manager>
</Context>
5-Filter介绍与简单使用

Filter 其实就是对客户端发出来的请求进行过滤,浏览器发出,然后服务器派servlet处理,在中间就可以过滤,其实过滤器起到的是拦截的作用
比如它可以做什么?
  1. 对一些敏感词汇进行过滤
  2. 统一设置编码
  3. 自动登录
  …

Filter的生命周期:在服务器加载该项目时创建,在服务器关闭或从服务器移除该项目时销毁
Filter的执行顺序:
 1、客户端发出请求,先经过过滤器 如果过滤器放行,那么才能到servlet
 2、如果有多个过滤器,则会按照注册的映射顺序来排队,如果只有一个过滤器不放行,那么后面排队的过滤器以及servlet都不会受到请求


Filter的简单使用:
filter1、定义一个类 实现Filter

public class FilterDemo implements Filter {
	public void destroy() {}
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		System.out.println("doFilter……");
		chain.doFilter(request, response);
	}
	public void init(FilterConfig fConfig) throws ServletException {}
}

2、注册过滤器

#在web.xml里面注册 注册的手法与servlet基本一样
<filter>
	<display-name>FilterDemo</display-name>
	<filter-name>FilterDemo</filter-name>
	<filter-class>com.itheima.filter.FilterDemo</filter-class>
</filter>
<filter-mapping>
	<filter-name>FilterDemo</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

Filter的一些细节:
1、如果想放行,那么在doFilter方法里面操作,使用参数chain的
chain.doFilter(request, response);放行,让请求到达下一个目标
2、<url-pattern>/*</url-pattern> 写法格式与servlet一样
  1. 全路径匹配 以 / 开始
  2. 以目录匹配 以 / 开始 以 * 结束
  3. 以后缀名匹配 以 * 开始 以后缀名结束
3、针对 dispatcher 设置
  REQUEST : 只要是请求过来,都拦截,默认就是REQUEST
  FORWARD : 只要是转发都拦截
  ERROR : 页面出错发生跳转
  INCLUDE : 包含页面的时候就拦截

6-Filter实现自动登录

1、案例分析
案例分析
2、搭建好数据库(用户信息),页面(jsp)
3、AutoLoginFilter(主要代码):

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
	try {
		//1.首先,无论用户进入什么页面,先判断用户是否登陆并且没关闭浏览器
		HttpServletRequest req = (HttpServletRequest) request;
		//如果已登录且没关闭浏览器,则自动放行
		if(req.getSession().getAttribute("user")!=null){
			chain.doFilter(request, response);
		}else{//session值不存在
			Cookie[] cookies = req.getCookies();
			Cookie cookie = CookieUtil.findCookie(cookies, "autologin");
			if(cookie!=null){//如果cookie存在,则说明用户已经登录过
				String value = cookie.getValue();
				String username = value.split("#")[0];
				String password = value.split("#")[1];
				UserDao dao = new UserDaoImpl();
				UserBean user = dao.login(username, password);
				req.getSession().setAttribute("user", user);
				chain.doFilter(request, response);
			}else{
				//cookie和session都不存在,直接放行要求登录
				chain.doFilter(request, response);
			}
		}
	} catch (Exception e) {
		e.printStackTrace();
		chain.doFilter(request, response);
	}
}

4、LoginServlet(主要代码):

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	try {
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String auto_login = "";
		auto_login+=request.getParameter("autologin");
		System.out.println(auto_login);
//			System.out.println(username+"=="+password+"=="+aotologin);
		UserDao dao = new UserDaoImpl();
		UserBean user = dao.login(username,password);
		if(user != null){
			//将user存储到session中
			request.getSession().setAttribute("user", user);
			if(auto_login.equals("on")){
				//设置autologin的Cookie,包含账号密码,准备自动登录
				Cookie autologin = new Cookie("autologin", (username+"#"+password));
				//设置最长存活时间
				autologin.setMaxAge(60*2);
				//设置保存路径
				autologin.setPath(request.getContextPath());
				response.addCookie(autologin);
			}
			response.sendRedirect("index.jsp");
		}else{
			response.setContentType("text/html;charset=utf-8");
			response.getWriter().write("账号或密码错误!请重新登录!");
			response.setHeader("refresh", "3;login.jsp");
		}
	} catch (SQLException e) {
		e.printStackTrace();
	}
}
HPF-自我总结

  第一次接触监听器尤其是过滤器的时候,对于这个自动登录案例还不是理解的特别到位,但这次写博客的时候,我对案例的代码做了修改,而且针对修改过的代码与原来的代码做了比较,最后发现了问题所在。总而言之,希望对这两个组件的理解能够深刻记下!
  ——— 不积跬步,无以至千里;不积小流,无以成江海。

发布了15 篇原创文章 · 获赞 18 · 访问量 4568

猜你喜欢

转载自blog.csdn.net/oZuoShen123/article/details/105338631
今日推荐