一、Listener监听器
Javaweb开发中的监听器,是用于监听web常见对象 HttpServletRequest HttpSession ServletContext
监听它们的创建与销毁、属性变化 以及session绑定javaBean
1、监听机制
- 事件 就是一个事情
- 事件源 产生这个事情的源头
- 监听器 用于监听指定的事件的对象
- 注册监听 要想让监听器可以监听到事件产生,必须对其进行注册。
2、Javaweb开发中常见监听器
2.1、监听域对象的创建与销毁
- 监听ServletContext创建与销毁 ServletContextListener
- 监听HttpSession创建与销毁 HttpSessionListener
- 监听HttpServletRequest创建与销毁 ServletRequestListener
2.2、监听域对象的属性变化
- 监听ServletContext属性变化 ServletContextAttributeListener
- 监听HttpSession属性变化 HttpSessionAttributeListener
- 监听HttpServletRequest属性变化 ServletRequestAttributeListener
2.3、监听session绑定javaBean
它是用于监听javaBean对象是否绑定到了session域 HttpSessionBindingListener
它是用于监听javaBean对象的活化与钝化 HttpSessionActivationListener
3、监听器的快速入门
关于创建一个监听器的步骤
- 创建一个类,实现指定的监听器接口
- 重写接口中的方法
- 在web.xml文件中对监听器进行注册。
- ServletContext对象的创建与销毁
3.1、关于域对象创建与销毁的演示
这个对象是在服务器启动时创建的,在服务器关闭时销毁的。
HttpSession对象的创建与销毁
HttpSession session=request.getSession();
Session销毁 的方法
- 默认超时 30分钟
- 关闭服务器
- invalidate()方法
- setMaxInactiveInterval(int interval) 可以设置超时时间
问题:直接访问一个jsp页面时,是否会创建session?
会创建,因为我们默认情况下是可以在jsp页面中直接使用session内置对象的。
HttpServletRequest创建与销毁
Request对象是发送请求服务器就会创建它,当响应产生时,request对象就会销毁。
3.2、演示了Request域对象中属性变化
在java的监听机制中,它的监听器中的方法都是有参数的,参数就是事件对象,而我们可以通过事件对象直接获取事件源。
3.3、演示session绑定javaBean
1、javaBean对象自动感知被绑定到session中.
HttpSessionBindingListener 这个接口是由javaBean实现的,并且不需要在web.xml文件中注册.
2、javabean对象可以活化或钝化到session中。
HttpSessionActivationListener如果javaBean实现了这个接口,那么当我们正常关闭服务器时,session中的javaBean对象就会被钝化到我们指定的文件中。
当下一次在启动服务器,因为我们已经将对象写入到文件中,这时就会自动将javaBean对象活化到session中。
我们还需要个context.xml文件来配置钝化时存储的文件
在meta-inf目录下创建一个context.xml文件
<Context> <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"> <Store className="org.apache.catalina.session.FileStore" directory="it315"/> </Manager> </Context>
案例-定时销毁session
1、怎样可以将每一个创建的session全都保存起来?
我们可以做一个HttpSessionListener,当session对象创建时,就将这个session对象装入到一个集合中.
将集合List<HttpSession>保存到ServletContext域中。
2、怎样可以判断session过期了?
在HttpSession中有一个方法public long getLastAccessedTime()
它可以得到session对象最后使用的时间,可以使用invalidate方法销毁。
ps(我们上面的操作需要使用任务调度功能.)在java中有一个Timer定时器类
package com.timer; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class TestTimer { public static void main(String[] args) { Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run() { System.out.println(new Date().toLocaleString()); } }, 2000, 1000); } }
关于三个域对象获取
如果在Servlet中要获取request,在方法上就有,request.getSession() getServletContext();
如果我们有request对象了, request.getSession() request.getSession().getServletCotnext();
public class MySessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent arg0) { HttpSession session = arg0.getSession(); //得到application中的list集合 ServletContext application = session.getServletContext(); //得到session对象,并放入list集合 List<HttpSession> list =(List<HttpSession>) application.getAttribute("sessions"); list.add(session); System.out.println("添加了"+session.getId()); } public void sessionDestroyed(HttpSessionEvent arg0) { // TODO Auto-generated method stub } }
程序在使用时,需要考虑并发问题,因为我们在web中,它一定是一个多线程的,那么我们的程序对集合进行了添加,还有移除操作。具体在MyServletContextListener的方法中如下
public class MyServletContextListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent arg0) { } public void contextInitialized(ServletContextEvent arg0) { //通過事件原對象得到事件源 ServletContext application = arg0.getServletContext(); //创建一个集合 存储所有session对象 final List<HttpSession> list = Collections.synchronizedList(new ArrayList<HttpSession>()); application.setAttribute("sessions", list); //创建一个计时器对象 Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run() { System.out.println("开始扫描"); for (Iterator iterator = list.iterator(); iterator.hasNext();) { HttpSession session = (HttpSession) iterator.next(); long l = System.currentTimeMillis() - session.getLastAccessedTime(); if(l > 5000){ System.out.println("session移除了"+session.getId()); session.invalidate(); iterator.remove(); } } } }, 2000, 5000); } }
二、Filter
二、Filter过滤器(重要)
Javaweb中的过滤器可以拦截所有访问web资源的请求或响应操作。
1.1、步骤:
- 创建一个类实现Filter接口
- 重写接口中方法 doFilter方法是真正过滤的。
- 在web.xml文件中配置
注意:在Filter的doFilter方法内如果没有执行chain.doFilter(request,response),那么资源是不会被访问到的。
1.2、FilterChain
FilterChain 是 servlet 容器为开发人员提供的对象,它提供了对某一资源的已过滤请求调用链的视图。过滤器使用 FilterChain 调用链中的下一个过滤器,如果调用的过滤器是链中的最后一个过滤器,则调用链末尾的资源。
问题:怎样可以形成一个Filter链?
只要多个Filter对同一个资源进行拦截就可以形成Filter链
问题:怎样确定Filter的执行顺序?
由<filter-mapping>来确定
1.3、Filter生命周期
Servlet生命周期:
实例化 --》 初始化 --》 服务 --》 销毁
- 1 当服务器启动,会创建Filter对象,并调用init方法,只调用一次.
- 2 当访问资源时,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,这个方法是真正拦截操作的方法.
- 3 当服务器关闭时,会调用Filter的destroy方法来进行销毁操作.
1.4、FilterConfig
在Filter的init方法上有一个参数,类型就是FilterConfig.
FilterConfig它是Filter的配置对象,它可以完成下列功能
- 获取Filtr名称
- 获取Filter初始化参数
- 获取ServletContext对象。
问题:怎样在Filter中获取一个FIlterConfig对象?
1 package com.itheima.filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest; 10 import javax.servlet.ServletResponse; 11 12 public class MyFilterConfigTest implements Filter{ 13 14 private FilterConfig filterConfig; 15 16 public void init(FilterConfig filterConfig) throws ServletException { 17 this.filterConfig = filterConfig; 18 } 19 20 public void doFilter(ServletRequest request, ServletResponse response, 21 FilterChain chain) throws IOException, ServletException { 22 //通过FilterConfig对象获取到配置文件中的初始化信息 23 String encoding = filterConfig.getInitParameter("encoding"); 24 System.out.println(encoding); 25 request.setCharacterEncoding(encoding); 26 //放行 27 chain.doFilter(request, response); 28 } 29 30 public void destroy() { 31 // TODO Auto-generated method stub 32 } 33 }
如下 web.xml配置
<filter>
<filter-name>MyFilterConfigTest</filter-name>
<filter-class>com.itheima.filter.MyFilterConfigTest</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFilterConfigTest</filter-name>
<servlet-name>ServletDemo2</servlet-name>
</filter-mapping>
1.5、Filter配置
基本配置
<filter> <filter-name>filter名称</filter-name> <filter-class>Filter类的包名.类名</filter-class> </filter> <filter-mapping> <filter-name>filter名称</filter-name> <url-pattern>路径</url-pattern> </filter-mapping>
关于其它配置
1.<url-pattern>
完全匹配 以”/demo1”开始,不包含通配符*
目录匹配 以”/”开始 以*结束
扩展名匹配 *.xxx 不能写成/*.xxx
2.<servlet-name>
它是对指定的servlet名称的servlet进行拦截的。
3.<dispatcher>
可以取的值有 REQUEST FORWARD ERROR INCLUDE 根据跳转方式拦截
它的作用是:当以什么方式去访问web资源时,进行拦截操作.
1.REQUEST 当是从浏览器直接访问资源,或是重定向到某个资源时进行拦截方式配置的 它也是默认值
2.FORWARD 它描述的是请求转发的拦截方式配置
3.ERROR 如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
4.INCLUDE 如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用
三、自动登录 (PS bean的属性名和数据库里的字段名千万要一样哦 不然会emmm 很惨)
- 当用户登陆成功后,判断是否勾选了自动登陆,如果勾选了,就将用户名与密码持久化存储到cookie
- 做一个Filter,对需要自动登陆的资源进行拦截
首写要在登录Servlet中登录成功时把登录的信息保存在cookie里,并设置存活时间
if(null != user){ String autologin = request.getParameter("autologin"); Cookie cookie = new Cookie("user", user.getUsername()+"&"+user.getPassword()); cookie.setPath("/"); if(autologin != null){// on / null cookie.setMaxAge(60*60*24*7); }else{ cookie.setMaxAge(0); } response.addCookie(cookie); request.getSession().setAttribute("user", user); request.getRequestDispatcher("/home.jsp").forward(request, response); }
然后设置好filter类 记住要在web.xml里面配置 如下 为 doFilter代码
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { //1、转换对象 HttpServletRequest req = (HttpServletRequest) arg0; //2、处理业务 Cookie[] cookies = req.getCookies(); String username = ""; String password = ""; for (int i = 0;cookies!=null && i < cookies.length; i++) { if("user".equals(cookies[i].getName())){ String value = cookies[i].getValue(); String[] values = value.split("&"); username = values[0]; password = values[1]; } } UserService us = new UserService(); User user = us.findUser(username, password); if(user != null){ req.getSession().setAttribute("user", user); } //3、放行 arg2.doFilter(arg0, arg1); }