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
- request — ServletRequestAttributeListener
- session — HttpSessionAttributeListener
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的简单使用:
1、定义一个类 实现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-自我总结
第一次接触监听器尤其是过滤器的时候,对于这个自动登录案例还不是理解的特别到位,但这次写博客的时候,我对案例的代码做了修改,而且针对修改过的代码与原来的代码做了比较,最后发现了问题所在。总而言之,希望对这两个组件的理解能够深刻记下!
——— 不积跬步,无以至千里;不积小流,无以成江海。